
審核被打回時(shí)真正費(fèi)時(shí)間的往往不是改一行配置而是確認(rèn)代碼、權(quán)限、SDK、隱私政策和后臺(tái)聲明到底哪一處沒有對(duì)齊。一、審核意見只有一句排查卻橫跨四個(gè)地方這次遇到的審核意見并不復(fù)雜“應(yīng)用實(shí)際申請(qǐng)的權(quán)限與隱私政策說明不一致請(qǐng)核對(duì)后重新提交?!眻F(tuán)隊(duì)第一反應(yīng)是檢查module.json5確認(rèn)相機(jī)和相冊(cè)權(quán)限都寫了用途說明。配置看起來沒問題隱私政策里也出現(xiàn)了“圖片處理”幾個(gè)字于是大家懷疑是審核誤判。真正把代碼、構(gòu)建產(chǎn)物和隱私政策放在一起看問題才顯出來項(xiàng)目曾經(jīng)接入一個(gè)圖片統(tǒng)計(jì) SDK后來業(yè)務(wù)入口刪除了依賴包仍然保留隱私政策列出了相機(jī)和相冊(cè)卻沒有逐項(xiàng)說明這個(gè) SDK 可能處理的設(shè)備信息測(cè)試包里還存在一條只在調(diào)試頁面觸發(fā)的位置權(quán)限請(qǐng)求。每個(gè)單點(diǎn)看起來都“差不多正確”組合起來卻無法形成一致的證據(jù)鏈。我沒有繼續(xù)人工翻文件而是給項(xiàng)目補(bǔ)了一個(gè)PrivacyGate檢查腳本。它不替代人工合規(guī)判斷也不保證通過審核它只解決一個(gè)工程問題在打包前把聲明權(quán)限、代碼調(diào)用、三方依賴、隱私政策關(guān)鍵詞和上架后臺(tái)清單整理成同一份報(bào)告讓不一致盡早暴露。Demo 工程叫QuietGallery構(gòu)建版本為2.3.0(20300)檢查批次為PG-20260930-04。掃描結(jié)果一共發(fā)現(xiàn) 3 個(gè)阻斷項(xiàng)未聲明的 SDK 數(shù)據(jù)類型、無業(yè)務(wù)入口的位置權(quán)限、隱私政策缺少撤回授權(quán)路徑。二、上架審核不是最后一步而是構(gòu)建鏈的一部分官方上架指引明確提醒HarmonyOS 應(yīng)用發(fā)布前需要完成漏洞、隱私、兼容性、穩(wěn)定性和性能等測(cè)試如果集成第三方 SDK還要在隱私政策中逐一明示其收集個(gè)人信息的目的、方式和范圍。換句話說隱私文本不是運(yùn)營(yíng)同事在后臺(tái)補(bǔ)的一段介紹它應(yīng)當(dāng)與代碼和依賴一起被版本管理。我把審核相關(guān)信息分成五份清單declared-permissions.json模塊清單中聲明的權(quán)限與用途runtime-requests.json代碼中可能觸發(fā)的權(quán)限請(qǐng)求third-party-sdks.jsonOHPM 與本地 HAR/HSP 依賴privacy-policy.json隱私政策中結(jié)構(gòu)化的數(shù)據(jù)類型和處理目的release-profile.json版本號(hào)、包名、上架區(qū)域與后臺(tái)配置快照。這五份數(shù)據(jù)不是讓開發(fā)者維護(hù)五遍而是由掃描器從不同來源提取后生成。人工只維護(hù)一份規(guī)則映射例如“相機(jī)權(quán)限對(duì)應(yīng)拍攝頭像功能觸發(fā)點(diǎn)在 AvatarEditor隱私政策條目為 camera_capture”。三、先從權(quán)限清單里找到靜態(tài)事實(shí)第一步掃描module.json5中的requestPermissions。這里只能證明應(yīng)用聲明了什么不能證明運(yùn)行時(shí)一定會(huì)請(qǐng)求也不能證明說明文案符合實(shí)際業(yè)務(wù)。掃描器把權(quán)限名稱、reason 資源、使用場(chǎng)景和模塊名稱統(tǒng)一輸出作為后續(xù)比對(duì)的基線。**這段代碼解決什么問題**解析模塊權(quán)限配置識(shí)別重復(fù)聲明、缺少用途資源和沒有配置使用場(chǎng)景的權(quán)限。// 文件tools/privacy-gate/src/permission-scanner.ts// 用途讀取 module.json5 并輸出標(biāo)準(zhǔn)權(quán)限記錄exportinterfacePermissionRecord{moduleName:stringname:stringreason:stringabilities:string[]}exportfunctionscanPermissions(moduleConfig:Recordstring,Object):PermissionRecord[]{constmoduleInfomoduleConfig[module]asRecordstring,ObjectconstmoduleNamemoduleInfo[name]asstringconstrequestsmoduleInfo[requestPermissions]asArrayRecordstring,Object??[]returnrequests.map((item:Recordstring,Object){constusedSceneitem[usedScene]asRecordstring,Object|undefinedreturn{moduleName,name:item[name]asstring,reason:item[reason]asstring??,abilities:usedScene?.[abilities]asstring[]??[]}})}exportfunctionvalidatePermission(record:PermissionRecord):string[]{consterrors:string[][]if(record.reason.length0){errors.push(PERMISSION_REASON_MISSING:${record.name})}if(record.abilities.length0){errors.push(PERMISSION_SCENE_EMPTY:${record.name})}returnerrors}實(shí)際項(xiàng)目中要注意 JSON5 不是嚴(yán)格 JSON不能簡(jiǎn)單刪除注釋后直接解析。腳本應(yīng)使用與構(gòu)建環(huán)境兼容的解析器并且同時(shí)掃描主模塊和動(dòng)態(tài)特性模塊。只看entry目錄會(huì)漏掉其他模塊帶入的權(quán)限。四、代碼里出現(xiàn)權(quán)限名不等于一定會(huì)申請(qǐng)第二步是掃描運(yùn)行時(shí)請(qǐng)求。最粗糙的方式是全文搜索權(quán)限字符串但它會(huì)把注釋、測(cè)試代碼和常量定義都算進(jìn)去。PrivacyGate采用兩級(jí)策略先通過文本搜索找到候選文件再識(shí)別權(quán)限請(qǐng)求 API 的調(diào)用上下文記錄調(diào)用方法、頁面和構(gòu)建條件。這里不追求做一個(gè)完整 ArkTS 編譯器而是找出“值得人工確認(rèn)”的位置。腳本報(bào)告中把結(jié)果分成三類生產(chǎn)路徑、調(diào)試路徑和無法判斷。無法判斷不等于違規(guī)只是提醒發(fā)布前補(bǔ)一次人工確認(rèn)。**這段代碼解決什么問題**把代碼中的權(quán)限請(qǐng)求映射到業(yè)務(wù)入口并識(shí)別沒有對(duì)應(yīng)配置聲明的調(diào)用。// 文件tools/privacy-gate/src/runtime-request-scanner.ts// 用途提取 requestPermissionsFromUser 調(diào)用附近的權(quán)限常量exportinterfaceRuntimeRequest{file:stringline:numberpermission:stringbuildScope:production|debug|unknown}exportfunctionfindRuntimeRequests(file:string,source:string):RuntimeRequest[]{constrowssource.split(\n)constresult:RuntimeRequest[][]rows.forEach((row:string,index:number){if(!row.includes(requestPermissionsFromUser)){return}constcontextrows.slice(Math.max(0,index-8),index8).join(\n)constmatchescontext.match(/ohos\.permission\.[A-Z_]/g)??[]constscopecontext.includes(BuildProfile.DEBUG)?debug:unknownmatches.forEach((permission:string){result.push({file,line:index1,permission,buildScope:scope})})})returnresult}掃描結(jié)果發(fā)現(xiàn)LocationDebugPage.ets:86請(qǐng)求了位置權(quán)限。頁面已經(jīng)沒有菜單入口但仍會(huì)被打包進(jìn)生產(chǎn)模塊。我的處理不是在隱私政策里補(bǔ)一條位置說明而是把調(diào)試頁面從 release 構(gòu)建中排除同時(shí)刪除對(duì)應(yīng)權(quán)限。合規(guī)不是“代碼申請(qǐng)什么就都寫進(jìn)政策”沒有實(shí)際業(yè)務(wù)需要的權(quán)限應(yīng)該從產(chǎn)物里拿掉。五、三方 SDK 是最容易漏掉的一層應(yīng)用自身沒有讀取設(shè)備信息不代表依賴庫不會(huì)處理。依賴掃描不能只看包名還要記錄版本、來源、能力說明、數(shù)據(jù)類型、目的、方式和政策鏈接。升級(jí)依賴版本后這些字段也要重新確認(rèn)。PrivacyGate會(huì)讀取oh-package-lock.json5和約定目錄中的sdk-privacy.json。如果某個(gè)生產(chǎn)依賴沒有隱私說明文件報(bào)告直接標(biāo)成阻斷項(xiàng)開發(fā)依賴則標(biāo)成提醒項(xiàng)并檢查它是否意外進(jìn)入 release 產(chǎn)物。**這段代碼解決什么問題**將依賴鎖文件與項(xiàng)目維護(hù)的 SDK 隱私清單比對(duì)找到“代碼里有、政策里沒有”的三方組件。// 文件tools/privacy-gate/src/sdk-policy-checker.ts// 用途核對(duì)三方依賴版本與隱私政策條目exportinterfaceSdkPrivacyItem{packageName:stringversion:stringdataTypes:string[]purpose:stringpolicyKey:string}exportfunctioncheckSdkDisclosure(releasePackages:Mapstring,string,disclosures:SdkPrivacyItem[]):string[]{consterrors:string[][]releasePackages.forEach((version:string,packageName:string){constitemdisclosures.find((value:SdkPrivacyItem)value.packageNamepackageNamevalue.versionversion)if(!item){errors.push(SDK_DISCLOSURE_MISSING:${packageName}${version})return}if(item.dataTypes.length0||item.purpose.length0){errors.push(SDK_DISCLOSURE_INCOMPLETE:${packageName}${version})}})returnerrors}這次被找出來的是quiet/analytics1.6.2。依賴沒有被調(diào)用但鎖文件和 release 依賴圖里仍然存在。刪除依賴后重新構(gòu)建產(chǎn)物大小減少 412 KB對(duì)應(yīng)隱私條目也不再需要。這個(gè)結(jié)果說明依賴清理既是合規(guī)工作也是包體積治理的一部分。六、隱私政策要能被機(jī)器粗檢也要能被人讀懂為了便于檢查我們?cè)趥}庫中保留一份結(jié)構(gòu)化政策源文件再生成用戶閱讀的 HTML。結(jié)構(gòu)化字段包括數(shù)據(jù)類型、處理目的、處理方式、觸發(fā)場(chǎng)景、保存期限、三方接收方、撤回方式和刪除路徑。機(jī)器檢查能發(fā)現(xiàn)字段缺失卻不能判斷一句話是否足夠清楚。例如“為了改善體驗(yàn)我們可能收集必要信息”從字段上看并不為空但用戶無法知道是什么信息、何時(shí)收集、用在哪里。腳本只能做下限保護(hù)最終文本仍要經(jīng)過產(chǎn)品、法務(wù)和開發(fā)共同確認(rèn)。運(yùn)行頁顯示本次掃描批次PG-20260930-04版本2.3.0(20300)五項(xiàng)檢查完成三項(xiàng)當(dāng)前發(fā)現(xiàn) 3 個(gè)阻斷項(xiàng)。每個(gè)阻斷項(xiàng)都能跳到來源文件而不是只顯示一個(gè)紅色數(shù)字。頁面里把“阻斷”和“提醒”分開。阻斷表示存在明確的不一致不建議繼續(xù)打包提醒表示腳本無法自動(dòng)判斷需要人工確認(rèn)。否則團(tuán)隊(duì)為了讓報(bào)告變綠可能會(huì)把真實(shí)風(fēng)險(xiǎn)改成忽略規(guī)則。七、把檢查接入 Hvigor但保留開發(fā)節(jié)奏檢查如果只靠開發(fā)者主動(dòng)運(yùn)行很快會(huì)被忘掉。我們把它接到 release 構(gòu)建前debug 構(gòu)建輸出報(bào)告但不阻斷release 構(gòu)建遇到 blocker 就失敗。這樣不會(huì)影響日常調(diào)試又能保證正式包有一致性檢查記錄。// 文件hvigorfile.ts// 用途在 release 打包前執(zhí)行 PrivacyGateimport{appTasks}fromohos/hvigor-ohos-pluginimport{runPrivacyGate}from./tools/privacy-gate/src/indexexportdefault{system:appTasks,plugins:[{pluginId:privacy-gate,apply(node){node.registerTask({name:privacyGateRelease,run:async(){constreportawaitrunPrivacyGate({buildMode:release,version:2.3.0(20300),batchId:PG-20260930-04})if(report.blockers.length0){thrownewError(PRIVACY_GATE_BLOCKED:${report.blockers.length})}}})}}]}不同 DevEco Studio 和 Hvigor 版本的插件接口可能有差異接入時(shí)要以項(xiàng)目當(dāng)前版本文檔與模板為準(zhǔn)。本文代碼表達(dá)的是接入位置和阻斷策略不建議不經(jīng)驗(yàn)證直接復(fù)制到所有版本。八、修復(fù)完成后報(bào)告應(yīng)該能證明什么第一次掃描的三個(gè)阻斷項(xiàng)是PG-201 SDK_DISCLOSURE_MISSING quiet/analytics1.6.2 PG-104 UNUSED_RUNTIME_PERMISSION ohos.permission.LOCATION PG-308 WITHDRAW_PATH_MISSING privacy-policy.json修復(fù)后重新運(yùn)行SDK 從 release 依賴中刪除位置權(quán)限及調(diào)試頁面從生產(chǎn)構(gòu)建中移除隱私政策增加“設(shè)置—隱私管理—撤回授權(quán)”的可操作路徑。第二次報(bào)告顯示blockers0、warnings1唯一提醒是截圖素材中的賬號(hào)信息需要發(fā)布前復(fù)核。這張?jiān)\斷圖承擔(dān)的不是展示一個(gè)漂亮的綠色頁面而是把整改前后對(duì)應(yīng)起來同一個(gè)批次規(guī)則、同一個(gè)版本、三項(xiàng)問題的來源和修復(fù)結(jié)果都能復(fù)查。如果審核再次反饋團(tuán)隊(duì)可以從報(bào)告回到具體文件而不是重新開始猜。九、自動(dòng)化檢查的邊界PrivacyGate不能判斷業(yè)務(wù)是否具有合法、正當(dāng)、必要的處理目的也不能替代審核指南、法律意見或真實(shí)設(shè)備測(cè)試。它能做的是減少低級(jí)不一致配置聲明了但代碼不用、代碼請(qǐng)求了但政策沒寫、依賴存在但缺少說明、后臺(tái)版本與構(gòu)建版本不同。還有一些信息不適合完全自動(dòng)化。例如行業(yè)資質(zhì)、上架區(qū)域、付費(fèi)能力和賬號(hào)主體需要結(jié)合業(yè)務(wù)實(shí)際核對(duì)隱私政策在在架版本關(guān)聯(lián)或?qū)徍酥袝r(shí)后臺(tái)的編輯與生效流程也有狀態(tài)約束不能把“文件已更新”等同于“線上協(xié)議已生效”。我的個(gè)人判斷是上架審核最有效的提速方式不是研究“審核喜歡什么文案”而是讓每個(gè)聲明都有代碼證據(jù)每個(gè)權(quán)限都有業(yè)務(wù)入口每個(gè) SDK 都有版本和隱私說明每次發(fā)布都留下可復(fù)查報(bào)告。這樣即使規(guī)則變化團(tuán)隊(duì)也能快速知道應(yīng)該改哪一層。十、提交前的最終動(dòng)作在QuietGallery中發(fā)布負(fù)責(zé)人會(huì)拿報(bào)告做最后一次人工檢查確認(rèn)包名與版本、核對(duì) release 產(chǎn)物、走一遍首次啟動(dòng)和權(quán)限拒絕路徑、驗(yàn)證隱私政策與撤回入口、檢查截圖素材、確認(rèn)三方 SDK 清單然后再把 APP 包提交到 AppGallery Connect。工具把分散信息放到一起人負(fù)責(zé)判斷這些信息是否真實(shí)、必要和清楚。這個(gè)分工比“讓腳本保證審核通過”更可靠也更符合實(shí)際項(xiàng)目的責(zé)任邊界。十一、參考資料華為開發(fā)者聯(lián)盟提交 HarmonyOS 應(yīng)用與鴻蒙 APPhttps://developer.huawei.com/consumer/cn/app/submitHarmonyOS 開發(fā)者文檔上架申請(qǐng)與 SDK 隱私聲明要求https://developer.huawei.com/consumer/cn/doc/HMScore-Guides/harmonyos-release-application-0000001181600758AppGallery Connect更新隱私政策協(xié)議https://developer.huawei.com/consumer/cn/doc/doccenter-submission/agc-help-publish-api-update-privacy-agreement-0000002328805169