前四篇做的事情都围绕“当前这个 1.3.0 包能不能进入发布流程”。

01 看包名、版本号和 release 签名;02 看权限、隐私与三方 SDK;03 看商店文案和素材;04 再回到构建后包体,检查 deviceTypes、Profile 权限子集、HAP 签名和 packageType。

做到这里,单个候选包已经很干净了。

第五篇开始换一个视角:发布不是只判断“现在这个包对不对”,还要判断“它相对上一正式版本发生了什么变化”。

AppGallery Connect 当前提供 Version History,可以查看历史版本的包信息、新功能和审核详情;分阶段发布则面向版本更新场景,可以先按一定比例向用户分发,再逐步扩大范围,并支持暂停、恢复和调整。ReleaseGuard 05 就围绕这两条能力,把版本差异、签名身份、权限变化和灰度计划放在一张“升级预检”里。

本轮统一数据:

taskId:
release_20261002_05

上一正式版本:
1.2.9
10290

候选版本:
1.3.0
10300

版本码增量:
+10

上一版包体:
16.9MB

当前包体:
18.4MB

包体增量:
+1.5MB
+8.9%

previousSigningIdentity:
release_cert_sha256_6a8f3c1d

currentSigningIdentity:
release_cert_sha256_6a8f3c1d

signingContinuity:
true

previousDeviceTypes:
phone / tablet

currentDeviceTypes:
phone / tablet

addedPermission:
ohos.permission.READ_IMAGEVIDEO

permissionDelta:
+1

privacyReviewState:
REVIEWED

listingRevision:
listing_130_r3

phasedReleaseEligible:
true

phasePlan:
5% → 20% → 50% → 100%

checks:
11 / 11

blockers:
0

status:
VERSION_READY

一、第五篇不再扫描“当前值”,而是生成版本差异

如果只看当前包:

versionCode=10300

很难判断它是否真的比上一版新。

所以 05 的输入变成两个 Package Report:

PackageReport_1.2.9.json
PackageReport_1.3.0.json

Version History 也会被同步成 ReleaseGuard 的历史快照,用来和当前候选版本对照。

版本差异模型:

export interface VersionSnapshot {
  versionName: string
  versionCode: number

  artifactSizeMb: number

  signingIdentity: string

  deviceTypes: string[]
  permissions: string[]

  listingRevision: string
}

export interface VersionDiff {
  versionCodeDelta: number

  artifactSizeDeltaMb: number
  artifactSizeDeltaPercent: number

  signingContinuity: boolean

  addedPermissions: string[]
  removedPermissions: string[]

  addedDevices: string[]
  removedDevices: string[]
}

这一篇不是重新解析 .app。

04 已经完成包体报告,05 只消费稳定输出。

二、版本号递增是第一条硬门槛

当前:

1.2.9 / 10290
→
1.3.0 / 10300

ReleaseGuard 只把 versionCode 当作机器比较依据:

export class VersionHistoryAudit {
  compare(
    previous: VersionSnapshot,
    current: VersionSnapshot
  ): CheckItem {
    const passed =
      current.versionCode >
      previous.versionCode

    return {
      key:
        'VERSION_CODE_INCREMENT',
      passed,
      message:
        `${current.versionCode} > ${previous.versionCode}`
    }
  }
}

versionName 仍然保留给人阅读。

这样可以避免:

1.10
1.9

这类字符串比较误判。

三、签名连续性先做“身份一致”检查,不替代官方证书校验

05 最重要的一条变化是:

上一版签名身份
=
当前候选签名身份

当前:

release_cert_sha256_6a8f3c1d

两边一致。

ReleaseGuard 的 signingIdentity 来自构建阶段证书指纹摘要,不在 ArkTS 里重新生成私钥或签名。

export class SigningContinuityAudit {
  check(
    previous: VersionSnapshot,
    current: VersionSnapshot
  ): CheckItem {
    const passed =
      previous.signingIdentity ===
      current.signingIdentity

    return {
      key:
        'SIGNING_CONTINUITY',
      passed,
      message:
        passed
          ? current.signingIdentity
          : 'signing identity changed'
    }
  }
}

这里要把边界说清楚。

这个检查是 ReleaseGuard 的发布连续性门禁,不等于“本地工具已经替 AppGallery Connect 完成全部签名校验”。真正 release certificate、Profile 和包签名有效性仍然以当前官方发布与包解析规则为准。

四、签名身份变化要直接升级为 BLOCKER

包体大小变化可以是正常变化,签名身份变化不能轻描淡写。

如果:

previous:
release_cert_sha256_6a8f3c1d

current:
release_cert_sha256_9b22aa90

ReleaseGuard 不会给:

WARNING

而是:

SIGNING_IDENTITY_CHANGED
BLOCKER

这条规则对版本更新尤其重要。

当前 AppGallery Connect 的证书与签名配置文档也明确区分 debug 与 release 证书;发布阶段应该使用正确的 release 身份。

五、包体从 16.9MB 到 18.4MB,合法不代表不用解释

本轮:

+1.5MB
+8.9%

没有触发 Blocker。

但 ReleaseGuard 会把包体变化放进 VersionDiff。

export class ArtifactDeltaAudit {
  calculate(
    previousMb: number,
    currentMb: number
  ): {
    deltaMb: number
    percent: number
  } {
    const delta =
      currentMb -
      previousMb

    return {
      deltaMb:
        Number(
          delta.toFixed(1)
        ),

      percent:
        Number(
          (
            delta /
            previousMb *
            100
          ).toFixed(1)
        )
    }
  }
}

8.9% 只作为趋势信息。

如果下一版突然:

18.4 → 31.7MB

即使仍在平台允许范围内,也应该先确认:

是不是新增三方库
资源重复
调试文件误打包
多语言资源扩张

六、权限变化不能只显示“当前有 3 个”

上一版:

2 permissions

当前:

3 permissions

新增:

ohos.permission.READ_IMAGEVIDEO

这条变化必须关联到 02 的隐私审核结果。

当前:

privacyReviewState=REVIEWED

所以版本升级可以继续。

如果新增权限,但 02 的 Privacy Report 还没重新确认:

PERMISSION_CHANGE_NOT_REVIEWED

ReleaseGuard 直接阻断。

这就把 02 和 05 连起来了。

七、设备支持删减比新增更值得警惕

本轮:

previous:
phone / tablet

current:
phone / tablet

没有变化。

如果候选版本突然变成:

phone

ReleaseGuard 会标记:

REMOVED_DEVICE_TYPE=tablet

这种变化不一定绝对不能发布,但一定要人工确认。

因为 04 已经证明当前 .app 支持范围是发布计划的一部分,05 再比较历史后,就能发现“版本升级误删设备支持”。

八、Listing Revision 也要进入版本对比

当前:

listing_130_r3

意味着 1.3.0 的商店素材已经走到第 3 版批准快照。

05 不关心截图具体长什么样,只确认:

候选版本
已经绑定一个最新 Listing Report

如果:

version=1.3.0
listing revision 仍属于 1.2.9

就不允许 VERSION_READY。

这是 03 和 05 的连续关系。

九、分阶段发布只在版本更新阶段启用

当前官方分阶段发布说明明确:

用于版本更新
不适用于应用首次发布

并支持设置分发比例、逐步扩大用户范围,以及暂停、恢复和调整发布过程。

ReleaseGuard 因此先判断:

phasedReleaseEligible=true

因为当前是:

1.2.9 → 1.3.0

版本更新,不是首次上架。

十、5% → 20% → 50% → 100% 是项目策略,不是官方固定比例

本轮团队计划:

5%
→
20%
→
50%
→
100%

这组比例属于 ReleaseGuard 的发布策略。

AppGallery Connect 的能力是:

支持按比例分阶段发布

并允许逐步扩大。

平台并没有规定必须使用上面这四个百分比。

项目配置:

export interface PhasedReleasePlan {
  eligible: boolean

  phases: number[]

  observationHours:
    number[]
}

export const plan:
  PhasedReleasePlan = {
    eligible: true,

    phases:
      [5, 20, 50, 100],

    observationHours:
      [24, 24, 24, 0]
  }

每一阶段至少观察 24 小时是 ReleaseGuard 当前团队策略,不是平台规则。

十一、灰度计划还要绑定“暂停条件”

如果只配置比例,没有暂停阈值,灰度就只是慢一点的全量发布。

当前计划还保存:

crash rate threshold
ANR / freeze threshold
review feedback threshold
business metric guard

真正数据可以来自 APMS、运营分析和团队自己的业务监控。

05 不把这些阈值写死成系统标准,只要求:

每个阶段有可执行的 pause condition

否则:

PHASE_PLAN_INCOMPLETE

十二、DevEco 图里最重要的是“版本差异不是当前值”

开发图:

HiLog:

taskId=
release_20261002_05

version:
1.2.9(10290)
→
1.3.0(10300)

signing:
release_cert_sha256_6a8f3c1d
→
release_cert_sha256_6a8f3c1d

continuity=
true

artifact:
16.9MB
→
18.4MB

delta:
+1.5MB
+8.9%

permissionAdded:
READ_IMAGEVIDEO

privacyReview:
REVIEWED

phasePlan:
5,20,50,100

checks:
11/11

blockers:
0

status:
VERSION_READY

这种“前后版本同时可见”的报告,才真正适合升级前检查。

十三、运行图把风险变化集中到一屏

最终运行图:

页面不再重复 01~04 的每一项明细。

只展示版本更新最关键的变化:

版本号增长

签名身份连续

包体增量

权限新增

隐私已复核

分阶段发布计划

最终:

VERSION_READY

它表达的是:

当前候选版本相对上一正式版本的变化已经被解释,没有发现阻断升级的问题。

十四、Version History 不是简单“上一版版本号查询”

AppGallery Connect 当前 Version History 可以查看历史版本的包信息、新功能和审核详情。

ReleaseGuard 最终会把历史版本快照缓存到内部报告里:

version
package
release review result
publishedAt

下一次升级时可以直接作为上一基线。

如果历史版本还在审核中,也不能把它随意当成“上一正式版本”。

版本基线要明确区分:

已发布
审核中
灰度中
已回滚

十五、签名身份检查还要防“配置名一样,实际证书变了”

不能只比较:

signingConfig:
release_prod_202610

因为配置名可能没改,底层证书文件已经换了。

所以 05 真正比较的是:

certificate fingerprint

配置名只是辅助信息。

这和 01 里“release_ 开头只是团队命名规则”保持一致。

十六、灰度发布也必须有退出路径

当前 AppGallery Connect 分阶段发布支持暂停、恢复和更新。

团队侧因此要求:

每个阶段都能暂停

异常版本有明确处置人

继续扩量必须有人确认

全量前再跑一次 release gate

这几条属于流程治理。

ReleaseGuard 不直接替人做最终发布决策。

十七、11 项版本检查怎么组成

本轮:

1 versionCode 递增

2 versionName 更新

3 signing identity 连续

4 deviceTypes 未被意外删除

5 permission delta 已识别

6 新增权限已通过隐私复核

7 包体增量在团队预警范围

8 Listing Revision 属于候选版本

9 Package Report 属于候选 artifact

10 分阶段发布资格成立

11 分阶段发布计划完整

最终:

11 / 11
blockers=0

十八、05 最后固定八组故障注入

正常链以外,我会故意制造:

1 versionCode 没递增

2 签名 fingerprint 改变

3 tablet 支持被删除

4 新增权限但 Privacy Report 未复核

5 Listing Revision 指向旧版本

6 Package Report hash 与 candidate artifact 不一致

7 首次发布却启用 phased release

8 灰度计划没有 pause condition

每一种必须得到不同风险码。

工具只有能抓住这些“升级特有问题”,才算真正从单包预检升级成版本治理工具。

十九、下一篇会把前五篇收成一个 CI Release Gate

01~05 已经分别有:

Package Preflight
Privacy Audit
Listing Audit
Package Report
Version Audit

06 不再新增业务检查。

最后只做:

把五份报告绑定同一个 releaseContextId

生成 Evidence Pack

让 CI 在进入上传步骤前自动判断

到那一步,ReleaseGuard 才真正从“几个检查页面”变成发布门禁。

二十、版本历史对比还要区分“上一正式版”和“上一候选版”

真正跑发布流水线时,历史里可能同时出现:

1.2.9
已全量发布

1.3.0-rc1
内部候选

1.3.0
当前候选

如果 ReleaseGuard 只是取“时间上最近的一条”,很容易把 rc1 当成上一正式版本。

所以历史基线必须带发布状态:

FULL_RELEASED
PHASED
UNDER_REVIEW
ROLLED_BACK
INTERNAL_ONLY

05 只把:

FULL_RELEASED

作为版本升级的主比较基线。

分阶段发布中的版本可以作为风险参考,但不替代“上一正式版”身份。

这也是为什么 Version History 快照不能只保存:

versionName
versionCode

还要保存:

releaseState
publishedAt
reviewState

否则后续 rollback、open testing、phased release 一多,比较基线就会越来越混乱。

二十一、版本回滚以后,签名与版本比较也不能回到旧逻辑

假设:

1.2.9
→ 1.3.0
→ 回滚到 1.2.9

下一次再发 1.3.1,团队很容易误以为“当前线上是 1.2.9,所以只和 1.2.9 比”。

ReleaseGuard 会保留:

lastFullRelease
latestAcceptedSigningIdentity
latestVersionCodeEverReleased

三个维度。

即使线上展示版本发生回滚,也不会把已经使用过的签名身份、版本历史和证据记录一起“倒退”。

这样版本治理不会因为一次回滚失去历史连续性。

二十二、权限新增不仅要检查隐私,也要看 Profile 是否同步

05 当前新增:

READ_IMAGEVIDEO

02 已经确认隐私披露。

04 还确认:

package permissions
⊆
release Profile permissions

所以版本对比里,新增权限需要同时满足两条证据:

Privacy Report reviewed

Package Report permissionSubset=true

缺一不可。

如果隐私已写,但 release Profile 还没更新:

PERMISSION_PROFILE_NOT_READY

仍然阻断。

这样 02、04、05 三篇的结果真正连在一起,不会出现“每篇都绿,组合起来却不能发”。

二十三、签名连续性报告最好保存“来源证据”

最终只展示:

release_cert_sha256_6a8f3c1d

对 CI 足够,但人工排查还需要知道它从哪里来。

所以 Evidence 里会同时保存:

certificate file fingerprint
profile identity
signingConfig
build task id
artifact hash

如果某次签名身份变化,可以快速判断:

是证书换了
Profile 换了
配置指错了
还是产物根本不是同一流水线

这种“来源证据”比单纯的 true/false 更有发布价值。

二十四、灰度发布计划也需要和版本风险等级联动

当前 1.3.0 的变化包括:

新增 1 个权限
包体 +8.9%
设备范围不变
签名不变

ReleaseGuard 可以给出一个团队内部风险级别:

LOW
MEDIUM
HIGH

本轮因为新增权限,所以不会直接判 LOW,而是:

MEDIUM

于是默认采用:

5 → 20 → 50 → 100

如果只是文案修复、无权限变化、无包体大幅增加,团队可能选择更快节奏。

这仍然属于项目发布策略,不是 AppGallery Connect 的平台规则。

工具只负责把变化翻译成可执行的发布建议。

二十五、每个灰度阶段都要绑定观察证据

“观察 24 小时”如果没有指标,只是等时间。

所以每一阶段还绑定:

APMS 稳定性
崩溃 / 冻屏趋势
关键接口错误率
用户反馈
核心业务完成率

真正扩量前必须有一个:

phaseEvidenceId

记录为什么从 5% 升到 20%。

这样分阶段发布不是“凭感觉点下一步”,而是有依据地扩大用户范围。

二十六、05 的最终版本报告应该回答五个问题

发布负责人看到 Version Audit,应该在一分钟内回答:

这个版本真的比上一版新吗

签名身份连续吗

权限与设备发生了什么变化

商店素材和隐私是否已经同步

分阶段发布是否有明确计划

如果报告只能告诉你:

11/11

却回答不了这五个问题,仍然不够。

所以手机图里才刻意把:

版本
签名
权限
隐私
分阶段计划

放在一起。

VERSION_READY 的真正价值不是“更多绿勾”,而是让版本变化已经被完整解释。

二十七、VERSION_READY 还要和候选包状态绑定

最后再补一条容易被忽视的规则:VERSION_READY 不是永久状态。

只要候选包重新构建、签名身份改变、权限集合变化,或者 Listing Revision 被更新,这个状态就必须失效并重新跑 05。ReleaseGuard 会把版本报告和当前 artifactHash、releaseContextId 绑定,任何输入发生变化都转成 VERSION_AUDIT_STALE。

这样发布负责人不会拿着半小时前已经过期的 11/11 报告继续灰度。版本治理真正可靠的前提,是“检查结果只对当时那份候选版本有效”,而不是一次通过以后长期绿灯。

参考资料

  • AppGallery Connect:Viewing the Version History
    https://developer.huawei.com/consumer/fr/doc/app/agc-help-maintain-version-history-0000002236334582
  • AppGallery Connect:Phased Release
    https://developer.huawei.com/consumer/cn/agconnect/phased-release
  • AppGallery Connect:Configuring the App Signing Certificate Fingerprint
    https://developer.huawei.com/consumer/fr/doc/app/agc-help-signature-info-0000001628566748
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐