初始化
@@ -0,0 +1,190 @@
|
|||||||
|
# Miscellaneous
|
||||||
|
*.class
|
||||||
|
*.log
|
||||||
|
*.pyc
|
||||||
|
*.swp
|
||||||
|
.DS_Store
|
||||||
|
.atom/
|
||||||
|
.buildlog/
|
||||||
|
.history
|
||||||
|
.svn/
|
||||||
|
.properties
|
||||||
|
.flutter-plugins
|
||||||
|
.packages
|
||||||
|
.lock
|
||||||
|
.bin
|
||||||
|
pubspec.look
|
||||||
|
local.properties
|
||||||
|
.packages
|
||||||
|
.flutter-plugins
|
||||||
|
searchFile.js
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.packages
|
||||||
|
.metadata
|
||||||
|
.fvm/
|
||||||
|
# VSCode 工作区配置纳入版本管理(settings.json 里的排除规则要团队共用),
|
||||||
|
# 其余个人化/临时文件仍然忽略。
|
||||||
|
# 注意:全局 ~/.gitignore_global 也忽略了这两个文件,靠项目级白名单覆盖
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
zaixiankefu/pubspec.lock
|
||||||
|
# IntelliJ related
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
|
||||||
|
# The .vscode folder contains launch configuration and tasks you configure in
|
||||||
|
# VS Code which you may wish to be included in version control, so this line
|
||||||
|
# is commented out by default.
|
||||||
|
#.vscode/
|
||||||
|
|
||||||
|
|
||||||
|
# Flutter/Dart/Pub related
|
||||||
|
**/doc/api/
|
||||||
|
.dart_tool/*
|
||||||
|
.flutter-plugins
|
||||||
|
.packages
|
||||||
|
.pub-cache/
|
||||||
|
.pub/
|
||||||
|
/build/
|
||||||
|
|
||||||
|
|
||||||
|
# Android related
|
||||||
|
# Android related
|
||||||
|
**/android/**/gradle-wrapper.jar
|
||||||
|
**/android/.gradle
|
||||||
|
**/android/captures/
|
||||||
|
**/android/gradlew
|
||||||
|
**/android/gradlew.bat
|
||||||
|
**/android/local.properties
|
||||||
|
**/android/**/GeneratedPluginRegistrant.java
|
||||||
|
**/android/key.properties
|
||||||
|
*.jks
|
||||||
|
|
||||||
|
|
||||||
|
# 针对flutter当做module集成进现有项目时,.android目录下的文件
|
||||||
|
**/.android/**/gradle-wrapper.jar
|
||||||
|
**/.android/.gradle
|
||||||
|
**/.android/captures/
|
||||||
|
**/.android/gradlew
|
||||||
|
**/.android/gradlew.bat
|
||||||
|
**/.android/local.properties
|
||||||
|
**/.android/**/GeneratedPluginRegistrant.java
|
||||||
|
**/.android/key.properties
|
||||||
|
**/*.jks
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# iOS/XCode related
|
||||||
|
**/ios/**/*.mode1v3
|
||||||
|
**/ios/**/*.mode2v3
|
||||||
|
**/ios/**/*.moved-aside
|
||||||
|
**/ios/**/*.pbxuser
|
||||||
|
**/ios/**/*.perspectivev3
|
||||||
|
**/ios/**/*sync/
|
||||||
|
**/ios/**/.sconsign.dblite
|
||||||
|
**/ios/**/.tags*
|
||||||
|
**/ios/**/.vagrant/
|
||||||
|
**/ios/**/DerivedData/
|
||||||
|
**/ios/**/Icon?
|
||||||
|
**/ios/**/Pods/
|
||||||
|
**/ios/**/.symlinks/
|
||||||
|
**/ios/**/profile
|
||||||
|
**/ios/**/xcuserdata
|
||||||
|
**/ios/.generated/
|
||||||
|
**/ios/Flutter/App.framework
|
||||||
|
**/ios/Flutter/Flutter.framework
|
||||||
|
**/ios/Flutter/Generated.xcconfig
|
||||||
|
**/ios/Flutter/app.flx
|
||||||
|
**/ios/Flutter/app.zip
|
||||||
|
**/ios/Flutter/flutter_assets/
|
||||||
|
**/ios/ServiceDefinitions.json
|
||||||
|
**/ios/Runner/GeneratedPluginRegistrant.*
|
||||||
|
|
||||||
|
|
||||||
|
# 针对flutter当做module集成进现有项目时,.ios目录下的文件
|
||||||
|
**/.ios/**/*.mode1v3
|
||||||
|
**/.ios/**/*.mode2v3
|
||||||
|
**/.ios/**/*.moved-aside
|
||||||
|
**/.ios/**/*.pbxuser
|
||||||
|
**/.ios/**/*.perspectivev3
|
||||||
|
**/.ios/**/*sync/
|
||||||
|
**/.ios/**/.sconsign.dblite
|
||||||
|
**/.ios/**/.tags*
|
||||||
|
**/.ios/**/.vagrant/
|
||||||
|
**/.ios/**/DerivedData/
|
||||||
|
**/.ios/**/Icon?
|
||||||
|
**/.ios/**/Pods/
|
||||||
|
**/.ios/**/.symlinks/
|
||||||
|
**/.ios/**/profile
|
||||||
|
**/.ios/**/xcuserdata
|
||||||
|
**/.ios/.generated/
|
||||||
|
**/.ios/Flutter/App.framework
|
||||||
|
**/.ios/Flutter/Flutter.framework
|
||||||
|
**/.ios/Flutter/Generated.xcconfig
|
||||||
|
**/.ios/Flutter/app.flx
|
||||||
|
**/.ios/Flutter/app.zip
|
||||||
|
**/.ios/Flutter/flutter_assets/
|
||||||
|
**/.ios/ServiceDefinitions.json
|
||||||
|
**/.ios/Runner/GeneratedPluginRegistrant.*
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# macOS
|
||||||
|
**/macos/Flutter/GeneratedPluginRegistrant.swift
|
||||||
|
**/macos/Flutter/Flutter-Debug.xcconfig
|
||||||
|
**/macos/Flutter/Flutter-Release.xcconfig
|
||||||
|
**/macos/Flutter/Flutter-Profile.xcconfig
|
||||||
|
|
||||||
|
|
||||||
|
# Coverage
|
||||||
|
coverage/
|
||||||
|
|
||||||
|
|
||||||
|
# Symbols
|
||||||
|
app.*.symbols
|
||||||
|
|
||||||
|
|
||||||
|
# Exceptions to above rules.
|
||||||
|
!**/ios/**/default.mode1v3
|
||||||
|
!**/ios/**/default.mode2v3
|
||||||
|
!**/ios/**/default.pbxuser
|
||||||
|
!**/ios/**/default.perspectivev3
|
||||||
|
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
|
||||||
|
!/dev/ci/**/Gemfile.lock
|
||||||
|
.packages~92442170bbeb67da2b4cc92142720c48c0d7f490
|
||||||
|
|
||||||
|
/pubspec.lock
|
||||||
|
/.flutter-plugins-dependencies
|
||||||
|
linux/*
|
||||||
|
!ios/Podfile
|
||||||
|
!ios/ExportOptions.plist.example
|
||||||
|
|
||||||
|
m3u8_downloader-master/.dart_tool/
|
||||||
|
m3u8_downloader-master/example/.dart_tool/
|
||||||
|
m3u8_downloader-master/example/.flutter-plugins-dependencies
|
||||||
|
m3u8_downloader-master/*/*.lock
|
||||||
|
m3u8_downloader-master/pubspec.lock
|
||||||
|
dist/
|
||||||
|
|
||||||
|
ume_kit/*/.dart_tool/
|
||||||
|
ume_kit/*/.flutter-plugins-dependencies
|
||||||
|
ume_kit/*/pubspec.lock
|
||||||
|
|
||||||
|
third_party/*/.dart_tool/
|
||||||
|
third_party/*/.flutter-plugins-dependencies
|
||||||
|
third_party/*/pubspec.lock
|
||||||
|
|
||||||
|
|
||||||
|
*.apk
|
||||||
|
ume_kit/
|
||||||
|
|
||||||
|
# Claude Code 本地配置
|
||||||
|
.claude/
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
{
|
||||||
|
// 使用 IntelliSense 了解相关属性。
|
||||||
|
// 悬停以查看现有属性的描述。
|
||||||
|
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "hgdj",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hgdj (profile mode)",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart",
|
||||||
|
"flutterMode": "profile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hgdj (release mode)",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart",
|
||||||
|
"flutterMode": "release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "m3u8_downloader-master",
|
||||||
|
"cwd": "m3u8_downloader-master",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "m3u8_downloader-master (profile mode)",
|
||||||
|
"cwd": "m3u8_downloader-master",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart",
|
||||||
|
"flutterMode": "profile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "m3u8_downloader-master (release mode)",
|
||||||
|
"cwd": "m3u8_downloader-master",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart",
|
||||||
|
"flutterMode": "release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "example",
|
||||||
|
"cwd": "m3u8_downloader-master/example",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "example (profile mode)",
|
||||||
|
"cwd": "m3u8_downloader-master/example",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart",
|
||||||
|
"flutterMode": "profile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "example (release mode)",
|
||||||
|
"cwd": "m3u8_downloader-master/example",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart",
|
||||||
|
"flutterMode": "release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "flutter_native_image",
|
||||||
|
"cwd": "third_party/flutter_native_image",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "flutter_native_image (profile mode)",
|
||||||
|
"cwd": "third_party/flutter_native_image",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart",
|
||||||
|
"flutterMode": "profile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "flutter_native_image (release mode)",
|
||||||
|
"cwd": "third_party/flutter_native_image",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart",
|
||||||
|
"flutterMode": "release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "image_gallery_saver",
|
||||||
|
"cwd": "third_party/image_gallery_saver",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "image_gallery_saver (profile mode)",
|
||||||
|
"cwd": "third_party/image_gallery_saver",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart",
|
||||||
|
"flutterMode": "profile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "image_gallery_saver (release mode)",
|
||||||
|
"cwd": "third_party/image_gallery_saver",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart",
|
||||||
|
"flutterMode": "release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "image_pickers",
|
||||||
|
"cwd": "third_party/image_pickers",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "image_pickers (profile mode)",
|
||||||
|
"cwd": "third_party/image_pickers",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart",
|
||||||
|
"flutterMode": "profile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "image_pickers (release mode)",
|
||||||
|
"cwd": "third_party/image_pickers",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart",
|
||||||
|
"flutterMode": "release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mac_address",
|
||||||
|
"cwd": "third_party/mac_address",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mac_address (profile mode)",
|
||||||
|
"cwd": "third_party/mac_address",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart",
|
||||||
|
"flutterMode": "profile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mac_address (release mode)",
|
||||||
|
"cwd": "third_party/mac_address",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart",
|
||||||
|
"flutterMode": "release"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
{
|
||||||
|
"dart.flutterSdkPath": ".fvm/versions/3.38.3",
|
||||||
|
"dart.flutterSdkPaths": [
|
||||||
|
"/Users/mac/Documents/flutter"
|
||||||
|
],
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.organizeImports": "explicit"
|
||||||
|
},
|
||||||
|
"editor.wordWrapColumn": 120,
|
||||||
|
|
||||||
|
//=========== 文件监听排除 ===========
|
||||||
|
// VSCode 的 watcher 不看 .gitignore,只认这里;
|
||||||
|
// Flutter 的 build/ 和 .dart_tool/ 不排掉会被整个监听
|
||||||
|
"files.watcherExclude": {
|
||||||
|
"**/.git/objects/**": true,
|
||||||
|
"**/.git/subtree-cache/**": true,
|
||||||
|
"**/build/**": true,
|
||||||
|
"**/.dart_tool/**": true,
|
||||||
|
"**/.fvm/**": true,
|
||||||
|
"**/dist/**": true,
|
||||||
|
"**/android/.gradle/**": true,
|
||||||
|
"**/android/**/build/**": true,
|
||||||
|
"**/ios/Pods/**": true,
|
||||||
|
"**/ios/.symlinks/**": true,
|
||||||
|
"**/ios/Flutter/ephemeral/**": true,
|
||||||
|
"**/*.apk": true,
|
||||||
|
"**/*.ipa": true
|
||||||
|
},
|
||||||
|
|
||||||
|
//=========== 全局搜索排除 ===========
|
||||||
|
"search.exclude": {
|
||||||
|
"**/build": true,
|
||||||
|
"**/.dart_tool": true,
|
||||||
|
"**/.fvm": true,
|
||||||
|
"**/dist": true,
|
||||||
|
"**/android/.gradle": true,
|
||||||
|
"**/ios/Pods": true,
|
||||||
|
"**/ios/.symlinks": true
|
||||||
|
},
|
||||||
|
|
||||||
|
// 不跟随软链,避免顺着 .fvm 爬进整个 Flutter SDK
|
||||||
|
"search.followSymlinks": false,
|
||||||
|
|
||||||
|
//=========== 资源管理器隐藏纯中间产物 ===========
|
||||||
|
// dist / ios/Pods 保留可见,取包和看 Pod 配置还要用
|
||||||
|
"files.exclude": {
|
||||||
|
"**/build": true,
|
||||||
|
"**/.dart_tool": true,
|
||||||
|
"**/android/.gradle": true,
|
||||||
|
"**/ios/.symlinks": true,
|
||||||
|
"**/ios/Flutter/ephemeral": true
|
||||||
|
},
|
||||||
|
|
||||||
|
//=========== Dart 分析器排除 ===========
|
||||||
|
// 只排构建产物,path 依赖(third_party 等)保持分析,避免丢跳转和补全
|
||||||
|
"dart.analysisExcludedFolders": [
|
||||||
|
"build",
|
||||||
|
".dart_tool",
|
||||||
|
".fvm",
|
||||||
|
"dist",
|
||||||
|
"android",
|
||||||
|
"ios/Pods"
|
||||||
|
],
|
||||||
|
|
||||||
|
//=========== GitLens 降载 ===========
|
||||||
|
// 这两项每次渲染和移动光标都触发 blame,直接拖慢滚动
|
||||||
|
"gitlens.codeLens.enabled": false,
|
||||||
|
"gitlens.currentLine.enabled": false,
|
||||||
|
|
||||||
|
//=========== Gradle / Java 扩展降载 ===========
|
||||||
|
// Flutter 打包直接走 gradle wrapper,不需要 Java 扩展导入这套构建
|
||||||
|
"gradle.autoDetect": "off",
|
||||||
|
"gradle.nestedProjects": false,
|
||||||
|
"java.import.gradle.enabled": false,
|
||||||
|
"java.configuration.updateBuildConfiguration": "disabled"
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# 黄果短剧
|
||||||
|
|
||||||
|
A new Flutter project. 3.16.8
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
This project is a starting point for a Flutter application.
|
||||||
|
|
||||||
|
A few resources to get you started if this is your first Flutter project:
|
||||||
|
|
||||||
|
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
|
||||||
|
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
|
||||||
|
|
||||||
|
For help getting started with Flutter development, view the
|
||||||
|
[online documentation](https://docs.flutter.dev/), which offers tutorials,
|
||||||
|
samples, guidance on mobile development, and a full API reference.
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# This file configures the analyzer, which statically analyzes Dart code to
|
||||||
|
# check for errors, warnings, and lints.
|
||||||
|
#
|
||||||
|
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
|
||||||
|
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
|
||||||
|
# invoked from the command line by running `flutter analyze`.
|
||||||
|
|
||||||
|
# The following line activates a set of recommended lints for Flutter apps,
|
||||||
|
# packages, and plugins designed to encourage good coding practices.
|
||||||
|
include: package:flutter_lints/flutter.yaml
|
||||||
|
|
||||||
|
linter:
|
||||||
|
# The lint rules applied to this project can be customized in the
|
||||||
|
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
||||||
|
# included above or to enable additional rules. A list of all available lints
|
||||||
|
# and their documentation is published at https://dart.dev/lints.
|
||||||
|
#
|
||||||
|
# Instead of disabling a lint rule for the entire project in the
|
||||||
|
# section below, it can also be suppressed for a single line of code
|
||||||
|
# or a specific dart file by using the `// ignore: name_of_lint` and
|
||||||
|
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
|
||||||
|
# producing the lint.
|
||||||
|
rules:
|
||||||
|
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
||||||
|
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
||||||
|
|
||||||
|
# 禁止提示要把构造函数设为 const
|
||||||
|
prefer_const_constructors: false
|
||||||
|
# 禁止提示要把集合/列表设为 const
|
||||||
|
prefer_const_literals_to_create_immutables: false
|
||||||
|
# 禁止提示在构造函数中使用 const
|
||||||
|
prefer_const_constructors_in_immutables: false
|
||||||
|
|
||||||
|
# Additional information about this file can be found at
|
||||||
|
# https://dart.dev/guides/language/analysis-options
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
gradle-wrapper.jar
|
||||||
|
/.gradle
|
||||||
|
/captures/
|
||||||
|
/gradlew
|
||||||
|
/gradlew.bat
|
||||||
|
/local.properties
|
||||||
|
GeneratedPluginRegistrant.java
|
||||||
|
.cxx/
|
||||||
|
|
||||||
|
# Remember to never publicly share your keystore.
|
||||||
|
# See https://flutter.dev/to/reference-keystore
|
||||||
|
key.properties
|
||||||
|
**/*.keystore
|
||||||
|
**/*.jks
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
arguments=
|
||||||
|
auto.sync=false
|
||||||
|
build.scans.enabled=false
|
||||||
|
connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
|
||||||
|
connection.project.dir=
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
gradle.user.home=
|
||||||
|
java.home=
|
||||||
|
jvm.arguments=
|
||||||
|
offline.mode=false
|
||||||
|
override.workspace.settings=false
|
||||||
|
show.console.view=false
|
||||||
|
show.executions.view=false
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
plugins {
|
||||||
|
id 'com.android.application'
|
||||||
|
id 'kotlin-android'
|
||||||
|
id 'dev.flutter.flutter-gradle-plugin'
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: 'top.niunaijun.blackobfuscator'
|
||||||
|
apply plugin: 'walle'
|
||||||
|
|
||||||
|
def bundledReleaseKeystore = file('../keystore/nut.jks')
|
||||||
|
def legacyBundledReleaseKeystore = file('../keystore/nut.jks.old')
|
||||||
|
def resolvedReleaseKeystore = bundledReleaseKeystore.exists() ? bundledReleaseKeystore : legacyBundledReleaseKeystore
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace "com.xvproject"
|
||||||
|
compileSdk 36
|
||||||
|
ndkVersion "28.2.13676358"
|
||||||
|
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_17
|
||||||
|
targetCompatibility JavaVersion.VERSION_17
|
||||||
|
coreLibraryDesugaringEnabled true
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = JavaVersion.VERSION_17.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main.java.srcDirs += 'src/main/kotlin'
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
applicationId "com.noporn.newchatone_twelve_five"
|
||||||
|
minSdk = 24
|
||||||
|
targetSdk = 36
|
||||||
|
versionCode = 1
|
||||||
|
versionName = "1.12.6"
|
||||||
|
}
|
||||||
|
|
||||||
|
signingConfigs {
|
||||||
|
release {
|
||||||
|
storeFile resolvedReleaseKeystore
|
||||||
|
storePassword 'jiahua123456'
|
||||||
|
storeType 'jks'
|
||||||
|
keyAlias 'nut'
|
||||||
|
keyPassword 'jiahua123456'
|
||||||
|
v1SigningEnabled false
|
||||||
|
v2SigningEnabled true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
minifyEnabled true
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
|
shrinkResources true
|
||||||
|
signingConfig signingConfigs.release
|
||||||
|
}
|
||||||
|
debug {
|
||||||
|
minifyEnabled false
|
||||||
|
shrinkResources false
|
||||||
|
versionNameSuffix "test"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
packagingOptions {
|
||||||
|
jniLibs {
|
||||||
|
excludes += ['**/armeabi-v7a/**', '**/x86/**', '**/x86_64/**']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
applicationVariants.configureEach { variant ->
|
||||||
|
println "variant.name= ${variant.name}"
|
||||||
|
variant.outputs.configureEach {
|
||||||
|
//只处理生产版本
|
||||||
|
if (buildType.name == 'release') {
|
||||||
|
println "buildType= ${variant.buildType.getName()}"
|
||||||
|
def outputFileDir = "${project.projectDir.absolutePath}/release/"
|
||||||
|
def createTime = new Date().format("MM-dd-HH-mm", TimeZone.getTimeZone("GMT+08:00"))
|
||||||
|
println "outputFileDir= ${outputFileDir}"
|
||||||
|
def abi = filters.find { it.filterType.toString() == "ABI" }?.identifier
|
||||||
|
def abiSuffix = (variant.outputs.size() > 1 && abi) ? "_${abi}" : ""
|
||||||
|
def path = "hgdj" + '_release' + "_" + variant.versionName + abiSuffix + "_" + createTime + ".apk"
|
||||||
|
println("path= " + path)
|
||||||
|
outputFileName = path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
flutter {
|
||||||
|
source '../..'
|
||||||
|
}
|
||||||
|
|
||||||
|
configurations.configureEach {
|
||||||
|
resolutionStrategy {
|
||||||
|
force 'androidx.core:core-ktx:1.6.0'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
configurations.all {
|
||||||
|
resolutionStrategy {
|
||||||
|
force 'com.tencent:mmkv:1.2.14'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加入混淆配置
|
||||||
|
BlackObfuscator {
|
||||||
|
// 是否启用
|
||||||
|
enabled true
|
||||||
|
// 混淆深度
|
||||||
|
depth 3
|
||||||
|
// 需要混淆的包或者类(匹配前面一段)
|
||||||
|
obfClass = ["lib"]
|
||||||
|
// blackClass中的包或者类不会进行混淆(匹配前面一段)
|
||||||
|
// blackClass = ["top.niunaijun.black"]
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'
|
||||||
|
// android 读取渠道号码
|
||||||
|
implementation 'com.mcxiaoke.packer-ng:helper:2.0.1'
|
||||||
|
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||||
|
implementation 'androidx.core:core-ktx:1.12.0'
|
||||||
|
implementation 'androidx.lifecycle:lifecycle-common:2.6.2'
|
||||||
|
def camerax_version = "1.0.0-beta11"
|
||||||
|
implementation "androidx.camera:camera-core:${camerax_version}"
|
||||||
|
implementation "androidx.camera:camera-camera2:${camerax_version}"
|
||||||
|
implementation "androidx.camera:camera-lifecycle:${camerax_version}"
|
||||||
|
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
|
||||||
|
// 协程核心库
|
||||||
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4"
|
||||||
|
// 协程Android支持库
|
||||||
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
|
||||||
|
// 协程Java8支持库
|
||||||
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.6.4"
|
||||||
|
implementation 'com.qiniu:happy-dns:2.0.1'
|
||||||
|
implementation 'com.github.Petterpx.walle:library:1.0.5'
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
运行 ./resp_genkey.sh xxxxx
|
||||||
|
xxxxx 为alias/密码和密钥的名称;
|
||||||
|
如果提示输入密钥,直接输入xxxxx即可
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
if [ $# -ne 1 ]; then
|
||||||
|
printf -- "Please input alias.\n\n"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
echo "输入参数密钥$1\n"
|
||||||
|
keystoreName="$1.jks"
|
||||||
|
# echo "test code 2"
|
||||||
|
|
||||||
|
printf "\n开始生成key:[$keystoreName]...\n\n"
|
||||||
|
`keytool -genkey -alias $1 -keyalg RSA -validity 10000 -keystore $keystoreName`
|
||||||
|
printf "\n[$keystoreName]正在进行pkcs12重新加密...\n\n"
|
||||||
|
`keytool -importkeystore -srckeystore $keystoreName -destkeystore $keystoreName -deststoretype pkcs12`
|
||||||
|
printf "\n删除老的key:[$keystoreName.old]...okay\n\n"
|
||||||
|
`rm -rf $keystoreName.old`
|
||||||
|
|
||||||
|
cat /dev/null > ../../key.properties
|
||||||
|
echo "storePassword=$1" >> ../../key.properties
|
||||||
|
echo "keyPassword=$1" >> ../../key.properties
|
||||||
|
echo "keyAlias=$1" >> ../../key.properties
|
||||||
|
echo "storeFile=./key/$keystoreName" >> ../../key.properties
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
#!/usr/bin/expect
|
||||||
|
#功能:自动填充生成androidkey功能
|
||||||
|
#注意:expect 是用c语言写的 所以用argc和argv接收参数
|
||||||
|
#注意:expect 只接受shell而不是bash 请./运行
|
||||||
|
|
||||||
|
# expect 常用命令
|
||||||
|
# spawn 交互程序开始后面跟命令或者指定程序
|
||||||
|
# expect 获取匹配信息匹配成功则执行expect后面的程序动作
|
||||||
|
# send exp_send 用于发送指定的字符串信息
|
||||||
|
# exp_continue 在expect中多次匹配就需要用到
|
||||||
|
# send_user 用来打印输出 相当于shell中的echo
|
||||||
|
# exit 退出expect脚本
|
||||||
|
# eof expect执行结束 退出
|
||||||
|
# set 定义变量
|
||||||
|
# puts 输出变量
|
||||||
|
# set timeout 设置超时时间
|
||||||
|
|
||||||
|
if {$argc < 1} {
|
||||||
|
puts "Please input alias.\n\n"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
set password [lindex $argv 0]
|
||||||
|
# send_user $password
|
||||||
|
puts stderr $password
|
||||||
|
# spawn [exec bash ./genkey.sh $password]
|
||||||
|
spawn bash ./genkey.sh $password
|
||||||
|
|
||||||
|
# expect "输入密钥库口令:"
|
||||||
|
# send "$password\r"
|
||||||
|
# expect "再次输入新口令:"
|
||||||
|
# send "$password\r"
|
||||||
|
# expect "是什么?"
|
||||||
|
# send "$password\r"
|
||||||
|
# expect "是什么?"
|
||||||
|
# send "$password\r"
|
||||||
|
# expect "是什么?"
|
||||||
|
# send "$password\r"
|
||||||
|
# expect "是什么?"
|
||||||
|
# send "$password\r"
|
||||||
|
# expect "是什么?"
|
||||||
|
# send "$password\r"
|
||||||
|
# expect "是什么?"
|
||||||
|
# send "$password\r"
|
||||||
|
# expect "是否正确?"
|
||||||
|
# send "y\r"
|
||||||
|
# expect "按回车):"
|
||||||
|
# send "\r"
|
||||||
|
# expect "输入源密钥库口令:"
|
||||||
|
# send "$password\r"
|
||||||
|
# # expect "输入目标密钥库口令:"
|
||||||
|
# # send "$password\r"
|
||||||
|
# # expect "再次输入新口令:"
|
||||||
|
# # send "$password\r"
|
||||||
|
|
||||||
|
expect {
|
||||||
|
"输入密钥库口令:"
|
||||||
|
{ send "$password\r"; exp_continue }
|
||||||
|
"再次输入新口令:"
|
||||||
|
{send "$password\r"; exp_continue}
|
||||||
|
"是什么?"
|
||||||
|
{send "$password\r"; exp_continue}
|
||||||
|
"是否正确?"
|
||||||
|
{send "y\r"; exp_continue}
|
||||||
|
"按回车):"
|
||||||
|
{send "\r"; exp_continue}
|
||||||
|
"输入源密钥库口令:"
|
||||||
|
{send "$password\r";exp_continue}
|
||||||
|
"输入目标密钥库口令:"
|
||||||
|
{send "$password\r";exp_continue}
|
||||||
|
"再次输入新口令:"
|
||||||
|
{send "$password\r";exp_continue}
|
||||||
|
}
|
||||||
|
# interact
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
-dontwarn javax.imageio.spi.ImageInputStreamSpi
|
||||||
|
-dontwarn javax.imageio.spi.ImageOutputStreamSpi
|
||||||
|
-dontwarn javax.imageio.spi.ImageReaderSpi
|
||||||
|
-dontwarn javax.imageio.spi.ImageWriterSpi
|
||||||
|
-dontwarn org.bouncycastle.jsse.BCSSLParameters
|
||||||
|
-dontwarn org.bouncycastle.jsse.BCSSLSocket
|
||||||
|
-dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider
|
||||||
|
-dontwarn org.conscrypt.Conscrypt$Version
|
||||||
|
-dontwarn org.conscrypt.Conscrypt
|
||||||
|
-dontwarn org.conscrypt.ConscryptHostnameVerifier
|
||||||
|
-dontwarn org.openjsse.javax.net.ssl.SSLParameters
|
||||||
|
-dontwarn org.openjsse.javax.net.ssl.SSLSocket
|
||||||
|
-dontwarn org.openjsse.net.ssl.OpenJSSE
|
||||||
|
|
||||||
|
# ffmpeg_kit_flutter_new_https_gpl:原生库 JNI_OnLoad 通过 RegisterNatives 绑定 AbiDetect.getNativeCpuAbi 等方法,
|
||||||
|
# release 下 R8 混淆改名会导致绑定失败 → JNI_OnLoad 返回 0 → 启动 SIGSEGV 闪退,必须 keep。
|
||||||
|
-keep class com.antonkarpenko.ffmpegkit.** { *; }
|
||||||
|
# 通用兜底:任何含 native 方法的类,保留其 native 方法名(防止其它 JNI 库重蹈覆辙)
|
||||||
|
-keepclasseswithmembernames,includedescriptorclasses class * {
|
||||||
|
native <methods>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<!-- The INTERNET permission is required for development. Specifically,
|
||||||
|
the Flutter tool needs it to communicate with the running application
|
||||||
|
to allow setting breakpoints, to provide hot reload, etc.
|
||||||
|
-->
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
</manifest>
|
||||||
@@ -0,0 +1,318 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
package="com.xvproject">
|
||||||
|
|
||||||
|
<!-- release 包只用 main manifest,INTERNET 必须在这里声明;
|
||||||
|
否则 release 无网络权限,启动选线 host lookup errno=7,弹"线路检测失败" -->
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:label="黄果短剧"
|
||||||
|
android:name=".JPApplication"
|
||||||
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:usesCleartextTraffic="true"
|
||||||
|
android:largeHeap="true"
|
||||||
|
android:hardwareAccelerated="true"
|
||||||
|
android:extractNativeLibs="true"
|
||||||
|
android:requestLegacyExternalStorage="true">
|
||||||
|
<activity
|
||||||
|
android:name=".MainActivity"
|
||||||
|
android:exported="true"
|
||||||
|
android:launchMode="singleTop"
|
||||||
|
android:theme="@style/LaunchTheme"
|
||||||
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||||
|
android:hardwareAccelerated="true"
|
||||||
|
android:windowSoftInputMode="adjustResize">
|
||||||
|
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||||
|
the Android process has started. This theme is visible to the user
|
||||||
|
while the Flutter UI initializes. After that, this theme continues
|
||||||
|
to determine the Window background behind the Flutter UI. -->
|
||||||
|
<meta-data
|
||||||
|
android:name="io.flutter.embedding.android.NormalTheme"
|
||||||
|
android:resource="@style/NormalTheme"
|
||||||
|
/>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
<activity-alias
|
||||||
|
android:name=".lld"
|
||||||
|
android:targetActivity=".MainActivity"
|
||||||
|
android:label="黄果短剧"
|
||||||
|
android:enabled="false"
|
||||||
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity-alias>
|
||||||
|
|
||||||
|
<activity-alias
|
||||||
|
android:name=".aiyinyue"
|
||||||
|
android:targetActivity=".MainActivity"
|
||||||
|
android:label="爱音乐"
|
||||||
|
android:enabled="false"
|
||||||
|
android:icon="@mipmap/icon_1"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity-alias>
|
||||||
|
|
||||||
|
|
||||||
|
<activity-alias
|
||||||
|
android:name=".aiyuedu"
|
||||||
|
android:targetActivity=".MainActivity"
|
||||||
|
android:label="爱阅读"
|
||||||
|
android:enabled="false"
|
||||||
|
android:icon="@mipmap/icon_2"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity-alias>
|
||||||
|
|
||||||
|
<activity-alias
|
||||||
|
android:name=".alipay"
|
||||||
|
android:targetActivity=".MainActivity"
|
||||||
|
android:label="支付宝"
|
||||||
|
android:enabled="false"
|
||||||
|
android:icon="@mipmap/icon_3"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity-alias>
|
||||||
|
|
||||||
|
<activity-alias
|
||||||
|
android:name=".bilibili"
|
||||||
|
android:targetActivity=".MainActivity"
|
||||||
|
android:label="哔哩哔哩"
|
||||||
|
android:enabled="false"
|
||||||
|
android:icon="@mipmap/icon_4"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity-alias>
|
||||||
|
|
||||||
|
<activity-alias
|
||||||
|
android:name=".binggandazhuozhan"
|
||||||
|
android:targetActivity=".MainActivity"
|
||||||
|
android:label="金铲铲之战"
|
||||||
|
android:enabled="false"
|
||||||
|
android:icon="@mipmap/icon_5"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity-alias>
|
||||||
|
|
||||||
|
<activity-alias
|
||||||
|
android:name=".meisijiejian"
|
||||||
|
android:targetActivity=".MainActivity"
|
||||||
|
android:label="美食借鉴"
|
||||||
|
android:enabled="false"
|
||||||
|
android:icon="@mipmap/icon_6"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity-alias>
|
||||||
|
|
||||||
|
<activity-alias
|
||||||
|
android:name=".myworld"
|
||||||
|
android:targetActivity=".MainActivity"
|
||||||
|
android:label="我的世界"
|
||||||
|
android:enabled="false"
|
||||||
|
android:icon="@mipmap/icon_7"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity-alias>
|
||||||
|
|
||||||
|
|
||||||
|
<activity-alias
|
||||||
|
android:name=".shenxuanzhizhan"
|
||||||
|
android:targetActivity=".MainActivity"
|
||||||
|
android:label="神选之战"
|
||||||
|
android:enabled="false"
|
||||||
|
android:icon="@mipmap/icon_8"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity-alias>
|
||||||
|
|
||||||
|
|
||||||
|
<activity-alias
|
||||||
|
android:name=".shuixinwuxian"
|
||||||
|
android:targetActivity=".MainActivity"
|
||||||
|
android:label="随心无线"
|
||||||
|
android:enabled="false"
|
||||||
|
android:icon="@mipmap/icon_9"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity-alias>
|
||||||
|
|
||||||
|
|
||||||
|
<activity-alias
|
||||||
|
android:name=".texuanxiaoshuo"
|
||||||
|
android:targetActivity=".MainActivity"
|
||||||
|
android:label="特轩小说"
|
||||||
|
android:enabled="false"
|
||||||
|
android:icon="@mipmap/icon_10"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity-alias>
|
||||||
|
|
||||||
|
<activity-alias
|
||||||
|
android:name=".tiantianmajiang"
|
||||||
|
android:targetActivity=".MainActivity"
|
||||||
|
android:label="天天麻将"
|
||||||
|
android:enabled="false"
|
||||||
|
android:icon="@mipmap/icon_11"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity-alias>
|
||||||
|
|
||||||
|
<activity-alias
|
||||||
|
android:name=".tuyou"
|
||||||
|
android:targetActivity=".MainActivity"
|
||||||
|
android:label="途游"
|
||||||
|
android:enabled="false"
|
||||||
|
android:icon="@mipmap/icon_12"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity-alias>
|
||||||
|
|
||||||
|
<activity-alias
|
||||||
|
android:name=".weichat"
|
||||||
|
android:targetActivity=".MainActivity"
|
||||||
|
android:label="微信"
|
||||||
|
android:enabled="false"
|
||||||
|
android:icon="@mipmap/icon_13"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity-alias>
|
||||||
|
|
||||||
|
<activity-alias
|
||||||
|
android:name=".wendao"
|
||||||
|
android:targetActivity=".MainActivity"
|
||||||
|
android:label="问道"
|
||||||
|
android:enabled="false"
|
||||||
|
android:icon="@mipmap/icon_14"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity-alias>
|
||||||
|
|
||||||
|
<activity-alias
|
||||||
|
android:name=".yinyutusujiao"
|
||||||
|
android:targetActivity=".MainActivity"
|
||||||
|
android:label="英语图书角"
|
||||||
|
android:enabled="false"
|
||||||
|
android:icon="@mipmap/icon_15"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity-alias>
|
||||||
|
|
||||||
|
<activity-alias
|
||||||
|
android:name=".icon_16"
|
||||||
|
android:targetActivity=".MainActivity"
|
||||||
|
android:label="91PO黄果短剧RN"
|
||||||
|
android:enabled="false"
|
||||||
|
android:icon="@mipmap/icon_16"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity-alias>
|
||||||
|
|
||||||
|
<activity-alias
|
||||||
|
android:name=".icon_17"
|
||||||
|
android:targetActivity=".MainActivity"
|
||||||
|
android:label="黄果短剧"
|
||||||
|
android:enabled="false"
|
||||||
|
android:icon="@mipmap/icon_17"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity-alias>
|
||||||
|
|
||||||
|
<activity-alias
|
||||||
|
android:name=".icon_18"
|
||||||
|
android:targetActivity=".MainActivity"
|
||||||
|
android:label="黄果短剧"
|
||||||
|
android:enabled="false"
|
||||||
|
android:icon="@mipmap/icon_18"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity-alias>
|
||||||
|
|
||||||
|
<provider
|
||||||
|
android:name="androidx.core.content.FileProvider"
|
||||||
|
android:authorities="${applicationId}.fileprovider"
|
||||||
|
android:exported="false"
|
||||||
|
android:grantUriPermissions="true"
|
||||||
|
tools:replace="android:authorities">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
|
android:resource="@xml/totalfilepath"
|
||||||
|
tools:replace="android:resource" />
|
||||||
|
</provider>
|
||||||
|
|
||||||
|
<provider
|
||||||
|
android:name="com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFileProvider"
|
||||||
|
android:authorities="${applicationId}.flutter_inappwebview_android.fileprovider"
|
||||||
|
android:exported="false"
|
||||||
|
android:grantUriPermissions="true">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
|
android:resource="@xml/provider_paths" />
|
||||||
|
</provider>
|
||||||
|
|
||||||
|
<!-- Don't delete the meta-data below.
|
||||||
|
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||||
|
<meta-data
|
||||||
|
android:name="flutterEmbedding"
|
||||||
|
android:value="2" />
|
||||||
|
</application>
|
||||||
|
</manifest>
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
package io.flutter.plugins;
|
||||||
|
|
||||||
|
import android.media.MediaMetadataRetriever;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
|
||||||
|
/// 本地视频文件信息:时长 / 分辨率 / 比例 / 高度 / 比特率
|
||||||
|
/// 注:MediaMetadataRetriever 持有 native 资源,每次用完必须 release,否则多次调用后取不到任何信息
|
||||||
|
public class JPFileUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取视频时长(秒)
|
||||||
|
*/
|
||||||
|
public static int getVideoDuration(String filePath) {
|
||||||
|
String ms = extract(filePath, MediaMetadataRetriever.METADATA_KEY_DURATION);
|
||||||
|
if (TextUtils.isEmpty(ms) || !TextUtils.isDigitsOnly(ms)) return 0;
|
||||||
|
return Integer.parseInt(ms) / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取视频分辨率,格式 "宽*高",取不到返回空串
|
||||||
|
*/
|
||||||
|
public static String getVideoResolution(String filePath) {
|
||||||
|
int[] size = videoSize(filePath);
|
||||||
|
return size[0] > 0 && size[1] > 0 ? size[0] + "*" + size[1] : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取视频宽高比
|
||||||
|
*/
|
||||||
|
public static String getVideoRatio(String filePath) {
|
||||||
|
int[] size = videoSize(filePath);
|
||||||
|
if (size[0] <= 0 || size[1] <= 0) return "0";
|
||||||
|
return String.valueOf((float) size[0] / size[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取视频高度
|
||||||
|
*/
|
||||||
|
public static String getVideoHeight(String filePath) {
|
||||||
|
int[] size = videoSize(filePath);
|
||||||
|
if (size[0] <= 0 || size[1] <= 0) return "0";
|
||||||
|
return String.valueOf(size[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取比特率
|
||||||
|
*/
|
||||||
|
public static String getVideoBitrate(String filePath) {
|
||||||
|
String bitrate = extract(filePath, MediaMetadataRetriever.METADATA_KEY_BITRATE);
|
||||||
|
return TextUtils.isEmpty(bitrate) ? "0" : bitrate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取单个 metadata;用 FD 而非路径设源,避开部分机型对中文/特殊字符路径的兼容问题
|
||||||
|
*/
|
||||||
|
private static String extract(String filePath, int key) {
|
||||||
|
if (TextUtils.isEmpty(filePath)) return null;
|
||||||
|
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
|
||||||
|
try (FileInputStream in = new FileInputStream(filePath)) {
|
||||||
|
mmr.setDataSource(in.getFD());
|
||||||
|
return mmr.extractMetadata(key);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
release(mmr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视频宽高,取不到返回 {0,0}。宽高一次打开取完,避免为了宽和高开两次文件
|
||||||
|
*/
|
||||||
|
private static int[] videoSize(String filePath) {
|
||||||
|
int[] empty = {0, 0};
|
||||||
|
if (TextUtils.isEmpty(filePath)) return empty;
|
||||||
|
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
|
||||||
|
try (FileInputStream in = new FileInputStream(filePath)) {
|
||||||
|
mmr.setDataSource(in.getFD());
|
||||||
|
int width = parseInt(mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH));
|
||||||
|
int height = parseInt(mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT));
|
||||||
|
return new int[]{width, height};
|
||||||
|
} catch (Exception e) {
|
||||||
|
return empty;
|
||||||
|
} finally {
|
||||||
|
release(mmr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int parseInt(String value) {
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(value);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void release(MediaMetadataRetriever mmr) {
|
||||||
|
try {
|
||||||
|
mmr.release();
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
package io.flutter.plugins;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.media.MediaCodecInfo;
|
||||||
|
import android.media.MediaCodecList;
|
||||||
|
import android.media.MediaFormat;
|
||||||
|
import android.os.Build;
|
||||||
|
|
||||||
|
import com.meituan.android.walle.WalleChannelReader;
|
||||||
|
|
||||||
|
import io.flutter.embedding.android.FlutterActivity;
|
||||||
|
import io.flutter.embedding.engine.FlutterEngine;
|
||||||
|
import io.flutter.plugin.common.MethodCall;
|
||||||
|
import io.flutter.plugin.common.MethodChannel;
|
||||||
|
|
||||||
|
/// 本地插件:设备号 / 视频文件信息 / 渠道号 / H265 硬解能力
|
||||||
|
public class JPNativePlugin implements MethodChannel.MethodCallHandler {
|
||||||
|
|
||||||
|
private static final String CHANNEL = "com.yinse/device";
|
||||||
|
|
||||||
|
private final Activity activity;
|
||||||
|
|
||||||
|
private JPNativePlugin(Activity activity) {
|
||||||
|
this.activity = activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 注册
|
||||||
|
public static void registerWith(FlutterActivity flutterActivity, FlutterEngine engine) {
|
||||||
|
MethodChannel channel = new MethodChannel(engine.getDartExecutor().getBinaryMessenger(), CHANNEL);
|
||||||
|
channel.setMethodCallHandler(new JPNativePlugin(flutterActivity));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 调用
|
||||||
|
@Override
|
||||||
|
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
|
||||||
|
switch (call.method) {
|
||||||
|
case "getVideoDuration":
|
||||||
|
result.success(JPFileUtils.getVideoDuration(call.argument("filePath")));
|
||||||
|
break;
|
||||||
|
case "getVideoResolution":
|
||||||
|
result.success(JPFileUtils.getVideoResolution(call.argument("filePath")));
|
||||||
|
break;
|
||||||
|
case "getVideoRatio":
|
||||||
|
result.success(JPFileUtils.getVideoRatio(call.argument("filePath")));
|
||||||
|
break;
|
||||||
|
case "getVideoHeight":
|
||||||
|
result.success(JPFileUtils.getVideoHeight(call.argument("filePath")));
|
||||||
|
break;
|
||||||
|
case "getVideoBitrate":
|
||||||
|
result.success(JPFileUtils.getVideoBitrate(call.argument("filePath")));
|
||||||
|
break;
|
||||||
|
case "getChannel": // 获取android 渠道的东西
|
||||||
|
result.success(getChannel(activity));
|
||||||
|
break;
|
||||||
|
case "isH265HardwareSupported":
|
||||||
|
result.success(isHevcHardwareSupported());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// 不回 result 的话 Dart 那边的 Future 永远不完成
|
||||||
|
result.notImplemented();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 获取渠道号
|
||||||
|
public static String getChannel(Context context) {
|
||||||
|
return WalleChannelReader.getChannel(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 本机是否**硬解** H.265(HEVC)。只认硬解:软解(google/c2.android)当不支持,回落 264。
|
||||||
|
/// 查询编解码器能力,任何异常都按不支持处理。
|
||||||
|
private static boolean isHevcHardwareSupported() {
|
||||||
|
try {
|
||||||
|
MediaCodecList list = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
|
||||||
|
for (MediaCodecInfo info : list.getCodecInfos()) {
|
||||||
|
if (info.isEncoder() || !supportsHevc(info)) continue;
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
|
if (info.isHardwareAccelerated()) return true; // API29+ 直接问硬解
|
||||||
|
} else {
|
||||||
|
String name = info.getName().toLowerCase(); // 旧版本靠名字排除软解
|
||||||
|
if (!name.startsWith("omx.google.") && !name.startsWith("c2.android.")) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean supportsHevc(MediaCodecInfo info) {
|
||||||
|
for (String type : info.getSupportedTypes()) {
|
||||||
|
if (type.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.xvproject
|
||||||
|
|
||||||
|
import io.flutter.app.FlutterApplication
|
||||||
|
|
||||||
|
class JPApplication : FlutterApplication()
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package com.xvproject
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.ActivityManager
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
|
import io.flutter.embedding.engine.FlutterEngine
|
||||||
|
import io.flutter.plugin.common.MethodChannel
|
||||||
|
import io.flutter.plugins.JPNativePlugin
|
||||||
|
|
||||||
|
class MainActivity : FlutterActivity() {
|
||||||
|
|
||||||
|
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
||||||
|
super.configureFlutterEngine(flutterEngine)
|
||||||
|
JPNativePlugin.registerWith(this, flutterEngine)
|
||||||
|
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
|
||||||
|
.setMethodCallHandler { call, result ->
|
||||||
|
when (call.method) {
|
||||||
|
METHOD_CHANGE_ICON -> {
|
||||||
|
val index = call.argument<Int>(ARG_ICON_INDEX) ?: -1
|
||||||
|
ICON_ALIASES.getOrNull(index)?.let { switchIcon("$ALIAS_PACKAGE.$it") }
|
||||||
|
result.success(true)
|
||||||
|
}
|
||||||
|
// 不回 result 的话 Dart 那边的 Future 永远不完成
|
||||||
|
else -> result.notImplemented()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 切换启动图标:禁用当前入口 + 启用目标 alias,再杀掉桌面进程让图标立刻刷新
|
||||||
|
private fun switchIcon(alias: String) {
|
||||||
|
val pm = packageManager
|
||||||
|
pm.setComponentEnabledSetting(
|
||||||
|
componentName,
|
||||||
|
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP
|
||||||
|
)
|
||||||
|
pm.setComponentEnabledSetting(
|
||||||
|
ComponentName(this, alias),
|
||||||
|
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP
|
||||||
|
)
|
||||||
|
restartLauncher(pm)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 杀掉桌面进程,强制它重读图标
|
||||||
|
@SuppressLint("ServiceCast")
|
||||||
|
private fun restartLauncher(pm: PackageManager) {
|
||||||
|
val am = getSystemService(ACTIVITY_SERVICE) as ActivityManager
|
||||||
|
val intent = Intent(Intent.ACTION_MAIN)
|
||||||
|
.addCategory(Intent.CATEGORY_HOME)
|
||||||
|
.addCategory(Intent.CATEGORY_DEFAULT)
|
||||||
|
for (info in pm.queryIntentActivities(intent, 0)) {
|
||||||
|
am.killBackgroundProcesses(info.activityInfo?.packageName ?: continue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
//这个跟flutter的通道名称保持一致
|
||||||
|
private const val CHANNEL = "com.yinse/request"
|
||||||
|
|
||||||
|
private const val METHOD_CHANGE_ICON = "changeIcon"
|
||||||
|
private const val ARG_ICON_INDEX = "iconIndex"
|
||||||
|
|
||||||
|
/// 图标 alias 所在包名:AndroidManifest 里 activity-alias 写的是相对名(manifest package=com.xvproject),
|
||||||
|
/// 与 applicationId 不同,不能用 packageName 拼
|
||||||
|
private const val ALIAS_PACKAGE = "com.xvproject"
|
||||||
|
|
||||||
|
/// 下标即 Flutter 传来的 iconIndex,顺序必须与 manifest 里 activity-alias 的声明顺序一致
|
||||||
|
private val ICON_ALIASES = listOf(
|
||||||
|
"lld", "aiyinyue", "aiyuedu", "alipay", "bilibili", "binggandazhuozhan",
|
||||||
|
"meisijiejian", "myworld", "shenxuanzhizhan", "shuixinwuxian", "texuanxiaoshuo",
|
||||||
|
"tiantianmajiang", "tuyou", "weichat", "wendao", "yinyutusujiao",
|
||||||
|
"icon_16", "icon_17", "icon_18", //清明 / 端午 / 劳动
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Modify this file to customize your launch splash screen -->
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:drawable="?android:colorBackground" />
|
||||||
|
|
||||||
|
<!-- You can insert your own image assets here -->
|
||||||
|
<!-- <item>
|
||||||
|
<bitmap
|
||||||
|
android:gravity="center"
|
||||||
|
android:src="@mipmap/launch_image" />
|
||||||
|
</item> -->
|
||||||
|
</layer-list>
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector
|
||||||
|
android:height="108dp"
|
||||||
|
android:width="108dp"
|
||||||
|
android:viewportHeight="108"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#3DDC84"
|
||||||
|
android:pathData="M0,0h108v108h-108z"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Modify this file to customize your launch splash screen -->
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:drawable="@android:color/white" />
|
||||||
|
|
||||||
|
<!-- You can insert your own image assets here -->
|
||||||
|
<!-- <item>
|
||||||
|
<bitmap
|
||||||
|
android:gravity="center"
|
||||||
|
android:src="@mipmap/launch_image" />
|
||||||
|
</item> -->
|
||||||
|
</layer-list>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!-- Modify this file to customize your launch splash screen -->
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:opacity="opaque">
|
||||||
|
<item android:gravity="center">
|
||||||
|
<bitmap
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:mipMap="true"
|
||||||
|
android:src="@mipmap/ic_splash_bg" />
|
||||||
|
</item>
|
||||||
|
|
||||||
|
</layer-list>
|
||||||
|
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 208 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
||||||
|
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
|
<!-- Show a splash screen on the activity. Automatically removed when
|
||||||
|
the Flutter engine draws its first frame -->
|
||||||
|
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||||
|
</style>
|
||||||
|
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||||
|
This theme determines the color of the Android Window while your
|
||||||
|
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||||
|
running.
|
||||||
|
|
||||||
|
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||||
|
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
|
<item name="android:windowBackground">?android:colorBackground</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
|
<item name="android:windowBackground">@drawable/launch_bg</item>
|
||||||
|
<item name="android:colorPrimary">#12131C</item>
|
||||||
|
<item name="colorPrimaryDark">#12131C</item>
|
||||||
|
<item name="colorAccent">#12131C</item>
|
||||||
|
<item name="android:windowNoTitle">true</item>
|
||||||
|
<item name="windowActionBar">false</item>
|
||||||
|
</style>
|
||||||
|
<!-- Flutter UI 初始化时及运行时的窗口背景;缺失会导致浅色模式下窗口透明 -->
|
||||||
|
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
|
<item name="android:windowBackground">?android:colorBackground</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<paths>
|
||||||
|
<external-path
|
||||||
|
name="external-path"
|
||||||
|
path="." />
|
||||||
|
<external-cache-path
|
||||||
|
name="external-cache-path"
|
||||||
|
path="." />
|
||||||
|
<external-files-path
|
||||||
|
name="external-files-path"
|
||||||
|
path="." />
|
||||||
|
<files-path
|
||||||
|
name="files_path"
|
||||||
|
path="." />
|
||||||
|
<cache-path
|
||||||
|
name="cache-path"
|
||||||
|
path="." />
|
||||||
|
<root-path
|
||||||
|
name="name"
|
||||||
|
path="." />
|
||||||
|
<external-path
|
||||||
|
name="external_storage_root"
|
||||||
|
path="." />
|
||||||
|
</paths>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<!-- The INTERNET permission is required for development. Specifically,
|
||||||
|
the Flutter tool needs it to communicate with the running application
|
||||||
|
to allow setting breakpoints, to provide hot reload, etc.
|
||||||
|
-->
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
</manifest>
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
maven { url 'https://jitpack.io' } // 混淆
|
||||||
|
maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }
|
||||||
|
maven { url 'https://maven.aliyun.com/nexus/content/repositories/jcenter' }
|
||||||
|
maven { url 'https://maven.aliyun.com/nexus/content/repositories/google' }
|
||||||
|
maven { url 'https://maven.aliyun.com/nexus/content/repositories/gradle-plugin' }
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
classpath "com.github.CodingGay:BlackObfuscator-ASPlugin:3.9"
|
||||||
|
classpath 'com.github.Petterpx.walle:plugin:1.0.5'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }
|
||||||
|
maven { url 'https://maven.aliyun.com/nexus/content/repositories/jcenter' }
|
||||||
|
maven { url 'https://maven.aliyun.com/nexus/content/repositories/google' }
|
||||||
|
maven { url 'https://maven.aliyun.com/nexus/content/repositories/gradle-plugin' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.buildDir = '../build'
|
||||||
|
subprojects {
|
||||||
|
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
||||||
|
}
|
||||||
|
|
||||||
|
def ensureAndroidNamespace = { project ->
|
||||||
|
def androidExtension = project.extensions.findByName("android")
|
||||||
|
if (androidExtension == null || !androidExtension.hasProperty("namespace") || androidExtension.namespace != null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
def manifestFile = project.file("src/main/AndroidManifest.xml")
|
||||||
|
if (manifestFile.exists()) {
|
||||||
|
def manifestPackage = new XmlSlurper(false, false).parse(manifestFile).@package?.text()
|
||||||
|
if (manifestPackage) {
|
||||||
|
androidExtension.namespace = manifestPackage
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (project.group) {
|
||||||
|
androidExtension.namespace = project.group.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def setLibraryCompileSdk = { project ->
|
||||||
|
def androidExtension = project.extensions.findByName("android")
|
||||||
|
if (androidExtension == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (androidExtension.hasProperty("compileSdk")) {
|
||||||
|
androidExtension.compileSdk = 36
|
||||||
|
} else if (androidExtension.hasProperty("compileSdkVersion")) {
|
||||||
|
androidExtension.compileSdkVersion 36
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
// AGP 已锁定 compileSdk,跳过;该模块用自己声明的值即可
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def alignAndroidJvmTargets = { project ->
|
||||||
|
def androidExtension = project.extensions.findByName("android")
|
||||||
|
if (androidExtension == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (androidExtension.hasProperty("compileOptions")) {
|
||||||
|
androidExtension.compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_17
|
||||||
|
targetCompatibility JavaVersion.VERSION_17
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (androidExtension.hasProperty("kotlinOptions")) {
|
||||||
|
androidExtension.kotlinOptions {
|
||||||
|
jvmTarget = JavaVersion.VERSION_17.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
def finalizeAndroidAlignment = { project ->
|
||||||
|
if (project.plugins.hasPlugin("com.android.application") || project.plugins.hasPlugin("com.android.library")) {
|
||||||
|
ensureAndroidNamespace(project)
|
||||||
|
alignAndroidJvmTargets(project)
|
||||||
|
}
|
||||||
|
// afterEvaluate 阶段再强制一次 library 的 compileSdk,覆盖个别老插件
|
||||||
|
// (如 flutter_custom_dialog 在自身 build.gradle 写死 compileSdkVersion 28)
|
||||||
|
// 在 plugin apply 之后声明的低版本,否则配 Java 17 编译会报需 compileSdk≥30
|
||||||
|
if (project.plugins.hasPlugin("com.android.library")) {
|
||||||
|
setLibraryCompileSdk(project)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
subprojects {
|
||||||
|
plugins.withId("com.android.application") {
|
||||||
|
ensureAndroidNamespace(project)
|
||||||
|
// app 自己 build.gradle 已声明 compileSdk 36,这里不再重设(AGP 8.x 在 plugin apply 后会立即锁定 compileSdk)
|
||||||
|
}
|
||||||
|
plugins.withId("com.android.library") {
|
||||||
|
ensureAndroidNamespace(project)
|
||||||
|
setLibraryCompileSdk(project)
|
||||||
|
}
|
||||||
|
if (project.state.executed) {
|
||||||
|
finalizeAndroidAlignment(project)
|
||||||
|
} else {
|
||||||
|
afterEvaluate {
|
||||||
|
finalizeAndroidAlignment(project)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
project.evaluationDependsOn(':app')
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register("clean", Delete) {
|
||||||
|
delete rootProject.buildDir
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# build apk
|
||||||
|
# author: @sudong
|
||||||
|
# 使用方法:./build_release.sh 文件服务 http://in.test.tsmgsoce.com/sudong1/
|
||||||
|
./gradlew clean
|
||||||
|
rm -rf ./app/release/
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "gradle clean success"
|
||||||
|
./gradlew assembleRelease
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "gradle build success"
|
||||||
|
filename=`ls -t ./app/release|head -n1|awk '{print $0}'`
|
||||||
|
echo "filename is $filename"
|
||||||
|
cd ./app/release
|
||||||
|
# pwd
|
||||||
|
# scp -P 22889 $filename root@35.220.142.29:/data/test-apk/sudong1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# 生成密钥脚本
|
||||||
|
# author: @sudong
|
||||||
|
# 使用方法:./generatekey.sh alias
|
||||||
|
|
||||||
|
if [ $# -ne 1 ]; then
|
||||||
|
printf -- "Please input alias.\n\n"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
echo "输入参数密钥$1\n"
|
||||||
|
keystoreName="$1.jks"
|
||||||
|
echo "$keystoreName"
|
||||||
|
echo "$1"
|
||||||
|
if [ ! -d "./keystore" ]; then
|
||||||
|
mkdir ./keystore
|
||||||
|
fi
|
||||||
|
keystoreName=`uuidgen |cut -c 1-6`
|
||||||
|
keytool -genkeypair -alias $1 -keyalg "RSA" -keysize 2048 -keypass jiahua123456 -validity 3650 -keystore ./keystore/$1.jks -storepass jiahua123456 -dname "CN='中国', OU='广东', O='广东', L='广东', ST='广东', C='中国'"
|
||||||
|
echo jiahua123456 | keytool -importkeystore -srckeystore ./keystore/$1.jks -destkeystore ./keystore/$1.jks -deststoretype pkcs12
|
||||||
|
|
||||||
|
if [ ! -f "./key.properties" ]; then
|
||||||
|
touch ./key.properties
|
||||||
|
fi
|
||||||
|
# shellcheck disable=SC2129
|
||||||
|
echo "storePassword=jiahua123456" >> ./key.properties
|
||||||
|
echo "keyPassword=jiahua123456" >> ./key.properties
|
||||||
|
echo "keyAlias=$1" >> ./key.properties
|
||||||
|
echo "storeFile=./keystore/$1.jks" >> ./key.properties
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
org.gradle.jvmargs=-Xmx4g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
||||||
|
android.useAndroidX=true
|
||||||
|
android.enableJetifier=true
|
||||||
|
android.enableR8=true
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
pluginManagement {
|
||||||
|
def flutterSdkPath = {
|
||||||
|
def properties = new Properties()
|
||||||
|
file("local.properties").withInputStream { properties.load(it) }
|
||||||
|
def flutterSdkPath = properties.getProperty("flutter.sdk")
|
||||||
|
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
|
||||||
|
return flutterSdkPath
|
||||||
|
}()
|
||||||
|
|
||||||
|
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
gradlePluginPortal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||||
|
id "com.android.application" version "8.9.1" apply false
|
||||||
|
id "org.jetbrains.kotlin.android" version "2.1.0" apply false
|
||||||
|
}
|
||||||
|
|
||||||
|
include ":app"
|
||||||
|
After Width: | Height: | Size: 398 B |
|
After Width: | Height: | Size: 417 B |
|
After Width: | Height: | Size: 164 B |
|
After Width: | Height: | Size: 310 B |
|
After Width: | Height: | Size: 651 B |
|
After Width: | Height: | Size: 431 B |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 614 B |
|
After Width: | Height: | Size: 485 B |
|
After Width: | Height: | Size: 350 B |
|
After Width: | Height: | Size: 437 B |
|
After Width: | Height: | Size: 416 B |
|
After Width: | Height: | Size: 639 B |
|
After Width: | Height: | Size: 419 B |
|
After Width: | Height: | Size: 723 B |
|
After Width: | Height: | Size: 677 B |
|
After Width: | Height: | Size: 673 B |
|
After Width: | Height: | Size: 432 B |
|
After Width: | Height: | Size: 714 B |
|
After Width: | Height: | Size: 163 B |
|
After Width: | Height: | Size: 493 B |
|
After Width: | Height: | Size: 424 B |
|
After Width: | Height: | Size: 624 B |
|
After Width: | Height: | Size: 434 B |
|
After Width: | Height: | Size: 170 B |
|
After Width: | Height: | Size: 314 B |
|
After Width: | Height: | Size: 601 B |
|
After Width: | Height: | Size: 602 B |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 683 B |
|
After Width: | Height: | Size: 456 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 417 B |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 495 B |
|
After Width: | Height: | Size: 186 B |
|
After Width: | Height: | Size: 536 B |
|
After Width: | Height: | Size: 685 B |
|
After Width: | Height: | Size: 226 B |