ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

HarmonyOS 7 ArkTS + Node.js:把权限声明、运行时授权与隐私文案做成提审前一致性扫描【鸿蒙心迹】

HarmonyOS 7 ArkTS + Node.js:把权限声明、运行时授权与隐私文案做成提审前一致性扫描【鸿蒙心迹】 有些上架问题不是“功能坏了”而是工程里的三份事实没有对齐module.json5声明了一套权限ArkTS 实际申请的是另一套隐私文案又写成第三套。页面自己测没有问题到了提审阶段才开始逐项找差异成本会比开发时高很多。我这次没有再做一篇审核规则清单而是写了一个很小的工程工具ReleaseGuard。它不代替 AppGallery 审核也不声称能保证通过它只在提交版本前把项目里几类可以机械检查的内容拉到一起先把明显的不一致找出来。这次固定的运行结果是audit_20261001_02最终状态PASS6 / 6 检查通过Findings 0。一、真正麻烦的不是“有没有权限”而是三处事实会漂移做业务时很常见。最初扫码页需要相机于是在module.json5里加了ohos.permission.CAMERA。后来产品调整流程把扫码放到二级页开发者也把运行时弹窗改成用户点击“扫描小票”时才出现。再后来隐私文案还是旧版本写着“启动应用时需要相机权限”。单独看三处都不一定报错manifest 能编译ArkTS 能正常弹权限框隐私政策也有“相机”两个字。但放到一起场景已经不一致了。华为应用市场当前审核指南要求应用信息和包体完整准确、应用本身可正常运行并符合隐私相关要求。隐私规则里还强调权限使用最小化、清楚说明权限对应功能和场景同时避免在首次启动时频繁请求敏感权限。所以我想做的不是替审核员判断合规而是在代码提交阶段回答几个更具体的问题声明了哪些权限哪些权限在 ArkTS 中真的发起运行时申请隐私映射里有没有对应的用途和触发场景三方依赖有没有进入项目自己的隐私清单审核备注是否准备好当前发布信息是否完整二、先建一份“工程内隐私映射”别把真相只留在 Word 里这段配置解决的问题是给脚本一个可比较的数据源。我没有直接让脚本解析线上隐私政策因为文案格式可能变化也不适合把网络状态带进本地构建。Demo 里维护一个scripts/privacy-map.json它不是官方要求的文件只是项目自己的“机器可读映射”。{permissions:{ohos.permission.CAMERA:{requestAtRuntime:true,purpose:扫描纸质小票并生成识别图片,scene:用户点击扫描小票按钮后申请},ohos.permission.INTERNET:{requestAtRuntime:false,purpose:上传用户确认后的识别结果,scene:用户主动点击同步后使用}},thirdParty:[]}我特意加了requestAtRuntime。因为不是所有 manifest 权限都应该用同一套逻辑判断。如果脚本简单规定“声明的权限必须全部出现在requestPermissionsFromUser()”很快就会制造大量误报。这个文件真正有价值的地方是把“权限名、用途、场景、是否运行时申请”绑定在一起。以后业务改流程时代码评审不只看 ArkTS也能顺手看这一份映射有没有一起改。三、manifest 只保留当前功能需要的声明当前 Demo 用到相机和网络。这段配置解决的是声明侧事实让扫描脚本能拿到“工程准备申请什么”。{ module: { name: entry, type: entry, requestPermissions: [ { name: ohos.permission.CAMERA, reason: $string:camera_reason, usedScene: { abilities: [EntryAbility], when: inuse } }, { name: ohos.permission.INTERNET } ] } }正式项目里不要看到以前用过的权限就一直留着。权限越多不等于能力越完整。审核规则本身就强调最小化原则。如果一个旧模块已经下线声明却没有删隐私文案也被迫继续解释一个实际上不再存在的场景后续维护反而更困难。reason、usedScene是否需要、怎么配置要按具体权限类型和当前 HarmonyOS 权限文档处理不要把一个权限的写法机械复制到另一个权限。四、运行时授权只放在真正发生功能动作的位置我这次把相机授权从aboutToAppear()移到了“扫描小票”按钮动作里。这段 ArkTS 解决的问题是用户没有使用扫码功能时不提前打断流程。import{abilityAccessCtrl,common,PermissionRequestResult}fromkit.AbilityKit;asyncfunctionrequestCameraWhenNeeded(context:common.UIAbilityContext):Promiseboolean{constatManagerabilityAccessCtrl.createAtManager();try{constresult:PermissionRequestResultawaitatManager.requestPermissionsFromUser(context,[ohos.permission.CAMERA]);returnresult.authResults[0]abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;}catch(error){console.error(request camera failed:${JSON.stringify(error)});returnfalse;}}调用方再决定后续动作privateasyncstartReceiptScan():Promisevoid{constcontextthis.getUIContext().getHostContext()ascommon.UIAbilityContext;constgrantedawaitrequestCameraWhenNeeded(context);if(!granted){this.scanStatePERMISSION_DENIED;return;}this.scanStateCAMERA_READY;awaitthis.openScanner();}这个调整以后权限状态和业务状态就分开了。用户拒绝相机不应该导致整个应用不可用它只影响“扫码小票”这一项功能。后续如果系统策略要求引导用户到设置页重新授权也应该在用户再次触发相应功能时处理而不是在首页循环弹窗。官方当前文档里仍然使用abilityAccessCtrl.createAtManager()和requestPermissionsFromUser()这条链路做用户授权请求。工程里需要额外关注的是拒绝以后怎么降级以及不要把授权弹窗当成业务成功结果。五、扫描脚本只做“能证明的事”接下来是这篇里真正的小工具。我没有让脚本判断“你的隐私政策是否合法”这种结论它做不了。它只比较本地工程里可以确认的集合。这段 Node.js 脚本解决三个最直接的问题manifest 声明了什么ArkTS 代码里请求了什么privacy-map.json覆盖了什么。importfsfromnode:fs;importpathfromnode:path;importJSON5fromjson5;importfgfromfast-glob;constmoduleJsonJSON5.parse(fs.readFileSync(entry/src/main/module.json5,utf8));constprivacyMapJSON.parse(fs.readFileSync(scripts/privacy-map.json,utf8));constdeclarednewSet((moduleJson.module.requestPermissions??[]).map(itemitem.name));constetsFilesawaitfg([entry/src/main/ets/**/*.ets]);constsourceetsFiles.map(filefs.readFileSync(file,utf8)).join(\n);construntimeRequestednewSet([...source.matchAll(/ohos\.permission\.[A-Z0-9_]/g)].map(matchmatch[0]));constmappednewSet(Object.keys(privacyMap.permissions??{}));constfindings[];for(constpermissionofdeclared){if(!mapped.has(permission)){findings.push(No privacy mapping:${permission});}}for(const[permission,meta]ofObject.entries(privacyMap.permissions)){if(meta.requestAtRuntime!runtimeRequested.has(permission)){findings.push(Runtime request missing:${permission});}if(!declared.has(permission)){findings.push(Mapped but not declared:${permission});}}console.log({declared:declared.size,runtimeRequested:runtimeRequested.size,mapped:mapped.size,findings});这里的正则故意很保守。它适合抓 Demo 里直接写出的权限常量不适合覆盖所有复杂封装。例如权限名来自常量模块、代码生成、字符串拼接时这种扫描会漏掉。所以正式项目更适合把权限常量集中管理或者在 AST 层做分析。我的原则是脚本宁可明确自己的边界也不要输出一个看起来很权威的“100% 合规”。六、我把最终检查拆成 6 项而不是一个大 PASSReleaseGuard页面最后展示六项Permission declarationRuntime requestPrivacy copyThird-party SDKReview notesRelease package前三项是权限与隐私的一致性。第四项检查oh-package.json5里的三方依赖是否在项目维护的thirdParty清单里有记录。它不判断某个 SDK 一定收集什么信息而是提醒“新增依赖以后隐私评估别漏掉”。官方审核相关说明也明确提到集成第三方 SDK 时隐私政策需要准确说明相关个人信息处理情况。具体内容仍然要以对应 SDK 的当前隐私声明和实际使用功能为准。第五项检查审核备注文件是否存在。某些功能依赖账号、硬件、特殊环境时官方审核指南要求提供有效测试账号以及必要的审核资源。脚本能做的只是提醒文件为空不能替你生成真实测试账号。第六项检查 bundleName、版本名、版本号和当前 release 配置是否都能读到。它同样不证明包一定能上架只是避免“代码是新版本提交信息还是上一个版本”这种低级错误。这张 DevEco 图里我特意把代码、模拟器和 HiLog 放在一起。底部日志固定为Audit: audit_20261001_02 Declared permissions: 2 Runtime requests: 1 Privacy mappings: 2 Checks: 6/6 Findings: 0 Result: PASS这里的Runtime requests: 1和Declared permissions: 2不矛盾因为INTERNET在当前映射里不走运行时用户授权。如果扫描器不理解这种差异最后只会逼着开发者为了“让脚本变绿”写错误代码。七、PASS 不是“审核一定通过”而是当前工程没有发现这六类差异手机端我最终只保留一个很克制的结果页。audit_20261001_02在 2026-10-01 10:24 完成状态PASS6 / 6Findings 为 0。我在页面里没有写“可以保证上架”而是写“当前版本已通过全部检查项可以进行提审正式提交前再次确认版本号、证书和发布信息”。这个措辞很重要。因为 AppGallery 审核覆盖的内容远不止本文六项。应用稳定性、内容、资质、账号、隐私政策全文、功能真实性、地区规则等都可能影响结果。一个本地脚本没有资格替平台做最终判断。它的价值只是在开发团队内部建立一道低成本门槛能机器比对的内容不要每次都靠人肉记忆。八、真正省时间的是让变更在提交前暴露以前我遇到这类问题往往是打包以后才开始核对。manifest 打开一遍代码搜一遍隐私政策再找一遍最后还要问产品“这个功能现在是不是还在用”。工具化以后我更希望它进入正常开发链路例如{scripts:{audit:privacy:node scripts/privacy-audit.mjs,release:precheck:npm run audit:privacy}}如果后续接 CI也只需要让脚本发现 findings 时返回非 0 状态码就能阻止一个明显不一致的版本直接进入发布流程。这里仍然要保留人工复核。因为“用途是不是描述准确”“某个 SDK 在当前配置下究竟处理哪些信息”“权限申请时机是否符合真实用户场景”这些都不能靠字符串集合完成。我更愿意把 ReleaseGuard 看成一个工程校对员而不是审核裁判。九、这次工具最终留下的是一张一致性关系图写完以后我把整件事归纳成四个箭头Manifest 声明 → ArkTS 实际调用 → 隐私映射 → 提审信息。四处变化应该尽量同步。新增功能时不只是“加权限”删除功能时也不只是“删页面”。权限声明、运行时申请、隐私说明、三方依赖说明、审核备注都可能需要跟着变。真正容易出问题的是代码改完了另外三处还停在上一个版本。所以这个小工具最有价值的不是 6 个绿色勾而是把一个原本依赖经验的检查动作变成每次发布都可以重复执行的流程。规则会继续更新平台能力也会变化。脚本里的检查项应该跟着项目和最新官方要求维护而不是写完一次就永久不动。至少下一次提审前我不用再凭记忆问一句“相机权限的文案是不是还没改”运行一次release:precheck先把工程里能确定的差异找出来再把时间留给真正需要人工判断的部分。参考资料AppGallery Review Guidelineshttps://developer.huawei.com/consumer/en/doc/50104-overviewAppGallery User Privacy Review Guidelineshttps://developer.huawei.com/consumer/fr/doc/app/50104-07常见个人信息保护问题https://developer.huawei.com/consumer/jp/doc/app/FAQ-faq-09HarmonyOS Ads Kit 当前权限申请示例https://developer.huawei.com/consumer/cn/doc/HarmonyOS-Guides/ads-publisher-service-banner
返回列表