# 构建、签名与发行核对清单

发行应绑定一个明确基线、一组不可混用的最终产物和分阶段回执。源码版本、测试数量、Archive、APK 文件、上传、提审和公开下载各有独立证据。以下命令供在授权构建环境核对，本次没有运行原生构建、签名、服务测试或渠道操作；当前状态见[版本发布](https://document.thestarline.cn/app/releases.md)。

## 冻结范围与版本资料

先记录仓库提交及未提交差异、目标平台、工具链、依赖锁文件、API 环境和计划版本。未提交改动也属于构建输入，不能只记一个 commit 后忽略工作区。共享 Account 必须以当前维护仓库和实际运行版本为准，不从 App 历史副本整目录部署。任何发布都不自动恢复暂停的小程序或启动手表任务。

```sh
git status --short
git rev-parse HEAD
node --version
xcodebuild -version
java -version
```

仅执行目标平台所需检查。保存输出前去除个人路径、账号、凭据和内部地址；公开发行说明只保留对评估兼容性有用的版本、产物标识及限制。版本表还应记录法律／隐私页版本、数据迁移、已知问题和回滚条件。

| 对象 | 必核对项 | 不能替代的证据 |
| --- | --- | --- |
| iOS | Bundle ID、营销版本、构建号、最低系统、设备族、权限、推送环境 | 源 plist 不等于最终 Archive，iPhone 测试不替代审核 iPad |
| Android | applicationId、versionName、versionCode、min/target SDK、权限、签名 | Debug 版本不等于 Release；文件名不证明签名或升级兼容 |
| 服务端 | 源码／镜像基线、迁移、配置来源、持久卷和稳定密钥版本 | 构建成功不等于已运行或业务可用 |
| 静态站 | 最终清单、正文、下载配置、公共文件范围 | 上传成功不等于公网字节、MIME、TLS 和链接正确 |

## Android 构建候选与签名

当前源码声明 `1.0.6-preview`、versionCode 7、API 26 起、编译与目标 API 35，实际候选必须重新读取。采用仓库 Gradle Wrapper，先核对 JDK 与插件组合，不因历史构建通过跳过当前兼容检查：

```sh
cd android-app
./gradlew --version
./gradlew :app:testDebugUnitTest :app:assembleDebug :app:assembleDebugAndroidTest \
  --max-workers=1 -Dorg.gradle.jvmargs=-Xmx1g \
  -Pkotlin.compiler.execution.strategy=in-process
./gradlew :app:assembleRelease --max-workers=1
```

最后一步只产生构建候选。当前 Gradle 未配置公开可复用的正式 Release 签名流程，不能把 unsigned 包、Debug key 或任意临时签名当作正式升级渠道。正式密钥由受保护签名系统提供，不在命令历史或文档中填写口令。

以下命令假定维护者已将正确签名的最终 APK 放为工作区内 `candidate-release.apk`，并准备好 Android SDK 命令：

```sh
apksigner verify --verbose --print-certs candidate-release.apk
apkanalyzer manifest application-id candidate-release.apk
apkanalyzer manifest version-name candidate-release.apk
apkanalyzer manifest version-code candidate-release.apk
apkanalyzer manifest min-sdk candidate-release.apk
apkanalyzer manifest target-sdk candidate-release.apk
shasum -a 256 candidate-release.apk
```

比对签名证书摘要、备案材料与上一可升级安装包，确认 application ID 不变、versionCode 递增。正式包不得包含模拟器地址、fixture 登录或本地 HTTP 依赖。Release 清单禁止明文流量，编译属性接受 URL 不代表网络策略允许。安装验收至少包括干净安装与从上一版原地升级；现有用户预览设备不得为测试方便而卸载或清数据。

升级后确认记忆、附件、任务、收藏和已登录恢复策略；对旧字段、加密格式和失败保护做专项回归。包签名变化可能阻止升级，应在独立 QA 设备发现，不能先要求用户删除原 App。验证完成后计算最终 SHA-256 与大小，后续重新签名、重打包或修改资源都要求重算并重验，不能沿用上一份摘要。

## iOS Archive 与发布签名

从 `project.yml` 与已提交 Xcode 工程核对源配置；当前最低 iOS 17、设备族 iPhone，Info.plist 仍含历史 1.0／构建 1。不得据此声称商店已有新构建。生成工程或修改版本后，检查实际构建设置：

```sh
xcodebuild -project ios-app/StarlineWorkbench.xcodeproj \
  -scheme StarlineWorkbench -configuration Release -showBuildSettings \
  | rg 'PRODUCT_BUNDLE_IDENTIFIER|MARKETING_VERSION|CURRENT_PROJECT_VERSION|IPHONEOS_DEPLOYMENT_TARGET|TARGETED_DEVICE_FAMILY'
```

没有出现某字段时继续核对 Info.plist 与最终产物，不能把空输出解释为默认正确。签名团队、证书、描述文件和 Push Notifications 能力需匹配；Debug 使用 development entitlement，Release 使用 production，并与服务端 APNs 环境及 VoIP topic 对齐。

```sh
xcodebuild -project ios-app/StarlineWorkbench.xcodeproj \
  -scheme StarlineWorkbench -configuration Release \
  -destination 'generic/platform=iOS' \
  -archivePath build/StarlineWorkbench.xcarchive archive
```

生成后在实际 App 目录检查签名和打包后的版本。这里的路径是仓库内候选产物，不是用户安装目录：

```sh
codesign --verify --deep --strict build/StarlineWorkbench.xcarchive/Products/Applications/StarlineWorkbench.app
codesign -dv --verbose=4 build/StarlineWorkbench.xcarchive/Products/Applications/StarlineWorkbench.app
plutil -p build/StarlineWorkbench.xcarchive/Products/Applications/StarlineWorkbench.app/Info.plist
```

Xcode Archive、导出、上传回执、处理完成、选择构建、审核提交、审核通过与正式可下载应逐项记录。iOS 的真实账号授权、自动返回、冷启动、取消与记忆保护必须在目标设备完成；历史系统表单测试不能代替完整授权。Apple iPad 登录驳回与商业模式说明仍需形成新的后台闭环，不能引用 Android 成功作为修复证明。

## 服务端、数据库与兼容门禁

| 检查阶段 | 执行内容 | 通过标准 |
| --- | --- | --- |
| 配置 | 按[配置参考](https://document.thestarline.cn/app/configuration-reference.md)核对变量来源、格式和依赖 | 无 fixture 混入；稳定密钥可匹配当前数据；外部能力明确启用条件 |
| 迁移 | 在隔离副本运行对应版本，验证 schema、读写与权限 | Account 001–007 与 PII 迁移有配套备份；聊天构造迁移不破坏旧记录 |
| 切换 | 停旧写入口、按维护窗口启用新实例 | 无双写、无指错持久卷、无新建空库误报健康 |
| 验证 | HTTP、身份、消息、媒体、事件、通话等分层探测 | 合成业务断言与拒绝路径通过，真实依赖另有证据 |
| 观测 | 错误、延迟、重启、磁盘、队列和外部接受状态 | 发现异常能关联阶段，日志不含秘密与用户内容 |

数据库升级没有通用降级脚本。发布前应验证旧客户端对新增字段的容忍、旧服务是否能读取升级后结构、数据保护密钥是否变化。退镜像与退数据是两种动作：退镜像可能遇到 schema 不兼容，退数据库可能丢失恢复点后写入。不能承诺一键无损回滚；按[恢复演练](https://document.thestarline.cn/app/incident-runbooks.md)预先验证并记录边界。

## 下载、渠道与正式回执

下载地址只指向已核验的最终产物。iOS 使用真实公开 App Store 链接；Android 填写最终版本、最低系统、大小、SHA-256 与渠道状态。只有稳定版验收完成后才切 `stable`，预览包需保留其可用范围说明；空地址继续显示准备中。

可以在发布后的授权核验阶段下载公开候选并比较，以下域名与文件名为合成示例：

```sh
set -eu
curl --fail --location --output qa-download.apk https://downloads.example.test/starline-release.apk
shasum -a 256 qa-download.apk
apksigner verify --verbose qa-download.apk
```

同时核对 HTTPS 信任链、重定向、响应文件类型、真实字节和安装升级，不只发 HEAD 请求或检查 URL 格式。备案标识、包名、签名证书和商店材料应属于同一产品；网站号与 App 号分开，星线与星企不混用。小米仍缺版权证明与聊天安全评估材料，草稿保存不能当作提审；正式 APK 与渠道回执仍需取得。

星线智联 0.1.0 只有开发上传历史，未提审、未发布，且保持暂停。上传版本号、开发者工具预览或设置 published 环境开关均不是官方发布回执。watchOS 独立联网版没有成品交付，手机包不能替它填报已上线。

渠道操作前把版本记录与材料逐项对应：创建草稿只记录草稿；上传成功记录包处理状态；选择构建后确认实际提交；审核结果以后台决定为准；公开发布后核对目标地区、可下载版本与安装结果。被拒后保留具体原因和对应设备，再关联修复提交、复验和新回执。截图、客服说明、审核回复和补件上传分别保存，不能用一项替代整套流程。渠道要求变化时核对当前后台字段，不从旧材料复制过期状态。

## 关闭发行记录

发行记录至少包含：最终源码／工作区基线、工具链、版本与签名标识、产物摘要、数据兼容结论、所选设备与网络、通过和失败用例、外部依赖、上传／审核／发布回执、公开下载核验、可回退版本和已知限制。给每项写准确阶段，不用“已经弄好”概括整条链路。后续紧急修复仍须关联相同清单，避免源码、文档、安装包和商店说明分别指向不同版本。
