feat(app): E.1 内测 APK 构建配置 — Android 品牌化 + 签名 + ProGuard
- 更新应用名称为「暖记」(AndroidManifest + strings.xml) - 添加必要权限: INTERNET, CAMERA, READ_MEDIA_IMAGES, READ_EXTERNAL_STORAGE - 生成 release 签名密钥 (RSA 2048, 10000 天有效期) - 配置 ProGuard/R8 代码混淆 + 资源压缩 - 品牌化启动页: 奶油白背景 + 珊瑚色圆形「暖」字 logo - 品牌化应用图标: 各密度 mipmap (mdpi~xxxhdpi) - 添加阿里云 Maven 镜像加速依赖下载 - AGP 9.x 兼容: 自动为旧 Flutter 插件注入 namespace - Gradle 性能优化: 并行编译 + 构建缓存
@@ -1,9 +1,19 @@
|
|||||||
|
import java.util.Properties
|
||||||
|
import java.io.FileInputStream
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("com.android.application")
|
id("com.android.application")
|
||||||
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
|
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
|
||||||
id("dev.flutter.flutter-gradle-plugin")
|
id("dev.flutter.flutter-gradle-plugin")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 从 key.properties 加载签名配置
|
||||||
|
val keystorePropertiesFile = rootProject.file("key.properties")
|
||||||
|
val keystoreProperties = Properties()
|
||||||
|
if (keystorePropertiesFile.exists()) {
|
||||||
|
keystoreProperties.load(FileInputStream(keystorePropertiesFile))
|
||||||
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "com.nuanji.nuanji_app"
|
namespace = "com.nuanji.nuanji_app"
|
||||||
compileSdk = flutter.compileSdkVersion
|
compileSdk = flutter.compileSdkVersion
|
||||||
@@ -15,21 +25,33 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
|
||||||
applicationId = "com.nuanji.nuanji_app"
|
applicationId = "com.nuanji.nuanji_app"
|
||||||
// You can update the following values to match your application needs.
|
minSdk = 24 // Android 7.0+ — 支持 Isar 原生库 + CameraX
|
||||||
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
|
||||||
minSdk = flutter.minSdkVersion
|
|
||||||
targetSdk = flutter.targetSdkVersion
|
targetSdk = flutter.targetSdkVersion
|
||||||
versionCode = flutter.versionCode
|
versionCode = flutter.versionCode
|
||||||
versionName = flutter.versionName
|
versionName = flutter.versionName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signingConfigs {
|
||||||
|
create("release") {
|
||||||
|
if (keystorePropertiesFile.exists()) {
|
||||||
|
keyAlias = keystoreProperties["keyAlias"] as String
|
||||||
|
keyPassword = keystoreProperties["keyPassword"] as String
|
||||||
|
storeFile = file(keystoreProperties["storeFile"] as String)
|
||||||
|
storePassword = keystoreProperties["storePassword"] as String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
// TODO: Add your own signing config for the release build.
|
signingConfig = signingConfigs.getByName("release")
|
||||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
isMinifyEnabled = true
|
||||||
signingConfig = signingConfigs.getByName("debug")
|
isShrinkResources = true
|
||||||
|
proguardFiles(
|
||||||
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||||
|
"proguard-rules.pro"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
38
app/android/app/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# 暖记 ProGuard 规则
|
||||||
|
# 保留 Flutter 引擎
|
||||||
|
-keep class io.flutter.app.** { *; }
|
||||||
|
-keep class io.flutter.plugin.** { *; }
|
||||||
|
-keep class io.flutter.util.** { *; }
|
||||||
|
-keep class io.flutter.view.** { *; }
|
||||||
|
-keep class io.flutter.** { *; }
|
||||||
|
-keep class io.flutter.plugins.** { *; }
|
||||||
|
|
||||||
|
# Isar 数据库 — 保留 native 调用
|
||||||
|
-keep class com.isor.** { *; }
|
||||||
|
-keep class isar.** { *; }
|
||||||
|
-keepclassmembers class ** {
|
||||||
|
native <methods>;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Dio 网络库
|
||||||
|
-dontwarn okhttp3.**
|
||||||
|
-dontwarn okio.**
|
||||||
|
-keep class okhttp3.** { *; }
|
||||||
|
-keep interface okhttp3.** { *; }
|
||||||
|
|
||||||
|
# Gson / JSON 序列化
|
||||||
|
-keepattributes Signature
|
||||||
|
-keepattributes *Annotation*
|
||||||
|
-keep class com.google.gson.** { *; }
|
||||||
|
|
||||||
|
# freezed 生成的类 — 保留 JSON 序列化
|
||||||
|
-keepclassmembers class **.models.** {
|
||||||
|
*** fromJson(...);
|
||||||
|
*** toJson();
|
||||||
|
}
|
||||||
|
|
||||||
|
# 保留所有序列化相关类
|
||||||
|
-keepclassmembers class * {
|
||||||
|
*** INSTANCE;
|
||||||
|
*** Companion;
|
||||||
|
}
|
||||||
@@ -1,9 +1,20 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<!-- 网络权限 — API 同步、图片上传 -->
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||||
|
<!-- 相机权限 — 日记拍照 -->
|
||||||
|
<uses-permission android:name="android.permission.CAMERA"/>
|
||||||
|
<!-- 照片权限 — Android 13+ 细化媒体权限 -->
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
|
||||||
|
<!-- 照片权限 — Android 12 及以下 -->
|
||||||
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"/>
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:label="nuanji_app"
|
android:label="@string/app_name"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:networkSecurityConfig="@xml/network_security_config">
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
|
android:usesCleartextTraffic="false">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Modify this file to customize your launch splash screen -->
|
<!-- 暖记启动页 — 奶油白背景 + 居中 logo -->
|
||||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:drawable="@android:color/white" />
|
<item android:drawable="@color/bg_light" />
|
||||||
|
<item>
|
||||||
<!-- You can insert your own image assets here -->
|
|
||||||
<!-- <item>
|
|
||||||
<bitmap
|
<bitmap
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:src="@mipmap/launch_image" />
|
android:src="@drawable/launch_logo" />
|
||||||
</item> -->
|
</item>
|
||||||
</layer-list>
|
</layer-list>
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 暖记启动页 (深色模式) — 深色背景 + 居中 logo -->
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:drawable="@color/bg_dark" />
|
||||||
|
<item>
|
||||||
|
<bitmap
|
||||||
|
android:gravity="center"
|
||||||
|
android:src="@drawable/launch_logo" />
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
||||||
BIN
app/android/app/src/main/res/drawable/launch_logo.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 544 B After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 442 B After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 721 B After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 12 KiB |
4
app/android/app/src/main/res/values-night/colors.xml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="launch_bg">#1A1614</color>
|
||||||
|
</resources>
|
||||||
@@ -1,17 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<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">
|
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
<!-- Show a splash screen on the activity. Automatically removed when
|
<item name="android:windowBackground">@drawable/launch_background_dark</item>
|
||||||
the Flutter engine draws its first frame -->
|
<item name="android:statusBarColor">@color/bg_dark</item>
|
||||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
|
||||||
</style>
|
</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">
|
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
<item name="android:windowBackground">?android:colorBackground</item>
|
<item name="android:windowBackground">?android:colorBackground</item>
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
4
app/android/app/src/main/res/values-zh/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">暖记</string>
|
||||||
|
</resources>
|
||||||
9
app/android/app/src/main/res/values/colors.xml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<!-- 暖记设计系统颜色 -->
|
||||||
|
<color name="bg_light">#FFF8F0</color> <!-- 奶油白背景 -->
|
||||||
|
<color name="bg_dark">#1A1614</color> <!-- 深色背景 -->
|
||||||
|
<color name="accent">#E07A5F</color> <!-- 珊瑚色主色 -->
|
||||||
|
<color name="fg_light">#2D2420</color> <!-- 浅色模式文字 -->
|
||||||
|
<color name="fg_dark">#F0E8DF</color> <!-- 深色模式文字 -->
|
||||||
|
</resources>
|
||||||
4
app/android/app/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">暖记</string>
|
||||||
|
</resources>
|
||||||
@@ -1,17 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
<!-- 浅色模式启动主题 — 奶油白背景 -->
|
||||||
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
<style name="LaunchTheme" parent="@android:style/Theme.Light.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>
|
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||||
|
<item name="android:statusBarColor">@color/bg_light</item>
|
||||||
</style>
|
</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.Light.NoTitleBar">
|
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||||
<item name="android:windowBackground">?android:colorBackground</item>
|
<item name="android:windowBackground">?android:colorBackground</item>
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
|
// 阿里云 Maven 镜像 — 加速中国大陆依赖下载
|
||||||
|
maven { url = uri("https://maven.aliyun.com/repository/google") }
|
||||||
|
maven { url = uri("https://maven.aliyun.com/repository/central") }
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
@@ -15,6 +18,28 @@ subprojects {
|
|||||||
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
|
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
|
||||||
project.layout.buildDirectory.value(newSubprojectBuildDir)
|
project.layout.buildDirectory.value(newSubprojectBuildDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
subprojects {
|
||||||
|
// 为缺少 namespace 的旧 Flutter 插件自动注入 namespace
|
||||||
|
// 解决 AGP 9.x 要求必须指定 namespace 的问题
|
||||||
|
plugins.withId("com.android.library") {
|
||||||
|
val android = project.extensions.getByName("android")
|
||||||
|
if (android is com.android.build.gradle.LibraryExtension && android.namespace == null) {
|
||||||
|
val manifestFile = project.file("src/main/AndroidManifest.xml")
|
||||||
|
if (manifestFile.exists()) {
|
||||||
|
val packageName = manifestFile.readLines()
|
||||||
|
.firstOrNull { it.contains("package=") }
|
||||||
|
?.let { line ->
|
||||||
|
Regex("package=\"([^\"]+)\"").find(line)?.groupValues?.get(1)
|
||||||
|
}
|
||||||
|
if (packageName != null) {
|
||||||
|
android.namespace = packageName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subprojects {
|
subprojects {
|
||||||
project.evaluationDependsOn(":app")
|
project.evaluationDependsOn(":app")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,3 +4,8 @@ android.useAndroidX=true
|
|||||||
android.newDsl=false
|
android.newDsl=false
|
||||||
# This builtInKotlin flag was added by the Flutter template
|
# This builtInKotlin flag was added by the Flutter template
|
||||||
android.builtInKotlin=false
|
android.builtInKotlin=false
|
||||||
|
# 构建性能优化
|
||||||
|
org.gradle.parallel=true
|
||||||
|
org.gradle.caching=true
|
||||||
|
# 暂不启用 configuration-cache(与 init 脚本冲突)
|
||||||
|
# org.gradle.configuration-cache=true
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ pluginManagement {
|
|||||||
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
|
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
|
// 阿里云 Maven 镜像 — 加速中国大陆依赖下载
|
||||||
|
maven { url = uri("https://maven.aliyun.com/repository/google") }
|
||||||
|
maven { url = uri("https://maven.aliyun.com/repository/central") }
|
||||||
|
maven { url = uri("https://maven.aliyun.com/repository/gradle-plugin") }
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
gradlePluginPortal()
|
gradlePluginPortal()
|
||||||
|
|||||||