Android(安卓)上架流程与构建文档
目录
- 第一部分 上架完整流程
- 1. 流程总览
- 2. 上架前需要准备的材料
- 3. 注册开发者账号
- 4. 生成签名认证文件(密钥库 .jks)
- 5. 把签名配置接入工程
- 6. 产物格式选择:AAB 还是 APK
- 7. 商店后台创建应用并提交审核
- 8. 常见驳回原因
- 9. 上架后的版本更新
- 第二部分 构建与打包操作文档
- 10. 环境要求
- 11. 开发工具
- 12. 构建步骤
- 13. 打包
- 14. 真机调试
- 15. 注意事项
- 第三部分 常见坑
第一部分 上架完整流程
1. 流程总览
准备资质材料
└─ 营业执照 / 身份证、软件著作权、隐私政策、App 备案
↓
注册开发者账号(Google Play / 华为 / 小米 / OPPO / vivo / 应用宝 / 荣耀)
↓
开发者实名认证(个人)或企业认证(对公打款 / 授权函)
↓
生成签名密钥库 release.jks(keytool 或 Android Studio)
↓
把签名配置写进 android/app/build.gradle
↓
构建 H5 产物 → 同步到 Android → 打签名包(AAB 上架 / APK 测试)
↓
商店后台创建应用 → 填写商店信息 → 上传包 → 上传资质
↓
提交审核 → 通过 → 发布上架
一次完整的首次上架,卡点通常不在打包,而在「实名/企业认证」和「资质材料」这两步,需要预留时间。按华为《实名认证》文档:企业打款认证最快 30 分钟、人工审核 1~2 个工作日;个人人脸识别或个人银行卡认证即时完成、人工审核 1~2 个工作日。各平台官方文档都没给出商店审核时长的承诺值,按实际排队情况预留。
2. 上架前需要准备的材料
| 材料 | 用途 | 说明 |
|---|---|---|
| 营业执照(企业)或身份证(个人) | 开发者账号实名/企业认证 | 企业还需法人身份证、对公银行账户 |
| 对公银行账户 | 企业认证打款验证 | 部分平台以打款小额随机金额方式验证 |
| 开发者资质授权函 | 企业认证 | 平台提供模板,需盖章 |
| 软件著作权登记证书 或 软件版权声明 | 上架资质 | 华为官方原文口径为软著属「非必选资质」,但建议申请《计算机软件著作权登记证书》《APP电子版权证书》或《软件著作权认证证书》以保护知识产权;游戏品类必需(软著 + 版号)。证书上的软件名称须与上架应用名称一致,著作权人须与开发者名称一致。软著登记周期较长,建议提前办 |
| App 备案号(工信部) | 国内商店上架 | 备案不在应用商店做,在云服务商(接入商)的备案系统做 —— 华为云/阿里云/腾讯云/移动云/天翼云/联通云。存在多个包名时所有包名均需备案;备案的包名、应用名称、主体信息必须与在架信息一致。无需备案的两类:单机应用(未通过公共互联网提供互联网信息服务)、境外应用(境外主体运营且服务器仅置于境外)。未备案会导致商店搜索与展示受限、安装时提示「应用未核准(备案)」 |
| ICP 备案 / 域名备案 | 应用内访问的服务端域名 | 服务端域名需已备案 |
| 隐私政策页面(可公网访问的 URL) | 商店信息填写 + 审核 | 需说明收集的个人信息、用途、第三方 SDK 清单 |
| 应用图标、应用截图、应用介绍 | 商店详情页 | 图标与截图尺寸各平台不同,按后台提示准备 |
| 测试账号 | 提交审核 | 需要登录才能用的 App 必须提供可用测试账号,否则会因「无法测试」被驳回 |
签名密钥库 release.jks |
打包签名 | 见第 4 节 |
如果丢进
dist/的 Web 产物需要登录才能进主界面,提交审核时必须一并提供可用测试账号和服务器地址,否则审核方进不去,会按「无法测试」驳回。
3. 注册开发者账号
3.1 Google Play(海外分发)
- 准备一个 Google 账号(建议用公司邮箱,不要用个人私有账号)。
- 打开 Google Play Console 注册页:
https://play.google.com/console/signup。 - 选择账号类型:
- 个人账号(Personal):认证材料相对简单;
- 组织账号(Organization):需要 D-U-N-S 编号(邓白氏编码;Apple 官方口径为「大多数司法管辖区免费申请」,申请周期通常 5~30 个工作日),用公司名称作为发布者名称必须走这条路。
- 缴纳注册费:一次性 25 美元,需国际信用卡。金额以 Play 管理中心注册页当时显示的为准。
- 完成身份验证:上传身份证明、地址证明;组织账号还需验证组织信息与法人。
- 填写开发者资料:开发者名称(展示给用户)、联系邮箱、联系电话、网站。
- 认证通过后即可创建应用。
Google Play 的签名机制(重点):Google Play 默认启用 Play App Signing(Play 应用签名)。这时存在两把 key:
- 上传密钥(upload key):就是你本地的 release.jks,用来给上传到 Play 的 AAB 签名;
- 应用签名密钥(app signing key):由 Google 托管,最终分发给用户的 APK 用它签名。
好处是上传密钥丢了可以向 Google 申请重置;但应用签名密钥一旦确定不可更换。
3.2 华为应用市场(AppGallery)
- 注册华为开发者账号:
https://developer.huawei.com/consumer/cn/。 - 实名认证:
- 按华为《实名认证》文档:企业三选一 —— ① 打款认证(官方推荐,最快 30 分钟):企业对公账号 + 法定代表人姓名 + 身份证号;② 人工审核(1~2 个工作日):营业执照原件扫描件或照片 + 法定代表人手持身份证正反面照片或人脸识别;③ 华为云授权认证(账号已在华为云实名为企业客户)。个人四选一 —— 人脸识别(推荐,即时完成)、个人银行卡(推荐,即时完成)、人工审核(1~2 个工作日)、华为云授权认证。
- 官方认证方式列表中不含任何收费项,此前"企业认证需支付认证费"的说法未在官方文档中出现,已删除。
- 企业认证暂不支持电子营业执照,须提供最新「三证合一」营业执照照片或扫描件,且信息与国家企业信用信息公示系统一致;法人为港澳台人士可提交手持通行证或护照照片,海外人士提供手持护照照片。不支持港澳台、海外企业及海外个人注册认证中国大陆开发者联盟账号(须走海外官网)。
- 进入 AGC(AppGallery Connect):
https://developer.huawei.com/consumer/cn/service/josp/agc/index.html。 - 创建应用。当前路径(AGC 帮助《创建应用》,更新于 2026-07-22):先在「证书、APP ID 和 Profile > APP ID」新建 APP ID(填应用类型、应用名称、应用包名、应用分类),再在 APP ID 列表中点「发布」为该 APP ID 关联创建待发布应用(填支持设备、默认语言),完成后才会出现在「APP 与元服务」列表中;旧版「我的应用 → 新建」已不是当前入口。仓库默认的 Android 包名是
com.d3.app。包名与应用分类一旦创建均不可修改,务必先确认。包名命名规范(段数、字符、保留字)见鸿蒙文档第 5.1 节。
- 填写应用信息:图标、简介、详细介绍、截图、隐私政策 URL、版本说明、应用权限说明。
- 上传软著/著作权声明、App 备案号等资质。
- 上传签名包(华为 Android 应用一般收 APK)。
- 提交审核。
3.3 小米应用商店
- 注册小米开放平台账号:
https://dev.mi.com/。 - 完成开发者实名认证(个人/企业),企业需营业执照 + 对公账户。
- 「应用管理」→ 创建应用,填写包名、应用名。
- 上传 APK、应用图标、截图、简介、隐私政策链接、软著、备案号。
- 提交审核。
3.4 OPPO / vivo / 应用宝 / 荣耀
流程与小米高度一致:注册 → 实名/企业认证 → 创建应用 → 上传 APK 与资质 → 提交审核。入口:
| 商店 | 开放平台地址 |
|---|---|
| OPPO 软件商店 | https://open.oppomobile.com/ |
| vivo 应用商店 | https://dev.vivo.com.cn/ |
| 应用宝(腾讯) | https://open.qq.com/ |
| 荣耀应用市场 | https://developer.honor.com/ |
国内多渠道分发时,同一个 App 在所有渠道必须使用同一个签名密钥库,否则用户无法跨渠道覆盖安装升级。
4. 生成签名认证文件(密钥库 .jks)
Android 的「认证文件」就是一个 Java 密钥库(keystore),扩展名一般是 .jks 或 .keystore,里面存放签名用的私钥和自签名证书。Android 不需要向平台申请证书(这一点和 iOS、鸿蒙不同),密钥库由开发者自己生成,平台只校验签名一致性。
4.1 方式一:Android Studio 图形界面生成
- 菜单 Build → Generate Signed App Bundle / APK。

- 首次没有密钥库时,点击 Create new... 新建。

- 在 New Key Store 弹窗里填写各字段,字段含义见下图标注:

4.2 方式二:keytool 命令行生成(推荐,可复现)
keytool 随 JDK 提供,确认 java/keytool 在 PATH 中即可:
keytool -genkeypair -v \
-keystore release.jks \
-storetype PKCS12 \
-keyalg RSA -keysize 2048 \
-validity 10950 \
-alias release
执行后会依次询问密钥库口令、姓名(CN)、组织单位(OU)、组织(O)、城市(L)、省份(ST)、国家代码(C)。
-validity 10950约 30 年。按developer.android.google.cn的应用签名文档:签名密钥的有效期必须在 2033 年 10 月 22 日以后结束,此项由 Google Play 强制执行,官方建议使用 25 年或以上的有效期,因此不要用默认的很短有效期。- 生成好的密钥库放在
h5_iOS_Android/android/app/release.jks、别名用release,就能直接对应第 5 节的示例配置。
4.3 密钥库字段说明
| 字段 | 含义 | 建议 |
|---|---|---|
| Key store path | 密钥库文件保存路径 | 放到工程外的安全目录,不要提交到仓库 |
| Password / Confirm(上半部分) | 密钥库口令 | 用密码管理器保存 |
| Alias | 密钥别名 | 本文示例用 release |
| Password / Confirm(Key 部分) | 密钥口令 | 可与密钥库口令不同 |
| Validity (years) | 证书有效年限 | ≥ 25 年 |
| First and Last Name (CN) | 通用名 | 一般填应用名或负责人 |
| Organizational Unit (OU) | 部门 | 如 Mobile |
| Organization (O) | 组织/公司全称 | 会写进证书,用户可见 |
| City / State / Country Code | 城市/省/国家码 | 国家码用两位,如 CN |
4.4 提取公钥与证书指纹
第三方 SDK(地图、推送、登录等)常需要提供签名的 MD5/SHA1/SHA256 指纹:
# 方式一:直接列出密钥库中证书的全部指纹
keytool -list -v -keystore release.jks -alias release
# 方式二:先导出 PEM 公钥证书,再 dump 指纹(Windows 下常用)
keytool -exportcert -rfc -keystore release.jks -alias release > cert.pem
certutil -dump cert.pem
# 方式三:直接校验已打好的 APK 用的是哪把 key
<Android SDK>/build-tools/<版本>/apksigner verify --print-certs app-release.apk
4.5 保管要求
release.jks和两个口令丢失即无法再更新已上架的应用(Google Play 走 Play App Signing 时可申请重置上传密钥,国内商店基本无解,只能改包名重新上架)。- 密钥库文件、口令不要进 Git 仓库,写进
.gitignore,通过密码管理器等受控渠道分发给需要的人。
5. 把签名配置接入工程
签名配置写在 h5_iOS_Android/android/app/build.gradle:
android {
signingConfigs {
release {
storeFile file("release.jks")
storePassword "******"
keyAlias "release"
keyPassword "******"
}
}
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
仓库里的写法:
android/app/build.gradle没有用上面那种四个值明文硬编码的写法,而是从android/keystore.properties读取,即下面「推荐写法」那一段。仓库里只带keystore.properties.example模板,release.jks、cert.pem、keystore.properties都在.gitignore里,不随仓库分发。所以拿到这份开源代码后,打 release 包前必须自己补两样东西,否则签名会失败:
- 把自己的密钥库放到
android/app/release.jks(或放别处,用下面的storeFile指向它);- 复制
android/keystore.properties.example为android/keystore.properties,填入真实的storePassword/keyAlias/keyPassword。只出 debug 包(
.\gradlew assembleDebug)不需要这两步,Gradle 会用默认调试签名。
推荐写法(对外开源版本):
// android/app/build.gradle
def keystorePropertiesFile = rootProject.file("keystore.properties")
def keystoreProperties = new Properties()
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
signingConfigs {
release {
storeFile file(keystoreProperties['storeFile'] ?: 'release.jks')
storePassword keystoreProperties['storePassword'] ?: ''
keyAlias keystoreProperties['keyAlias'] ?: ''
keyPassword keystoreProperties['keyPassword'] ?: ''
}
}
}
# keystore.properties.example(提交到仓库,不含真实值)
storeFile=release.jks
storePassword=
keyAlias=release
keyPassword=
另外 android/local.properties 里记录的是本机 Android SDK 路径,属于本地环境文件,不应提交仓库。
6. 产物格式选择:AAB 还是 APK
Build → Generate Signed App Bundle / APK 的第一步就是选格式:

- Android App Bundle(.aab):上架用。Google Play 对新应用要求以 AAB 上传,具体以 Play Console 帮助中心的当前说明为准。
- APK:给真机装包测试、内部分发用。国内商店目前主要收 APK。
命令行对应关系:
# APK(release,已签名)
./gradlew assembleRelease # Windows: .\gradlew assembleRelease
# AAB(release,已签名)
./gradlew bundleRelease # Windows: .\gradlew bundleRelease
产物位置:
| 类型 | 路径 |
|---|---|
| release APK | android/app/build/outputs/apk/release/app-release.apk |
| release AAB | android/app/build/outputs/bundle/release/app-release.aab |
| debug APK | android/app/build/outputs/apk/debug/app-debug.apk |
7. 商店后台创建应用并提交审核
以国内商店为例的通用步骤:
- 后台创建应用,填入包名(仓库默认
com.d3.app)与应用名(仓库默认示例应用,定义在capacitor.config.ts与android/app/src/main/res/values/strings.xml)。 - 上传签名包。上传后后台会自动解析包名、版本号(
versionCode/versionName,定义在android/app/build.gradle)、目标 SDK。 - Google Play 的目标 API 级别要求(
developer.android.google.cn《满足 Google Play 的目标 API 级别要求》官方原文):自 2026 年 8 月 31 日起,新应用和应用更新必须以 Android 16(API 级别 36)或更高版本为目标平台,才能提交到 Google Play;Wear OS 与 Android Automotive OS 应用除外,须以 API 35 及以上为目标;Android TV 与 Android XR 应用也除外,须以 API 34 及以上为目标。现有应用若要对更高版本系统设备的新用户可用,targetSdk须不低于 35。 - 仓库默认
compileSdk/targetSdk是 35、minSdk是 23(见android/variables.gradle),不满足上面这条要求,提交 Google Play 前必须把targetSdk升到 36。官方留有延期通道:可在 Play 管理中心的应用延期表单申请延期至 2026 年 11 月 1 日。唯一豁免是「仅限特定组织内部用户使用且仅供内部分发的永久专用应用」。 - 升级
targetSdk属工程改动,本次未执行。 - 填写商店详情:图标、截图、一句话简介、详细介绍、更新说明、分类、关键词。
- 填写合规信息:隐私政策 URL、权限使用说明、个人信息收集清单、第三方 SDK 清单、是否含广告、年龄分级。
- 壳里已声明的权限见
android/app/src/main/AndroidManifest.xml,其中MANAGE_EXTERNAL_STORAGE(访问公共目录)在各商店尤其是 Google Play 审核非常严格,如果业务不必须,建议上架前移除。 - 上传资质:软著或电子版权证书(华为口径为非必选资质,游戏品类必需)、App 备案号、行业许可证(如需要)。华为侧上传入口为「AGC > APP与元服务 > 点击应用名称 > 版本信息 > 版权信息」;资质图片要求:原件拍照或彩色扫描件(或加盖公章的复印件)、在有效期内、不可隔屏拍摄、边角完整内容清晰(国徽不得遮挡)、无反光、水印只能一行且不遮挡重要信息,支持 JPG / PNG / BMP / PDF。
- 提交审核 → 等待结果 → 通过后选择立即发布或定时发布。
8. 常见驳回原因
- 未提供测试账号,或提供的账号无法登录(产物需要登录时必须提供);
- 权限申请与功能不匹配,尤其是
MANAGE_EXTERNAL_STORAGE、CAMERA、定位类权限; - 隐私政策缺失、无法访问,或未列明第三方 SDK;
- 缺少 App 备案号(国内强制,未备案会提示「应用未核准(备案)」并影响商店搜索与展示);软著在华为口径下属「非必选资质」,但部分商店与部分品类(尤其游戏)仍强制要求;
- 应用内含"更新提示/自更新"能力被判定为绕过商店分发。壳里集成了
@capgo/capacitor-updater热更新(只更新 H5 资源,不替换原生包),需在审核说明中解释清楚"仅更新 Web 资源、不下发可执行代码",Google Play 对此尤其敏感; - 明文 HTTP 请求。仓库的
capacitor.config.ts里server.androidScheme: "http"、android.allowMixedContent: true,并配了network_security_config,如被判定为不安全传输需给出说明或改为 HTTPS。
9. 上架后的版本更新
- 提升版本号:
android/app/build.gradle中versionCode(整数,每次必须递增)和versionName(展示字符串)。 - 重新走第二部分的构建打包流程,必须用同一个
release.jks签名。 - 后台新建版本 → 上传新包 → 填写更新说明 → 提交审核。
第二部分 构建与打包操作文档
这一部分讲怎么把 Web 产物装进 Android 壳、以及怎么打出可安装/可上架的包。
10. 环境要求
- Node / NPM 版本 >= 20
- Java / JDK 21(Android 构建依赖)。⚠️ 不能用 JDK 17:Capacitor 7 的
node_modules/@capacitor/android/capacitor/build.gradle把sourceCompatibility/targetCompatibility写死成JavaVersion.VERSION_21,JDK 17 会在:capacitor-android:compileReleaseJavaWithJavac直接失败。最省事的做法是用 Android Studio 自带的 JBR(<Android Studio 安装目录>\jbr,例如 JBR 21.0.10),详见第三部分第 2 条。 - Android SDK(建议通过 Android Studio 安装与管理)
- Capacitor CLI —— 已在
devDependencies里,npm install之后用npx cap调用即可,不需要全局安装
拉到项目后先安装依赖:
npm install
Capacitor 官方文档:https://capacitorjs.com/docs/plugins
工程结构
这是一个纯原生壳工程,只有壳和配置,没有前端框架、没有业务代码、没有构建工具链:
| 路径 | 说明 |
|---|---|
android/ |
Android 壳工程。Android Studio 打开的就是这个目录,不是仓库根目录 |
ios/ |
iOS 壳工程,见 iOS 文档 |
dist/ |
Web 产物投放目录。你自己项目打包出来的 index.html 和静态资源直接丢进来,一个单文件 html 也可以。目录内容不入库,仓库里只有 .gitkeep 占位 |
capacitor.config.ts |
Capacitor 配置,webDir 已经指向 dist,不需要改 |
resources/ |
logo.png / splash.png 两张源图,npm run assets 据此生成 Android 与 iOS 全套图标和启动图 |
package.json |
只声明 Capacitor 自身和插件依赖,没有任何前端框架 |
Android 侧的原生代码在 android/app/src/main/java/com/d3/app/:
MainActivity.java:继承BridgeActivity,负责崩溃日志落盘(Download/d3/logs/)、存储权限检查、WebView 参数配置。没有覆盖 WebView 的加载路径,走 Capacitor 默认行为,即加载android/app/src/main/assets/public/index.html;StoragePermissionPlugin.java:自定义插件,向 Web 侧暴露Download/d3/{assets,upgrade,logs}的读写能力,配合热更新使用。
壳里用到的 Capacitor 插件
下面这份清单与 package.json、android/capacitor.settings.gradle、ios/App/Podfile 三处一致。
| 插件 | 作用 |
|---|---|
@capacitor/core |
Capacitor 核心库 |
@capacitor/cli |
命令行工具(cap sync / cap copy / cap open) |
@capacitor/assets |
图标 / 启动页资源生成 |
@capacitor/android |
Android 平台支持 |
@capacitor/ios |
iOS 平台支持 |
@capacitor/app |
应用生命周期管理、硬件返回键 |
@capacitor/dialog |
原生弹窗 |
@capacitor/filesystem |
文件读写 |
@capacitor/haptics |
震动 |
@capacitor/keyboard |
键盘 |
@capacitor/share |
分享 |
@capacitor/splash-screen |
启动画面 |
@capacitor/status-bar |
状态栏 |
@capgo/capacitor-updater |
热更新,从指定地址拉 dist.zip 并切换版本。当前配置 autoUpdate: false、statsUrl: '',默认不联网 |
增删插件之后必须重新跑
npx cap sync,capacitor.settings.gradle和Podfile都是cap sync生成的,手改会被覆盖。
11. 开发工具
- Android Studio(包含 SDK Manager)
- Android SDK 版本根据需求选择,可以下载内置的也可以单独下载然后引入;
- SDK Manager 里安装 platform-tools、对应 API Level、build-tools。

- 真机(建议 Android 8+)
12. 构建步骤
12.1 首次拿到代码(只做一次)
npm install # 装 node_modules
npx cap sync # 同步插件配置,并生成 android/capacitor-cordova-android-plugins/
这两步都不能跳:
android/capacitor.settings.gradle和ios/App/Podfile全部用../node_modules/@capacitor/*相对路径引用插件源码,没有node_modules直接编译不过;android/settings.gradle硬 include 了:capacitor-cordova-android-plugins,android/app/build.gradle也implementation project(':capacitor-cordova-android-plugins'),但这个目录是cap sync的生成物、已被android/.gitignore排除,仓库里没有。跳过cap sync,Gradle 第一句就报项目不存在。
12.2 日常:换一次 Web 产物
# 1. 把你的产物(index.html + 静态资源)放进 h5_iOS_Android/dist
# 2. 拷进 Android 工程
npx cap copy android
# 3. 打开 Android Studio
npx cap open android
package.json 里已经配好等价的 npm scripts:
| 命令 | 等价于 | 什么时候用 |
|---|---|---|
npm run copy |
cap copy |
日常只换了 dist 内容,比 sync 快 |
npm run sync |
cap sync |
增删了插件、或改了 capacitor.config.ts |
npm run open:android |
cap open android |
打开 Android Studio |
npm run assets |
capacitor-assets generate |
换了 resources/ 里的图 |
dist/不是 Android 直接读取的目录。 Android 实际加载android/app/src/main/assets/public/index.html,cap copy负责把dist/整体拷过去(该目录同样被.gitignore排除)。只把文件丢进dist/就去点 Build,打出来的还是上一次的内容。从仓库拉下来的代码已带配置好的
android目录,不要执行npx cap add android,会重置MainActivity.java、AndroidManifest.xml、res/下的启动图资源等已有改动。
12.3 需要自己确认的工程配置
下面这些是仓库里的默认值,换成自己应用的信息:
| 位置 | 仓库默认值 |
|---|---|
capacitor.config.ts appId |
com.d3.app |
capacitor.config.ts appName / ios.scheme |
示例应用 |
android/app/build.gradle namespace / applicationId |
com.d3.app |
android/app/src/main/res/values/strings.xml |
app_name / package_name / custom_url_scheme / slogan |
android/app/src/main/AndroidManifest.xml |
申请了 16 项权限,含相机、精确定位、蓝牙、MANAGE_EXTERNAL_STORAGE,用不到的建议删,见第三部分第 8 条 |
13. 打包
图形界面方式
- 在 Android Studio 中选择 Build → Generate Signed Bundle / APK;
- 选择 AAB(上架)或 APK(真机测试);
- 选择/创建密钥库并填入口令;
- 配置完成后点击 Next,选择 Build Variant = release,点击 Create 开始创建正式包:

命令行方式
# 在 h5_iOS_Android/android 目录下执行
.\gradlew assembleRelease # 出 APK
.\gradlew bundleRelease # 出 AAB
.\gradlew assembleDebug # 出调试包,用默认调试签名,不需要 keystore.properties
完整流程:
cd <仓库根>\h5_iOS_Android
# 首次还需要 npm install,见 12.1
npx cap copy android # 把 dist/ 拷进 android/app/src/main/assets/public/
# 关键:JDK 必须是 21,用 17 编不过,见第三部分第 2 条
$env:JAVA_HOME = 'C:\Program Files\Android\Android Studio\jbr'
cd android
.\gradlew assembleRelease
产物位置:android/app/build/outputs/apk/release/(AAB 在 outputs/bundle/release/)
一次完整构建的参考数据
| 项 | 参考值 |
|---|---|
| 构建耗时 | 约 2 分 25 秒(非首次,Gradle 依赖已缓存) |
| 产物 | android/app/build/outputs/apk/release/app-release.apk,7.66 MB(体积取决于你放进 dist 的内容,壳本身约 3 MB) |
| 签名 | apksigner 验出 Signer #1 为发布证书主体,签名有效 |
打完包建议校验一下用的是哪把 key,别拿调试签名去上架:
# 在 h5_iOS_Android\android 目录下执行;build-tools 版本按本机实际安装的改
& "$env:LOCALAPPDATA\Android\Sdk\build-tools\35.0.0\apksigner.bat" verify --print-certs `
app\build\outputs\apk\release\app-release.apk
输出里 Signer #1 certificate DN 应该是自己密钥库里的主体,SHA-256 digest 可以跟商店后台登记的指纹对一下。如果输出的是 CN=Android Debug,说明签名配置没生效(多半是 keystore.properties 缺失或口令为空),别上传。
14. 真机调试
- 手机打开开发者选项与 USB 调试,用可传输数据的数据线连接电脑后,Android Studio 可以识别到设备:

- 可使用 Chrome 访问
chrome://inspect进行真机 WebView 调试。
15. 注意事项
- 可以安装 nvm 工具统一管理 node 版本,版本过高会导致报错。
- 注意环境变量的配置,确保项目能够正常运行。
- 应用图标和启动页:源图是
resources/logo.png和resources/splash.png,换图后执行npm run assets重新生成 Android 与 iOS 全套尺寸。该工具(https://github.com/ionic-team/capacitor-assets)要求项目根目录存在assets或resources文件夹,文件名不能改。 - 崩溃日志位置:优先写
/storage/emulated/0/Download/d3/logs/crash-YYYYMMDD-HHmmss.txt,没有存储权限时退到应用私有目录files/crash_logs/。逻辑在MainActivity.java的崩溃处理里。 - 提取 jks 文件中的公钥和证书指纹:
注意导出的
keytool -exportcert -rfc -keystore release.jks -alias release > cert.pem certutil -dump cert.pemcert.pem和release.jks都在.gitignore里,别提交。 - 滑动退出在 iOS 环境下不生效,Android 正常。
第三部分 常见坑
- 首次执行
.\gradlew会下载 Gradle 全量包(gradle-8.11.1-all.zip),首次构建耗时会明显更长,需保证网络可达services.gradle.org,或提前配好镜像。 - JDK 必须是 21,用 17 编不过。报错停在
:capacitor-android:compileReleaseJavaWithJavac,原文:
错误: 无效的源发行版:21
根因在 Capacitor 自己的构建脚本 node_modules/@capacitor/android/capacitor/build.gradle,那里写死了 JavaVersion.VERSION_21,跟 android/app/build.gradle 无关,改工程侧配置没用。处理:换 JDK 21,用 Android Studio 自带的 JBR 最省事:
$env:JAVA_HOME = 'C:\Program Files\Android\Android Studio\jbr' # Android Studio 自带的 JBR 就是 21
也可以在 android/gradle.properties 里写 org.gradle.java.home=<JDK21 路径>,但那行是本机路径、不该入库。另外 JAVA_HOME 与 PATH 上的 java 版本不一致时 Gradle 以 JAVA_HOME 为准,所以显式指定这一条最可靠。
3. 克隆后没跑 npm install + npx cap sync 就构建,必然失败。两个原因叠加:capacitor.settings.gradle 按相对路径找 node_modules 里的插件源码;settings.gradle include 的 :capacitor-cordova-android-plugins 是 cap sync 生成物、不入库。见 12.1。
4. 只把产物丢进 dist/ 就打包,包里还是旧内容。Android 读的是 android/app/src/main/assets/public/,中间必须有 npx cap copy android。这一步很容易漏,症状是改完没反应、以为缓存问题。
5. 启动图不会自己消失。capacitor.config.ts 里 SplashScreen.launchAutoHide 是 false,而 MainActivity.java 只做了 registerPlugin 和 WebView 配置,没有任何隐藏启动图的原生代码,也就是说必须由 Web 侧主动调一次 SplashScreen.hide()。你丢进 dist/ 的产物如果不调这个方法,可能一直停在启动图上。两个处理方向:产物里加上这句调用,或者把 launchAutoHide 改成 true 并靠 launchShowDuration 自动收起。
6. 产物不要依赖外部 CDN。曾经出现过启动图之后直接黑屏,根因是 Web 侧把框架标成 external、从一个不可达的 CDN 域名加载 ES module,手机 DNS 解析失败、模块图中断,页面只剩一个空的挂载节点。壳只负责加载本地文件,产物自带的外链失败它救不了。真机调试用 Chrome chrome://inspect 看 Console 能直接定位这类问题。
7. capacitor.config.ts 里 SplashScreen.layoutName: "splash" 是失效配置。android/app/src/main/res/layout/ 下只有 activity_main.xml,没有 splash.xml。实际生效的启动图来自 res/values/styles.xml 里 AppTheme.NoActionBarLaunch 的 android:windowBackground(@drawable/splash_with_text),走的是 Android 12+ SplashScreen API 的 postSplashScreenTheme 机制。要换启动图改这里,或者补一个 splash.xml 让配置生效。
8. AndroidManifest.xml 申请了 16 项权限,包括 CAMERA、ACCESS_FINE_LOCATION、BLUETOOTH_SCAN、MANAGE_EXTERNAL_STORAGE、READ_MEDIA_*,是原业务的需求。MainActivity.onCreate 里还带存储权限检查,装上打开可能先弹授权框。用不到的建议删干净:一是省掉无谓的授权弹窗,二是 MANAGE_EXTERNAL_STORAGE 属于敏感权限,Google Play 和国内商店都会要求书面说明用途,说不清会被驳回。
9. aapt2 报 Failed to stat file ... android.jar 的 WARN:构建期间会反复出现,但不影响结果(最终仍 BUILD SUCCESSFUL),可忽略。
10. versionCode 每次上传商店必须递增,否则拒收(提示 build already exists)。当前 android/app/build.gradle 里是 versionCode 1 / versionName "1.0"。
11. 签名配置从 android/keystore.properties 读取,build.gradle 里没有明文口令。仓库里不含 release.jks、cert.pem、keystore.properties,只有 keystore.properties.example 模板;缺文件时 assembleRelease 会因为 storePassword 为空而失败,按第 5 节补齐即可。注意 keystore.properties 里填的是明文口令,这个文件永远不要入库。
12. targetSdk 当前是 35(见 android/variables.gradle)。Google Play 从 2026-08-31 起要求新应用与更新以 API 36 为目标,上架 Google Play 前需要升级并回归测试。国内商店暂无此要求。