Files
FamilyBook_harmonyos/docs/上架/正式证书与签名切换.md
laoyang 825008657b 品牌改名:家书 → 岁月家 (laoyang/FamilyBook#38)
## 起因

用户 2026-11-01:「家书已经有人做了,八月份刚上线的」。

核实:「家书 HomeBook」(广州家书科技有限责任公司,粤ICP备2026096420号,
2026-06 成立、08 上线)。功能**部分重合**(家庭记录 + 相册 + 家谱)。
华为审核指南 1.3「应用名称不得和其他应用名称相同,避免混淆」,
虽然个人与企业主体查重不互通、技术上能过,但被人工驳回概率高。

## 定名过程(用户逐个否掉)

| 候选 | 否决原因 |
|---|---|
| 寸草 | — |
| 家卷 | ❌ 与「家眷」同音,口头传播会打错字 |
| 家时光 | ❌ App Store 已有「家·时光」定位几乎一致;且「家+时光」是常见组合,辨识度低 |
| 家纪 | ❌ 已有重名 |
| **岁月家** | ✅ 搜不到同名应用;是口号的直接展开(岁月 + 家) |

## 最终定稿(用户明确指定)

```
应用名      岁月家
主标语      一家人用岁月写成的一本书     ← 不变
一句话简介  一家人用岁月写成的一本书     ← 改为与标语相同
官网标题    岁月家 · 一家人用岁月写成的一本书
英文名      FamilyBook                ← 不变
包名        familybook.yangyq.net     ← 不变
```

## 改动范围(17 + 18 处,12 个文件)

### 应用名(17 处)
`AppScope/resources/base/element/string.json` 的 app_name,
`entry/.../string.json` 的 16 条(应用名、卡片名、无障碍描述)。

### 用户可见文案(18 处)
`FbBackgroundSync` / `EntryAbility`「正在同步家书数据」、
`FbAttachOpen`「家书附件」相册名、`FbHttp` 地址校验失败提示、
`FbCardData` / `FbCardMediaData` 卡片空态「先在「家书」里填写服务器地址」、
`TopBar` / `Drawer` / `FbLoginPage` 的应用名文本、`FbSettingsPage` 的说明。

## 刻意不改

- **包名 / bundleName**(用户明确要求不变,且改了等于换一个应用)
- **英文名 FamilyBook**、目录名、仓库名(改了会让 git 历史、部署脚本、证书路径全跟改)
- **代码注释**里 200+ 处「家书 FamilyBook · 某模块」—— 不影响运行时,
  改了只会制造噪音 diff,让将来 blame 变难
- **主标语**里一个字都没动

## 验证

### 编译
`BUILD SUCCESSFUL`,33 tasks。

### 产物实测
解包 `.hap` 的 `resources.index`:
- 「岁月家」出现 **17** 次
- 「家书」出现 **0** 次

### 全局一致性校验(31 项全过)
`_tooling/check_rename.js`:
- 客户端 app_name / EntryAbility_label / 产物内容
- .ets 用户可见文案无残留(排除注释)
- 服务端非注释代码无残留
- `Auth::homeTitle()` 用「某某某的家庭岁月」
- `DEFAULT_SLOGAN` 未被改动
- 官网线上 5 个页面无「家书」、标题含岁月家、渲染后 h1 是品牌名
- 材料 app_name / 一句话简介 / 包名 / versionCode / 域名

⚠️ 校验过程中我自己的判据出了 2 次假红:
① 注释识别不全(漏了 `/**` 单行块注释和 `<!--` HTML 注释)→ 补齐 isCommentLine
② 「为什么叫岁月家」整节重写后,旧断言还在查「书信」「家与书」
   (那是**旧名字**的逻辑)→ 改成查「岁月」+「家」的拆解

## 一处语义决策(问过用户)

网页端 `Auth::homeTitle()` 生成「某某某的家书」—— 这是**产品核心语义**
(每个家有自己的那一本),直接换成品牌名会读成「某某某的岁月家」,不通。

用户定:改成 **「某某某的家庭岁月」**。
兜底(无姓名时)仍用品牌名「岁月家」。

## 连带影响(不阻塞)

- 上架材料 7 个文件已同步(含软著全称改为「岁月家家庭生活档案管理软件」)
- 官网已部署,线上标题已是新名字
- 软著申请尚未提交 —— 正好一次写对新名字,不需要变更
2026-11-01 19:55:36 +08:00

277 lines
11 KiB
Markdown
Raw Permalink 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 备案号,没有备案号会被拒。