Files
FamilyBook_harmonyos/docs/上架/正式证书与签名切换.md
T
laoyang c0d5fdff01 docs(上架): 应用商店上架 / 正式证书 / APP 备案 全套材料
## 背景

用户要同时办三件事:① 上架华为 AppGallery ② 申请正式发布证书 ③ 在阿里云做 APP 备案。
本目录是这三件事的全部材料,信息**全部取自真实代码与实测**,不是套模板。

## 材料清单

| 文件 | 用途 |
|---|---|
| `README总览.md` | 先看这个:材料索引 + 三件事的先后关系 + 你现在就能做的 |
| `商店上架文案.md` | AGC 各字段可直接复制的文案(一句话简介/应用介绍/更新说明/分级问卷/隐私标签) |
| `商店信息_结构化.json` | 同上,机器可读 |
| `隐私政策.md` | 完整隐私政策正文 |
| `用户服务协议.md` | 完整用户协议正文 |
| `正式证书与签名切换.md` | 发布证书申请 + release 打包全流程 |
| `APP备案材料.md` | 阿里云 APP 备案逐字段填写指引 |
| `图标/app_icon_216.png` | AppGallery 图标(216×216,9.7KB) |
| `图标/app_icon_1024.png` | 备案图标 + 1024 规格(112KB) |
| `verify_materials.py` | 校验材料与代码一致(42 项) |

## 实测核对过的事实(材料里的数字都从这里来)

- 包名 `familybook.yangyq.net`、版本 `0.8.0` / versionCode `800`(`AppScope/app.json5`)
- 应用名「家书」(`AppScope/resources/base/element/string.json`)
- 权限 **只有 3 个且全是普通权限**:INTERNET / GET_NETWORK_INFO / DETECT_GESTURE
  (`entry/src/main/module.json5`)—— 定位、通讯录、相机、麦克风、设备标识符**一个都没申请**
- 第三方 SDK:**无广告、无统计、无推送**
- 后端域名 `family.yangyq.net`,服务器阿里云 `47.104.72.161`(中国大陆)

权限少是审核优势:「权限滥用」是驳回第一大类原因,家书直接绕开。
隐私政策第二节与第十节做了**权限逐条对照表**,可直接给审核看。

## 图标为什么要重做

包内 `fb_logo.png` 是 **192×192 且自带圆角**(四角透明,半径约 33px)。
AppGallery 两种规格都不达标(要 216 或 1024,且「square-shaped icon」)。
→ 取内部主色 #F2E9D8 铺满方形画布补掉缺角,图案原样叠加、不裁切不缩放,
  生成 216 与 1024 两版。图案与包内完全一致(审核要求后台图标 = 包内图标同一图案)。

第一版直接用 LANCZOS 放大,**保留了圆角**,被 `verify_materials.py` 抓到并修正 ——
这就是写那个校验脚本的意义。

## 四个必须先解决的问题(已写进总览,不隐瞒)

1. **现在是调试证书** → 备案要正式证书的公钥/MD5,上架要正式签名(调试包报 991/1014)
2. **没有「家书」软著** → 备案不强制;华为要求但可用《免责函》过渡(6 项现有软著均无关)
3. **隐私政策页面还不存在** → 站点无 privacy 路由;建议用华为自带托管服务(SyncCalendar 用的那个,实测 200)
4. **阿里云服务器是否包年包月** → 备案硬性要求,需用户去控制台确认

## 顺序(三者有依赖,不能乱)

```
① 申请正式证书(10 分钟,AGC 即时出证)
      ↓ 拿到后才能
② APP 备案(1~20 工作日,最慢,先提交)
③ 打 release .app 包
      ↓ 拿到备案号才允许提审
④ 提交 AppGallery 审核(1~7 工作日)
      ↓
⑤ 公安联网备案(上架后 30 日内)
```

## 校验

`python3 verify_materials.py` → **42 项全过**:
包名/版本/名称与代码一致、权限集合完全一致、隐私政策"未申请"的声明与代码相符、
字数限内、三份文档互相不打架、图标尺寸与四角不透明、已知缺口如实记录。

## 没做的事(刻意的)

- 不生成截图:必须真机原生界面,不能是设计稿(审核明确禁止)
- 不填备案表:实名主体必须本人操作,且工信部短信核验要发到本人手机
- 不碰 AGC:需要登录用户账号,部分环节要扫码/人脸
2026-11-01 09:56:04 +08:00

277 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 华为正式发布证书申请 + 家书切 release 签名
> **一句话结论**:现在用的是**调试证书**,它能装到自己手机,但**不能上架、不能用于 APP 备案**。
> 必须先生成**正式发布证书(.cer)+ 发布 Profile(.p7b)**,再改 `build-profile.json5` 切到 release。
---
## 一、先确认现状(已核实)
`build-profile.json5` 当前签名配置:
```json5
{
"name": "default",
"type": "HarmonyOS",
"material": {
"certpath": "/home/yongquan/code/cert/familybook/familybook.yangyq.net.debug.cer",
"keyAlias": "debugKey",
"profile": ".../familybook.yangyq.net.debug.p7b",
"signAlg": "SHA256withECDSA",
"storeFile": ".../familybook.yangyq.net.debug.p12"
}
}
```
文件名里带 `.debug.` —— **这是调试证书**。它的特征:
| 项目 | 调试证书 | 发布证书 |
|---|---|---|
| 有效期 | 约 90 天(会过期) | **1 年**(可续) |
| 可装机范围 | 仅登记过的调试设备(UDID 白名单) | **任意设备** |
| 能否上架 AppGallery | ❌ **不能**(审核报 991 / 1014) | ✅ 必须 |
| 能否用于 APP 备案 | ❌ **不能**(备案要正式证书的公钥/MD5) | ✅ 必须 |
| 能否用于 Map Kit | ✅ 可以(这也是之前 #33 的前提之一) | ✅ 可以 |
### 实测当前调试证书的指纹
```
MD5 : 7D:0C:4B:46:B7:C1:C0:D2:3C:6E:43:16:E5:C9:96:A3
SHA256 : DF:21:A3:C0:9F:79:54:57:93:05:F8:5C:64:F8:0C:AD:86:F7:98:53:EE:3A:88:7C:1D:EC:95:D2:18:DF:3A:37
公钥 : MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEWidkGnDSOw3/HE2y2GHl+fpWBIa5S+IlnNrsGUvwC1I2QWvtqCHWmwFlFK95zKXiM8s9yV3VVXh7ivN8ZJO3SC5N1TCrvB2lpLMBwcz4DA0kgHCMm/wDec6kOHx1xvCR
```
> ⚠️ **这三项是调试证书的,不能拿去备案**。备案必须是正式证书的。
---
## 二、申请正式发布证书(AGC 网页操作,约 10 分钟)
### 前置:确认开发者账号已实名
AGC → 右上角头像 → 「实名认证」。个人开发者需身份证 + 人脸/银行卡验证,通常 1–3 个工作日。
**你之前上架过 SyncCalendar,说明已实名,可跳过。**
### 步骤 1:生成 CSR + 密钥库(在 WSL 里做)
华为的 `.cer` 是**用你本地生成的 CSR 去换**的,私钥始终在你手里,不上传。
```bash
cd ~/code/cert/familybook
# 生成密钥库(PKCS#12)与 CSR
# ⚠️ 口令自己定,记牢 —— 每次打包都要输,丢了只能重新申请证书
keytool -genkeypair \
-alias familybook_release \
-keyalg EC -groupname secp384r1 -sigalg SHA384withECDSA \
-validity 3650 \
-keystore familybook.yangyq.net.release.p12 \
-storetype PKCS12 \
-dname "C=CN, O=yangyq, OU=personal, CN=familybook.yangyq.net" \
-storepass '<你的口令>' -keypass '<同一个口令>'
# 导出 CSR
keytool -certreq \
-alias familybook_release \
-keystore familybook.yangyq.net.release.p12 \
-storepass '<你的口令>' \
-file familybook.yangyq.net.release.csr
```
产出:
- `familybook.yangyq.net.release.p12`(**私钥,绝不上传、务必备份**)
- `familybook.yangyq.net.release.csr`(这个拿去换证书)
> 💡 也可以直接在 DevEco Studio 里做:`Build → Generate Key and CSR`,效果一样。
> 但你在 WSL 命令行做更可控,且方便脚本化。
### 步骤 2:在 AGC 上传 CSR,换回 .cer
1. 登录 https://developer.huawei.com/consumer/cn/service/josp/agc/index.html
2. 右上角「我的」→ **「用户与访问」** → 左侧 **「证书管理」**
3. 点 **「新增证书」**
4. 证书类型选 **「发布证书」**(Release,不是 Debug)
5. 上传刚生成的 `familybook.yangyq.net.release.csr`
6. 提交 → 下载得到 **`familybook.yangyq.net.release.cer`**
7. 把这个 `.cer` 放到 `~/code/cert/familybook/`
> ⚠️ 一个账号最多 1 个**发布证书**(调试证书可多个)。若已有(SyncCalendar 用的那个),
> 需要先**吊销**旧的才能新建 —— 但吊销会让 SyncCalendar 的更新包签不了名,
> **所以建议:给家书单独申请前,先确认是不是共用同一个。**
>
> 更稳妥的做法:**同一个发布证书可以签多个应用**(Profile 才是按应用绑定的),
> 所以直接用 SyncCalendar 那个发布证书也行,只需为家书新建一个 **Profile**。
### 步骤 3:创建发布 Profile(按应用绑定)
1. 还在「用户与访问」→ 左侧 **「Profile」**
2. 点 **「新增 Profile」**
3. Profile 类型选 **「发布」**
4. 绑定:
- **应用**:选「家书」(若 AGC 里还没建这个应用,先去「我的应用 → 新建」建一个)
- **证书**:选上一步那个发布证书
5. 提交 → 下载得到 **`familybook.yangyq.net.release.p7b`**
> ⚠️ Profile 与**包名**绑定。家书包名 `familybook.yangyq.net`,
> 必须与 AGC 里创建应用时填的包名**完全一致**。
### 步骤 4:配置应用包名与指纹(备案也要用)
1. AGC →「我的应用」→ 新建(如果还没建)
- 平台:**HarmonyOS**
- 应用名称:**家书**
- 包名:**familybook.yangyq.net**(一字不差,**创建后不可改**)
- 分类:实用工具
- 默认语言:简体中文
2. 「项目设置 → 常规 → 应用」→ **添加公钥指纹**
- 上传步骤 2 下载的 `.cer`,或直接填 SHA256 指纹
3. 顺手把 **「应用」的 Client ID** 记下来(工单 #33 的 Map Kit 要用它)
---
## 三、切换到 release 签名(改代码)
`build-profile.json5` 目前只有 `default` 一个 signingConfig。**不要直接改掉它**
(否则日常调试也得用发布证书,很麻烦),而是**新增一个 release 配置**:
```json5
{
"app": {
"signingConfigs": [
{
// 保留原调试配置,日常装机继续用它
"name": "default",
"type": "HarmonyOS",
"material": {
"certpath": ".../familybook.yangyq.net.debug.cer",
"keyAlias": "debugKey",
"profile": ".../familybook.yangyq.net.debug.p7b",
"signAlg": "SHA256withECDSA",
"storeFile": ".../familybook.yangyq.net.debug.p12",
"storePassword": "...",
"keyPassword": "..."
}
},
{
// 🆕 发布用(上架 / 对外分发)
"name": "release",
"type": "HarmonyOS",
"material": {
"certpath": "/home/yongquan/code/cert/familybook/familybook.yangyq.net.release.cer",
"keyAlias": "familybook_release",
"profile": "/home/yongquan/code/cert/familybook/familybook.yangyq.net.release.p7b",
"signAlg": "SHA256withECDSA",
"storeFile": "/home/yongquan/code/cert/familybook/familybook.yangyq.net.release.p12",
"storePassword": "<你的口令>",
"keyPassword": "<同一个口令>"
}
}
],
"products": [
{
"name": "default",
"signingConfig": "release", // ← 只改这一处
"targetSdkVersion": "26.0.0",
"compatibleSdkVersion": "6.1.1(24)",
"runtimeOS": "HarmonyOS"
}
]
}
}
```
打包:
```bash
source ~/.workbuddy/env/harmonyos.sh
cd ~/code/FamilyBook_harmonyos
# AppGallery 只收 .app(App Pack),不是 .hap
hvigorw --mode module -p product=default -p buildMode=release assembleApp --no-daemon
```
产出在 `build/default/outputs/default/` 下的 **`.app`** 文件。
### 打完后务必自检这三条
```bash
# ① 确认是 .app 不是 .hap
ls -la build/default/outputs/default/*.app
# ② 确认签名用的是发布证书(不是 debug)
# 解包看签名信息,证书 CN 里不应出现 "debug"
unzip -l xxx.app | head
# ③ 确认版本号
unzip -p xxx.app/entry/... module.json | grep -E 'versionName|versionCode'
```
---
## 四、拿到正式证书后,顺手做 APP 备案
**备案需要的三项,只有正式证书才能提供:**
```bash
cd ~/code/cert/familybook
# ① 公钥
openssl x509 -in familybook.yangyq.net.release.cer -pubkey -noout
# ② 签名 MD5(备案用,**去掉冒号**!)
openssl x509 -in familybook.yangyq.net.release.cer -fingerprint -MD5 -noout
# ③ 包名(在 app.json5 里,已知)
grep bundleName ~/code/FamilyBook_harmonyos/AppScope/app.json5
```
> ⚠️ 备案系统的 MD5 字段要求**去掉冒号**,小写或大写都行但要去掉分隔符。
> 例如 `7D:0C:4B:...` → `7d0c4b46b7c1c0d2...`
---
## 五、证书有效期与续期
| 项 | 有效期 | 到期后果 |
|---|---|---|
| 发布证书 `.cer` | **1 年**(自签发日) | 到期后无法用该证书签新包;已上架的应用仍可运行,但**无法发布更新** |
| 发布 Profile `.p7b` | 跟随证书 | 同上 |
| 密钥库 `.p12` | 你设的 validity(建议 10 年以上) | 丢了就永远无法再签同名应用 |
### 🔴 必须做的事
1. **`.p12` 私钥文件务必备份**(至少两地)。**它丢了 = 这个包名以后再也发不了更新**,
只能换包名重新上架,等于从零开始积累下载量。
2. 在日历里设一个**证书到期前 60 天**的提醒。
3. 续期方式:AGC 重新走一遍「新增证书 → 上传 CSR → 下载 .cer」,并**重建 Profile**。
> 用**同一个密钥库**重新生成 CSR 时,公钥不变,指纹也不变 —— 这样对已上架应用最省事。
---
## 六、常见坑(提前避开)
| 坑 | 现象 | 原因与解法 |
|---|---|---|
| 拿调试证书打包上架 | 上传成功,进审核后报 **991 / 1014** 包无效 | 必须用发布证书 + 发布 Profile |
| Profile 包名对不上 | 上传时报"包名与 Profile 不匹配" | Profile 绑包名,AGC 建应用时包名必须一字不差 |
| 忘了加公钥指纹 | Map Kit 报 `1002600004` / 地图不显示 | AGC「项目设置 → 常规 → 应用」添加 SHA256 指纹 |
| 私钥口令忘记 | 无法打包 | 只能重新申请证书(可用同一 CSR 会得到同公钥) |
| 传了 `.hap` | AGC 不认 | 必须是 `.app`(`assembleApp`,不是 `assembleHap`) |
| versionCode 没递增 | 上传被拒 | 每次上传都要比上次大 |
---
## 七、时间预期
| 环节 | 耗时 |
|---|---|
| 本地生成 CSR | 2 分钟 |
| AGC 签发证书 | **即时**(网页直接下载) |
| AGC 创建 Profile | **即时** |
| 本地切签名 + 打 release 包 | 5 分钟 |
| **AppGallery 审核** | **1–7 个工作日**(首次通常更久) |
| **APP 备案(阿里云初审)** | 1–2 个工作日 |
| **APP 备案(管局审核)** | **1–20 个工作日**(多数省份约 7 天) |
> 备案是最慢的一环。**建议顺序:先申请正式证书 → 同时提交 APP 备案 → 备案通过后再提审应用。**
> 因为华为要求上架时填写 APP 备案号,没有备案号会被拒。