尧图精选

HarmonyOS AppGallery Connect:上架审核前的隐私权限与版本一致性校验【鸿蒙心迹】

🕒 发布时间:2026/10/1 8:04:38 📁 来源:尧图网络
这篇不是把审核指南重新抄一遍。我做了一个叫 ReleaseGuard 的上架自检小工具把最容易反复出错的几项——版本信息、权限声明、权限申请时机、三方 SDK 隐私披露——尽量变成机器能提前发现的问题。有一次准备提交 HarmonyOS 应用我在 DevEco Studio 里已经把功能跑通测试包也没崩真正到发布阶段却发现“能运行”和“适合提交审核”中间还隔着一层很具体的工程工作。官方的 HarmonyOS 应用提交页面把发布前测试拆得很清楚漏洞、隐私、兼容性、稳定性、性能都需要在提交前检查应用基本信息、素材、隐私保护和审核资质也不是最后点一下按钮就自动完成。对于集成第三方 SDK 的应用官方上架说明还特别强调隐私政策需要逐一说明相关 SDK 收集个人信息的目的、方式和范围否则可能影响审核。这些要求本身并不难理解真正麻烦的是它们散落在代码、配置、依赖和发布后台里。开发者经常是功能改了一处发布信息忘了同步依赖升级了隐私声明没补module.json5里声明了权限就误以为“权限这项已经处理完了”。于是我建了一个小工程ReleaseGuard。它不是官方审核工具也不会替代 AppGallery Connect 的最终审核目标只有一个在我上传 APP 包以前把能自动检查的低级问题先拦下来。本文 Demo 固定使用下面这组数据bundleNamecom.example.releaseguardversionName1.4.2versionCode1040203。第一次执行一共 9 项检查只通过 7 项两个失败项分别是“隐私声明缺少analytics-sdk3.2.1”以及“用户同意前触发 CAMERA 权限申请”。修复之后再次执行结果变成 9/9。这里的analytics-sdk3.2.1是我为了演示流程使用的虚构依赖名不对应某个真实 SDK。一、把“审核退回原因”翻译成工程规则我没有一开始就写脚本而是先把过去最容易出错的发布问题分成两类。第一类是机器很擅长发现的确定性问题比如版本号是否一致、某个依赖是否存在、声明的权限有哪些、隐私披露清单有没有对应条目、release 包是不是用了调试签名。这些规则非常适合放进 CI 或本地脚本。第二类是机器只能辅助、人仍然要判断的问题比如应用业务是否需要某项资质、隐私政策文字是否真正清楚、权限使用目的是否与实际功能匹配、页面是否存在误导性描述。这部分不能因为脚本显示绿色就当成“审核一定通过”。ReleaseGuard 只处理第一类第二类永远留给人工复核和官方最终审核。这个边界很重要否则一个“9/9”很容易制造错误的安全感。我给每条规则定义了同样的结果结构id / title / passed / evidence / messageevidence是关键。检查脚本说“版本一致”还不够它要告诉我读取的是哪个文件、值是什么说“隐私披露缺项”要列出缺的是哪个依赖。这样失败结果才真正能指导修改。二、版本一致性是最适合自动检查的一项HarmonyOS Stage 模型工程里应用级配置通常位于AppScope/app.json5版本名称和版本编码会进入最终应用包。发布时后台填写的信息、你准备对外说明的版本、代码仓里的版本最好在构建之前就对齐。我的 Demo 要求这次发布固定为bundleName com.example.releaseguard versionName 1.4.2 versionCode 1040203只要脚本读出来不是这组值就直接失败不继续生成“审核就绪”结果。这段代码解决什么问题构建前读取 app.json5把包名和版本与发布配置进行硬校验。// scripts/release-check.tsimportfsfromnode:fsimportJSON5fromjson5interfaceReleaseTarget{bundleName:stringversionName:stringversionCode:number}consttarget:ReleaseTarget{bundleName:com.example.releaseguard,versionName:1.4.2,versionCode:1040203}constappConfigJSON5.parse(fs.readFileSync(AppScope/app.json5,utf-8))constactual:ReleaseTarget{bundleName:appConfig.app.bundleName,versionName:appConfig.app.versionName,versionCode:appConfig.app.versionCode}functionassertEqual(name:keyofReleaseTarget):void{if(actual[name]!target[name]){thrownewError([ReleaseCheck]${name}mismatch:expected${target[name]}, actual${actual[name]})}}assertEqual(bundleName)assertEqual(versionName)assertEqual(versionCode)console.info([ReleaseCheck] version consistency: PASS)我没有让脚本去猜“下一个版本应该是多少”。版本策略属于团队规则脚本只负责验证当前这次发布目标。目标值可以来自环境变量、发布配置文件或 CI 参数重点是它必须只有一个可信来源。另外我会在生成 APP 后再做一次包级验证而不是只读源码配置。原因很简单真正上传的是构建产物不是app.json5。源码正确但构建分支、签名配置或产物选错一样可能提交错包。我还会把这组版本信息同步到发布说明草稿里避免出现“包里是 1.4.2运营文案还写 1.4.1”的尴尬。这个问题脚本未必能直接判断但可以让发布配置生成一份release-meta.json应用包校验、CI 构建记录和运营侧都读取同一个版本源。对于多人协作项目这比在群里发一句“这次版本号改成多少”可靠得多。如果项目同时维护测试、灰度和正式渠道我还会额外检查渠道对应的 bundle、签名和构建 profile避免把内部测试产物误当成正式包。版本一致性看起来只是三个字段实际上它是整条发布链路最适合建立“单一事实来源”的地方。三、权限声明和权限申请时机是两件事这是我觉得最容易被混在一起的地方。module.json5的requestPermissions解决的是“应用声明自己需要哪些权限”。真正涉及用户授权的权限还要在业务需要时通过访问控制能力查询状态并发起授权请求。官方 FAQ 也把getSelfPermissionStatus()与requestPermissionsFromUser()作为定位授权状态的关键接口。换成工程语言就是配置文件回答“可能会用什么”运行时代码回答“什么时候真的向用户要”。如果应用一启动就把 CAMERA、麦克风、相册等权限连续弹出来即使配置层面没有语法错误用户体验和隐私合规都很难说合理。更稳妥的方式是把权限申请放到清晰的功能动作后面例如用户点击“扫码”时再申请 CAMERA。ReleaseGuard 的 Demo 里我专门做了一个PermissionGate。只有隐私提示已经完成并且用户主动进入扫码功能时才允许发起相机授权。这段代码解决什么问题避免应用启动时提前申请 CAMERA把授权动作绑定到真实功能触发。// entry/src/main/ets/service/PermissionGate.etsimport{abilityAccessCtrl,common,Permissions}fromkit.AbilityKitexportclassPermissionGate{privateconsentAccepted:booleanfalsesetPrivacyConsent(accepted:boolean):void{this.consentAcceptedaccepted}asyncrequestCameraForScan(context:common.UIAbilityContext):Promiseboolean{if(!this.consentAccepted){console.warn([PermissionGate] CAMERA blocked before consent)returnfalse}constpermission:Permissionsohos.permission.CAMERAconstmanagerabilityAccessCtrl.createAtManager()conststatusmanager.getSelfPermissionStatus(permission)if(statusabilityAccessCtrl.PermissionStatus.GRANTED){returntrue}constresultawaitmanager.requestPermissionsFromUser(context,[permission])returnresult.authResults.length0result.authResults[0]0}}这里的重点不是“必须先放一个同意开关”这种固定模板而是权限要有明确业务上下文。你的产品流程可能和我的 Demo 完全不同但至少应该回答用户刚刚做了什么操作为什么此刻需要这项权限拒绝之后功能如何降级如果这些问题说不清楚脚本即使能检测到requestPermissions也不应该给“权限合规”打绿色勾。四、我把 DevEco Studio 里的检查结果做成可读日志这张图对应第一次执行 ReleaseGuard 的状态。右边模拟器显示 7/9通过项包括版本一致性、签名信息和权限声明失败项有两个隐私声明缺少analytics-sdk3.2.1CAMERA 在用户同意前被触发。底部 HiLog 也打印同样的信息[ReleaseCheck] version1.4.2 code1040203 [Privacy] analytics-sdk3.2.1 disclosure missing [PermissionGate] CAMERA blocked before consent [ReleaseCheck] finish: 7 / 9 passed我很在意“模拟器 UI”和“日志”必须说同一件事。开发工具页显示 7/9日志就不能写 8/9UI 写1040203脚本也必须读取到1040203。发布类问题最怕多个来源互相矛盾因为你最后很难判断应该信谁。所以 ReleaseGuard 的页面本身不重新计算结果它只渲染脚本/检查服务返回的CheckResult[]。五、三方 SDK 披露不能靠人肉记忆官方上架说明已经把这件事说得很明确集成第三方 SDK 时需要在应用隐私政策中逐一明示 SDK 收集个人信息的目的、方式和范围。现实项目里最容易发生的情况是依赖升级了开发者知道隐私文档维护者不知道。我给项目加了一个自定义清单release/privacy-sdk.json。注意这不是 HarmonyOS 官方规定的文件格式只是我自己的工程约定目的是让“代码依赖”和“隐私披露”之间可以被脚本比较。例如{disclosed:[network-core2.4.0,image-cache1.8.3]}而依赖清单里存在analytics-sdk3.2.1那脚本就直接把它列为缺项。这段代码解决什么问题从依赖集合中找出没有进入隐私披露清单的三方包。// scripts/privacy-check.tsimportfsfromnode:fsimportJSON5fromjson5constpkgJSON5.parse(fs.readFileSync(oh-package.json5,utf-8))constprivacyJSON.parse(fs.readFileSync(release/privacy-sdk.json,utf-8))constdependencyNamesObject.keys(pkg.dependencies??{})constdisclosedNames:string[]privacy.disclosed??[]constmissingdependencyNames.filter((name){return!disclosedNames.some((item)item.startsWith(${name}))})if(missing.length0){console.error([Privacy] disclosure missing:${missing.join(, )})process.exitCode1}else{console.info([Privacy] third-party disclosure: PASS)}真实项目里当然不能只比较“包名有没有出现”。还要确认版本、采集信息类型、使用目的、调用场景和供应商说明是否发生变化。这个脚本只负责把“完全忘了披露”这种错误提前抓出来后面的内容核对仍然必须人工做。我甚至建议把“依赖变更”纳入代码评审模板。只要 PR 修改了oh-package.json5或 lock 文件就要求顺手确认隐私披露是否需要更新。这样比临近发布时靠一个人从头翻依赖靠谱得多。六、7 / 9 这个页面的作用是阻止我带病提交手机页里我没有做很复杂的视觉设计核心就是让失败项足够明显。当前结果 7/978%底部“准备提交审核”按钮保持不可用。两个红色标记对应两个完全不同的问题。“隐私披露缺项”是静态工程问题改文档和披露清单“授权时机错误”是运行时业务问题需要改代码流程。把它们都叫“隐私问题”太宽泛真正修复时反而不知道动哪里。我把检查项拆得尽量具体版本一致性签名信息隐私声明权限申请声明权限申请时机三方 SDK 披露包信息发布构建类型调试标记检查。这些项目不是官方审核条目的完整映射只是 ReleaseGuard 的工程检查集合。官方审核规则和资质要求会更新最终仍以 AppGallery Connect 当前页面、审核指南和审核意见为准。七、修完以后我要求 9 / 9 还要有证据我先在隐私声明中补齐 Demo 依赖analytics-sdk3.2.1的说明再把 CAMERA 申请移动到用户完成隐私提示、点击“扫码”功能之后。重新执行检查后ReleaseGuard 才允许显示“审核就绪”。这次结果和第一次形成一一对应versionName1.4.2、versionCode1040203没变隐私披露记录在2026-09-30 11:05补齐CAMERA 授权流程在2026-09-30 11:12调整为按需申请最终检测时间是2026-09-30 11:18:219 项全部通过。我特意在页面里保留“问题修复记录”而不是只显示一个大绿勾。因为发布版本经常要回溯这次为什么改了权限流程为什么隐私政策突然多了一条 SDK如果只有最终结果过两周团队自己都忘了。八、工具脚本最好接在构建前而不是上传后如果 ReleaseGuard 只能靠开发者想起来时手动点一下它很快就会沦为摆设。我更倾向于把确定性检查放到发布构建前。一个简单的顺序是准备 release 参数 → 运行版本一致性检查 → 运行依赖 / 隐私披露检查 → 检查权限声明 → 构建 release APP → 校验产物包信息和签名 → 真机执行权限场景用例 → 人工复核隐私政策、资质、截图和应用信息 → 上传 AppGallery Connect这样做的好处是越便宜的问题越早失败。版本号错了就不要浪费时间跑后面的真机回归三方 SDK 披露缺项也不要等包上传后才发现。官方提交页面同样建议在发布前完成漏洞、隐私、兼容性、稳定性和性能等测试。ReleaseGuard 只是把其中一小部分工程检查左移并不能替代云测试、云调试或正式审核。九、我会为每次提交留一个“证据包”ReleaseGuard 做到后面我又多加了一件很土但特别有用的事每次真正准备提审时把这次检查结果导出成一个小证据包。它不需要很复杂至少包含应用包名、版本名、版本号、构建时间、依赖摘要、权限列表、检查结果和最终 APP 文件的哈希。这么做不是为了给审核平台看而是为了给团队自己留底。发布后的线上问题经常会问“商店里的 1.4.2 到底是哪次构建”如果只剩一个版本号而 CI 当天又跑过好几次很容易对不上。证据包能把“源码提交—构建产物—提交版本”串成一条线。我还会把隐私披露清单的摘要放进去例如本次构建识别到哪些三方依赖、哪些被标记为需要披露、人工复核人是谁。这里并不保存大段隐私政策正文只保留版本和校验结果避免证据包反过来变成维护负担。权限也一样。工具可以把module.json5中声明的权限和测试场景记录下来例如 CAMERA 是在“扫码”按钮触发后申请而不是启动时申请。等以后某个版本又把权限弹窗提前了回看两个证据包就能发现行为变化而不只是凭印象争论“以前是不是也这样”。这个做法还有一个附带收益当审核反馈发生时我可以直接在对应证据包上补一条“审核反馈—修改提交—再次检查”的链路。久而久之团队会积累出真正属于自己业务的发布知识而不是每次都从公开文档重新搜索。十、CI 里的检查必须能阻断错误构建很多团队其实已经有各种检查脚本但最后都变成一排绿色日志因为脚本失败了也不影响构建继续往下跑。我不希望 ReleaseGuard 变成这种“仅供参考”的装饰所以确定性规则失败时会直接返回非零退出码。例如版本号不一致、release 构建仍带调试标记、三方依赖完全没有进入披露清单这些都应该在生成正式产物之前阻断。开发者可以修改规则也可以在特殊情况下走审批后的 override但不能默默忽略。另外CI 里不要把所有检查塞进一个巨大的release-check。我更喜欢拆成version-check、privacy-check、permission-check、package-check最后再汇总。这样某一项失败时日志定位更快规则也更容易由不同负责人维护。真正需要人工判断的项目则明确输出REVIEW_REQUIRED而不是假装PASS。例如行业资质、隐私文案质量、商店截图是否与当前版本一致都应该进入发布工单的人工勾选项。自动化最怕边界不清什么都想判断最后没人再相信它的结果。我甚至会要求 CI 保存每一项检查的版本号。因为审核规则、SDK 和脚本都会变化。同样是“9/9”2026 年 9 月的规则和半年后的规则可能不是同一套。把规则版本一起记录之后回溯才有意义。十一、还有三类问题我不会让脚本自动判“通过”第一类是资质。某些业务面向中国大陆发布时会涉及 ICP、软件著作权或行业资质具体要求会随业务类型和规则更新。脚本最多提醒“这一栏待人工确认”不能根据几个关键词就替你判断是否具备合法资质。第二类是隐私文字质量。脚本能发现“SDK 名字没写”却很难判断你的收集目的描述是否清晰、是否和真实调用一致也难判断某个业务是不是存在过度收集。这里必须由产品、法务和开发一起看实际流程。第三类是页面内容与运营素材。截图、文案、登录流程、会员权益、广告展示、用户生成内容等都会影响审核。它们不是一个JSON5文件能覆盖的。所以我给 ReleaseGuard 的 9/9 定义得非常窄代表这 9 条工程规则都通过不代表应用一定通过审核。十二、上架稳定之后真正省下来的不是一次审核时间我以前会把上架问题看成发布当天的工作版本做完了开始填后台、补截图、检查隐私。现在更倾向于把它当成开发过程的一部分。加一个依赖时就顺手看它会不会影响隐私声明增加一个权限时同时设计申请时机和拒绝后的降级准备版本时版本号从同一个发布配置生成真正要上传时脚本只负责确认团队之前已经做过这些事情而不是临时补课。这也是 ReleaseGuard 这个小工具最有价值的地方。它没有什么复杂算法不过是读几个配置、比几个集合、检查几个状态。但它把“我应该没忘吧”变成了“这里明确还有两项没过”。上架审核很多时候并不是难在规则看不懂而是难在工程变化和发布资料长期保持一致。把能自动化的确定性问题交给脚本把需要判断的部分明确留给人发布流程反而会简单很多。最后留一句我现在每次提审前都会看的话不要把“应用能跑”当成发布完成真正的 release 版本还应该能解释自己的版本、权限、依赖和隐私边界。参考资料HarmonyOS 应用提交与发布https://developer.huawei.com/consumer/cn/app/submit华为应用市场审核与处理规则https://developer.huawei.com/consumer/cn/doc/App/50109上架申请与三方 SDK 隐私说明https://developer.huawei.com/consumer/cn/doc/HMScore-Guides/app-release-0000001569211185权限申请相关 FAQhttps://developer.huawei.com/consumer/cn/doc/doccenter-dev-faq/faqs-access-control-16
上一篇/下一篇内容由系统自动关联 返回资讯列表 →