一、Flutter 打包
flutter build apk --release二、生成 release 签名文件:autoclick-key.jks
⚠️ 此步骤只需要做一次。已经有
autoclick-key.jks的话,可以直接跳到后面的签名配置。
2.1 生成 keystore 的命令
在项目根目录执行(确保android/app目录存在):
keytool -genkeypair \ -v \ -keystore ./android/app/autoclick-key.jks \ -alias autoclick \ -keyalg RSA \ -keysize 2048 \ -validity 10000
参数说明:
-keystore ./android/app/autoclick-key.jks生成的 keystore 文件路径与文件名(放在android/app目录下,后续 Gradle 会按这个路径去找)-alias autoclick此 keystore 中 key 的别名(后续local.properties和验证命令都要用同一个 alias)-validity 10000证书有效期天数(10000 天 ≈ 27 年,可按需调整)
2.2 生成过程中的交互说明
执行命令后,keytool会按顺序问你:
Keystore 密码(例如:
YourStorePassword)名字与姓氏 (CN):例如:
***
组织单位 (OU):例如:
Development
组织名称 (O):例如:
****
城市或区域 (L):例如:
***
省/市/自治区 (ST):例如:
***
国家代码 (C):例如:
CN
最后会给出一行类似:
CN=****, OU=Development, O=****, L=jinan, ST=shandong, C=CN 是否正确? [否]:
这里输入:
y
或yes即可完成生成。
2.3 生成后的文件位置与备份
生成成功后:
文件路径:
android/app/autoclick-key.jks这个文件非常重要:
以后所有版本更新必须使用同一个 keystore 签名
丢失后将无法给已安装用户推送升级
建议:
备份到安全位置(例如移动硬盘 / 私有云盘)
记录:
keystore 文件名:
autoclick-key.jkskeystore 密码:
storePasswordalias:
autoclickkey 密码:
keyPassword(若与 keystore 密码不同)
三、APK 文件名修改方案说明
3.1 核心目标
在保持 Flutter 默认生成的:
app-release.apk
的同时,额外复制一份带有应用名 + 版本号的 APK:
autoclick-v1.0.0(1)-release.apk(示例)
这样既不影响 Flutter 工具寻找默认 APK,又方便对外发布。
3.2 版本号来源:local.properties
在build.gradle.kts中,通过local.properties获取 Flutter 写入的版本信息:
// 1️⃣ 从 local.properties 中读取 Flutter 写入的版本号 val localProperties = Properties().apply { val localPropsFile = rootProject.file("local.properties") if (localPropsFile.exists()) { load(FileInputStream(localPropsFile)) } } // 如果没取到,就给个默认值防止构建失败 val flutterVersionCode: Int = (localProperties.getProperty("flutter.versionCode") ?: "1").toInt() val flutterVersionName: String = localProperties.getProperty("flutter.versionName") ?: "1.0.0"Flutter 在运行
flutter build时会自动往local.properties写入flutter.versionCode、flutter.versionName,这里直接读出来用于 APK 命名。
3.3 自定义拷贝 & 重命名 Release APK
在android/app/build.gradle.kts底部定义任务:
// === 重命名 flutter-apk 产物:Release 版本 === tasks.register("copyAndRenameFlutterApkRelease") { doLast { val outputDir = file("$buildDir/outputs/flutter-apk") if (!outputDir.exists()) { println("flutter-apk dir not found, skip rename (release)") return@doLast } val appName = "autoclick" val vName = flutterVersionName val vCode = flutterVersionCode outputDir.listFiles()?.forEach { file -> if (file.isFile && file.extension == "apk" && "release" in file.name) { val newName = "${appName}-v${vName}(${vCode})-release.apk" val newFile = File(outputDir, newName) // ✅ 注意:copy 而不是 rename,保留原始 app-release.apk file.copyTo(newFile, overwrite = true) println("Copied and renamed flutter-apk → $newName") } } } }关键点说明:
遍历
build/outputs/flutter-apk下的所有.apk文件只处理文件名中包含
release的 APK新文件命名规则:
${appName}-v${versionName}(${versionCode})-release.apk 例:autoclick-v1.0.0(1)-release.apk使用
copyTo(),保证原始app-release.apk不被删除,Flutter 仍然能找到默认 APK
3.4 与 assembleRelease 任务关联
为了在每次构建 Release APK 时自动执行上述复制任务:
// ✅ 用 matching 动态关联 assembleRelease 任务,避免 “Task not found” 错误 tasks.matching { it.name == "assembleRelease" }.configureEach { finalizedBy("copyAndRenameFlutterApkRelease") }含义:
在 Gradle 中匹配名为
assembleRelease的任务为其追加
finalizedBy("copyAndRenameFlutterApkRelease")即:
assembleRelease执行完成后,自动执行拷贝重命名任务
3.5 打包后目录结构示例
执行:
flutter build apk --release
成功后,build/app/outputs/flutter-apk/目录中会同时存在:
app-release.apk # Flutter 默认产物 autoclick-v1.0.0(1)-release.apk # 自定义命名产物(用于发布)
对外发包 / 安装测试时推荐使用:
autoclick-v1.0.0(1)-release.apk
四、签名配置说明(signingConfigs + local.properties)
4.1 Gradle 中的签名配置
在android { signingConfigs { ... } }中:
signingConfigs { create("release") { // 这里从 local.properties 中读取参数,这里有个 app/, // 所以 keytool 生成的 jks 要放到 android/app 目录下 storeFile = localProperties.getProperty("storeFile") ?.let { File(rootProject.projectDir, "app/$it") } storePassword = localProperties.getProperty("storePassword") keyAlias = localProperties.getProperty("keyAlias") keyPassword = localProperties.getProperty("keyPassword") } }在buildTypes中启用 release 签名:
buildTypes { getByName("release") { isMinifyEnabled = true isShrinkResources = true // 使用上面的 release 签名配置 signingConfig = signingConfigs.getByName("release") // 只需要手动创建 proguard-rules.pro,可以是空文件,但要放在 app 目录下 proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } getByName("debug") { isMinifyEnabled = false isShrinkResources = false } }4.2 local.properties 中的签名字段示例
在android/local.properties中,新增(敏感信息请自己替换):
# keystore 文件名(相对 android/app 路径) storeFile=autoclick-key.jks # keystore 密码 storePassword=你的_keystore_密码 # key 别名(alias),例如:autoclick keyAlias=autoclick # key 密码(通常与 storePassword 相同,也可以不同) keyPassword=你的_key_密码
⚠️ 注意:
autoclick-key.jks文件应位于:android/app/autoclick-key.jks请勿将包含密码的
local.properties和.jks文件提交到公共仓库(如 GitHub 公共仓库)
五、签名验证:keystore 与 APK 对应关系
签名验证分两步:
验证keystore 自身信息(别名、证书 DN、指纹)
验证APK 使用的签名证书,确认与 keystore 一致
5.1 查看 keystore 证书信息(keytool)
在项目根目录执行(或调整路径到实际位置):
keytool -list -v -keystore ./android/app/autoclick-key.jks -alias autoclick
命令说明:
-keystore:指向你的 keystore 文件-alias:你生成 keystore 时设置的别名(这里是autoclick)
执行后会让你输入keystore 密码,成功后会输出类似:
Alias name: autoclick Creation date: ... Entry type: PrivateKeyEntry Owner: CN=***, OU=Development, O=***, L=****, ST=****, C=CN SHA1: AA:BB:CC:DD:... SHA256: 11:22:33:44:... ...
建议记录下:
Owner(证书 DN)SHA1SHA256
后续与 APK 对比使用。
5.2 验证 Release APK 的签名证书(apksigner)
使用你自定义命名的 Release APK 文件:
apksigner verify --print-certs \ build/app/outputs/flutter-apk/autoclick-v1.0.0(1)-release.apk
如果系统找不到
apksigner,可以使用 Android SDK 中的完整路径,例如:$ANDROID_HOME/build-tools/<build-tools-version>/apksigner verify --print-certs \ build/app/outputs/flutter-apk/autoclick-v1.0.0(1)-release.apk
输出示例:
Verifies Verified using v2 scheme (APK Signature Scheme v2) Verified using v3 scheme (APK Signature Scheme v3) Number of signers: 1
核对要点:
Signer #1 certificate DN是否与keytool -list输出的Owner一致SHA-1 digest/SHA-256 digest是否与 keystore 中的SHA1/SHA256一致
如果两处信息完全一致,说明:
✅
autoclick-v1.0.0(1)-release.apk确实是用android/app/autoclick-key.jks中 alias 为autoclick的 key 进行签名的,可以作为正式 Release 包对外发布。
六、常见问题 FAQ
Q1:目录里有两个 APK,我到底用哪个?
app-release.apkFlutter 默认生成,工具链依赖它
autoclick-v1.0.0(1)-release.apk通过
copyAndRenameFlutterApkRelease任务生成推荐作为对外发布 / 安装测试 / 上架的文件
签名一致,用哪一个都行;建议统一使用自定义命名的那个。
Q2:每次改版本号,需要改哪里?
Flutter 侧:在
pubspec.yaml中修改:version: 1.0.0+1
1.0.0=flutter.versionName1=flutter.versionCode
执行构建命令时,Flutter 会自动同步到
local.properties, Gradle 的flutterVersionName/flutterVersionCode会自动更新, 自定义 APK 命名也会随之变化,无需额外修改代码。
Q3:如何确认当前 Release 是否用的是 debug 签名?
如果apksigner输出中出现类似:
CN=Android Debug, O=Android, C=US
则说明是debug 签名,需要检查:
buildTypes { release { signingConfig = signingConfigs.getByName("release") } }是否正确local.properties中的storeFile等字段是否填写完整keystore 路径是否存在、密码是否正确
七、keytool 常用操作速查(进阶)
本节是对 keytool 相关操作的补充,方便以后查看 / 维护 keystore。 生成 keystore 的命令已在第二章给出,这里不再重复。
7.1 查看 keystore 中所有别名(alias 列表)
如果忘记 keystore 中有哪些 alias,可以不加-alias,只看列表:
keytool -list -keystore ./android/app/autoclick-key.jks
系统会让你输入 keystore 密码,然后打印所有别名名称。 再根据别名,使用前面的:
keytool -list -v -keystore ./android/app/autoclick-key.jks -alias autoclick
查看某个具体 alias 的详细证书信息。
7.2 修改 keystore 密码 / key 密码(可选操作)
修改 keystore 密码:
keytool -storepasswd -keystore ./android/app/autoclick-key.jks
修改某个 alias 对应的 key 密码:
keytool -keypasswd \ -keystore ./android/app/autoclick-key.jks \ -alias autoclick
修改后记得同步更新android/local.properties中的:
storePassword=新的_keystore_密码 keyPassword=新的_key_密码
7.3 导出证书(可用于对接第三方平台)
部分第三方平台会要求你提供签名证书(.cer/.pem):
keytool -exportcert \ -keystore ./android/app/autoclick-key.jks \ -alias autoclick \ -file ./android/app/autoclick-cert.cer \ -rfc
生成的autoclick-cert.cer就可以提供给需要校验证书的第三方。