【万能转换器|18】HarmonyOS ArkTS 权限与隐私实战:让 module.json5、功能说明和拒绝路径一致
【万能转换器18】HarmonyOS ArkTS 权限与隐私实战让 module.json5、功能说明和拒绝路径一致本轮证据边界当前源码的requestPermissions为空未发现网络、位置、相机或麦克风能力调用汇率使用静态表检查到的剪贴板路径只写不读。与此同时工程注册了EntryBackupAbility且allowToBackupRestore为true现有隐私文案没有解释系统备份恢复边界。本轮没有构建、安装、抓取运行时权限弹窗或核验 AGC 软件包。由于当前应用不申请运行时权限文中的“拒绝路径”仅是未来新增受限能力时的建议模板不代表现有页面已经实现权限拒绝交互。权限合规最容易出现一种“每个文件单独看都没问题合起来却互相打架”的状态module.json5没有声明敏感权限产品文案写着完全离线页面确实没有联网入口但本地数据、系统剪贴板、备份恢复、反馈联系方式和清除能力又各自在不同模块中演进。审核真正核验的不是某一句承诺而是声明、调用、界面、失败路径和上架资料能否组成同一个事实。“万能转换器”的当前源码非常适合做一次反向审计。entry/src/main/module.json5的requestPermissions是空数组ArkTS 源码没有导入网络请求、Web、定位、相机或麦克风能力oh-package.json5没有生产依赖历史记录、工具收藏、主题、字号和默认单位都写入 Preferences汇率说明明确使用内置参考表复制结果只向系统剪贴板写文本没有读取剪贴板。就这些证据而言“离线、免登录、无运行时权限申请”是可以复核的。但源码也暴露出几处不能略过的真实边界。backup_config.json把allowToBackupRestore设为true工程还注册了EntryBackupAbility而隐私文本只写“仅保存在设备本地不上传至任何服务器”没有解释系统备份恢复边界反馈邮箱和著作权人仍是显式占位值清除历史记录不会同步清除独立的工具收藏和设置偏好剪贴板写入失败时只记录日志没有给用户失败反馈。本文不会把这些问题写成已经修复更不会推断已上架安装包一定与当前源码快照相同而是把它们作为发布前必须核对的差异。本文面向 HarmonyOS 5.0 及以上版本基于module.json5、backup_config.json、EntryBackupAbility.ets、BrandConfig.ets、MinePage.ets、HistoryRepository.ets、FavoriteToolsService.ets、SettingsService.ets和剪贴板调用代码建立一套可复核的权限与隐私闭环。唯一标记AGC18-HMOS-18-18-PERMISSION-PRIVACY-MANIFEST-DENIAL一、权限审计要从事实矩阵开始不要先写隐私政策再去代码里寻找能够支持它的证据。更稳妥的顺序是先列出应用真实处理的数据和系统能力场景当前实现是否声明运行时权限数据去向当前失败路径单位与计算换算纯本地算法否内存输入校验汇率换算内置参考汇率表否内存不涉及网络失败历史记录Preferences否应用本地存储初始化/写入异常记录日志工具收藏Preferences否应用本地存储初始化失败记录日志主题、字号、默认单位Preferences否应用本地存储写入失败记录日志复制结果/邮箱写系统剪贴板否系统剪贴板成功 Toast失败仅日志备份恢复BackupExtensionAbility否需按系统备份策略确认当前回调只记录日志这张表的价值是把“权限”和“隐私”拆开。没有运行时权限不等于没有数据处理数据只在本地也不等于不需要说明保存内容、清除入口和备份边界。二、module.json5 的空权限清单是可验证事实当前模块配置为{ module: { name: entry, type: entry, deviceTypes: [phone], requestPermissions: [] } }requestPermissions: []表示当前模块没有在配置层声明应用运行所需权限。华为文档说明Stage 模型的module.json5会向编译工具、操作系统和应用市场提供模块、组件和权限信息因此它不是普通注释而是审核证据的一部分。空数组只能证明“配置里没声明”还需要继续搜索调用面。本文对entry/src/main/ets的 Kit 导入和敏感 API 进行了复核没有发现requestPermissionsFromUser()、atManager、HTTP、WebSocket、Web、相机、位置、麦克风、通讯录或用户文件选择调用。三、空权限不是免审通行证权限最小化的核心不是把清单写空而是功能不暗中依赖未声明能力。一次可靠检查至少包括三层ManifestrequestPermissions 声明了什么 Source实际导入和调用了什么 Kit/API Runtime核心流程是否触发系统授权、跨应用访问或网络如果只看 Manifest可能漏掉三方 SDK 的初始化、动态代码路径或系统能力间接调用如果只看源码又可能漏掉构建产物合并后的权限。当前项目没有生产依赖这降低了第三方 SDK 自动采集和自动加权权限的风险但发布前仍应对实际 APP/HAP 产物做权限扫描而不是把oh-package.json5空依赖当作最终结论。四、离线声明有四组源码证据BrandConfig.ets的产品描述和MinePage.ets的隐私文本都把应用定义为完全离线。这个结论在当前源码中有四组支撑module.json5没有ohos.permission.INTERNET。ArkTS 文件没有 HTTP、WebSocket、Web 组件或网络 Kit 导入。oh-package.json5的生产依赖为空。汇率页使用应用内置参考汇率不宣称实时联网价格。这里必须保留“当前源码快照”这一限定。正式审核的是上传包包内代码、权限、SDK 与 AGC 隐私标签才是最终事实。如果发布分支后来增加联网反馈、统计、广告或实时汇率就必须同步改 Manifest、隐私政策、SDK 清单、数据用途和拒绝路径。五、本地数据也要逐项披露源码中至少有三份 Preferencesapp_history / items app_favorites / favoriteList app_settings / theme, fontScale, defaultUnitsHistoryRepository把最多 200 条历史记录序列化为 JSON 字符串FavoriteToolsService保存收藏工具 keySettingsService保存主题、字号和默认单位。隐私文本已经覆盖“历史记录、工具收藏、主题、字号、默认单位”这点与实现基本一致。不过“本地数据”仍需回答四个问题为什么保存、保存多久、如何清除、是否参与系统备份。只写“不收集个人信息”无法替代这些说明因为用户的计算记录即使不构成身份信息也仍是用户产生的数据和应用状态。六、Preferences 的本地边界要说准确HistoryRepository的写入过程是const trimmed items.slice(0, MAX_ITEMS); await store.put(KEY_ITEMS, serializeHistory(trimmed)); await store.flush();这说明数据持久化发生在应用的 Preferences 存储中且历史数量有 200 条上限。适合对用户表述为“历史记录保存在应用本地用于展示最近换算结果”不宜扩张为“任何情况下都永不离开当前设备”因为工程同时开启了备份恢复能力。同理Preferences 不是敏感数据保险箱。当前保存的是工具 key、主题和普通计算结果不包含密码、令牌等关键资产若以后加入账号凭据、支付标识或健康数据就不能沿用同一套明文偏好存储与简单隐私描述。七、备份恢复是当前最大的声明差异backup_config.json的实际内容为{ allowToBackupRestore: true }module.json5还注册了{ name: EntryBackupAbility, type: backup, exported: false, metadata: [{ name: ohos.extension.backup, resource: $profile:backup_config }] }这意味着项目主动保留了系统备份恢复扩展点。当前onBackup()和onRestore()只记录日志没有显式枚举文件或上传服务器仅凭这两个空回调不能武断地声称哪些 Preferences 一定被备份也不能忽略allowToBackupRestore: true。正确做法是根据目标 SDK、系统备份策略和实机行为确认实际范围再二选一产品不需要迁移关闭备份恢复并验证升级、卸载和换机场景。产品需要迁移保留能力在隐私文本中准确说明由系统提供的备份/恢复范围、触发条件和用户控制方式。八、“仅保存在设备本地”需要补充边界词当前隐私文本写着以下数据仅保存在您的设备本地不上传至任何服务器。这句话与应用自身不发网络请求的事实一致但与“允许系统备份恢复”的配置之间存在解释空间。更稳妥的文案不是刻意模糊而是先决定产品策略。如果关闭备份可写“数据保存在应用本地应用自身不上传或同步”。如果保留系统备份可写“应用自身不向开发者服务器上传若用户启用系统备份恢复相关应用数据可能按系统机制迁移”并以实测结果约束“相关数据”的范围。关键是区分“应用开发者的服务器上传”和“操作系统提供的数据迁移”不能用一句“完全不上传”覆盖两个不同机制。九、系统剪贴板写入不应被误写成读取应用在ConvertPage、CapitalForm、RadixForm和MinePage中使用pasteboard但调用模式都是const data pasteboard.createData( pasteboard.MIMETYPE_TEXT_PLAIN, text, ); pasteboard.getSystemPasteboard().setData(data);源码没有读取剪贴板内容也没有声明ohos.permission.READ_PASTEBOARD。因此隐私清单应描述“在用户点击复制时将当前结果写入系统剪贴板”不应因为看到pasteboard就误写成“读取剪贴板”更不能虚构剪贴板采集。HarmonyOS 的单次授权文档把READ_PASTEBOARD列为支持“允许本次使用”的敏感权限之一但那针对读取场景。当前项目只写入不能把另一个 API 的规则机械套过来。十、复制失败路径目前只有日志copyResults()在成功后显示“已复制到剪贴板”但 Promise 失败时只执行.catch((err: Error) { console.error([ConvertPage] copy failed: ${err.message}); });这不属于权限拒绝崩溃却属于能力失败路径不完整。用户点击后没有成功 Toast也没有失败提示会误以为内容已经复制。建议把写入封装为统一服务返回明确结果// 建议方案非当前源码 export interface CopyResult { ok: boolean; reason?: string; } async function copyPlainText(text: string): PromiseCopyResult { try { const data pasteboard.createData( pasteboard.MIMETYPE_TEXT_PLAIN, text, ); await pasteboard.getSystemPasteboard().setData(data); return { ok: true }; } catch (error) { return { ok: false, reason: (error as Error).message }; } }页面根据ok显示“已复制”或“复制失败请重试”日志只承担诊断职责。十一、当前没有敏感权限也就没有真实拒绝弹窗本文标题中的“拒绝路径”不能伪造成已经存在。当前源码不申请相机、位置、麦克风等敏感权限所以运行时不会出现这类系统授权拒绝。当前最好的拒绝策略恰恰是无需权限的核心换算功能不弹权限框、不因拒绝退出、不要求用户先同意无关能力。如果未来新增扫码识别、拍照取数或位置单位推荐拒绝路径才需要进入产品设计。华为 UX 隐私规范强调电话、通讯录、定位、短信、录音、相机、存储、日历等权限被拒绝后应用不应退出或关闭。用户再次触发相关功能时可以说明影响并提供前往设置的明确入口。十二、未来新增权限应采用功能触发式申请一个可维护的权限状态机应至少区分// 建议模型非当前源码 export type PermissionUiState | idle | requesting | granted | denied | blocked | unavailable;申请顺序应是用户点击需要权限的功能 → 检查当前授权状态 → 调用系统授权接口 → 允许进入功能 → 拒绝留在原页展示无权限降级状态 → 再次触发说明影响并按平台规范提供设置入口不要在启动时批量申请尚未使用的权限也不要在系统权限弹窗前叠加一个强制自定义弹窗。当前应用没有敏感权限因此保持零申请比搭建一套空洞的首次启动同意流程更符合最小化原则。十三、隐私政策入口与首次运行提示不是同一件事MinePage在“关于”分组中提供“隐私政策”和“用户协议”入口用户可在应用内查看这是公开透明的一部分。隐私政策应是独立、可重复访问的文本而不是用户点过一次后永远找不到。是否需要首次运行同意要看应用是否在启动阶段处理需征得同意的个人信息或初始化会采集数据的 SDK。当前源码没有登录、广告、分析、网络 SDK和敏感权限不能为了“看起来合规”而添加一个不允许拒绝、不同意就无法使用离线换算的强制弹窗。一旦引入会处理个人信息的 SDK则必须在初始化之前完成必要告知与同意并提供拒绝后的可用范围而不是先初始化、后展示隐私文本。十四、反馈联系方式占位是发布阻断项当前BrandConfig.ets明确写着export const BRAND_FEEDBACK_EMAIL your-real-emailexample.com; export const BRAND_COPYRIGHT_OWNER 开发者名称;EntryAbility.onCreate()会通过listPlaceholderFields()检查并输出警告这是很好的开发期防线但日志警告不会阻止发布。隐私政策最后一节让用户通过“反馈与建议”联系开发者页面又把占位邮箱复制到剪贴板如果发布包确实包含该值联系方式将不可用。需要强调队列记录的版本状态不能证明当前源码快照就是市场安装包。这里能确认的只有“当前被审计源码仍有占位值”。发布前应将占位检查升级为构建门禁并核对 AGC 主体、应用内著作权人与隐私政策主体一致。十五、清除历史不等于清除全部本地数据设置页的“清除缓存”实际只调用HistoryService.get().clearAll()HistoryRepository.clear()删除app_history/items。工具收藏存放在独立的app_favorites/favoriteList主题、字号和默认单位存放在app_settings。因此按钮文案“清除缓存”容易让用户理解成清除全部应用数据但当前行为只是清除历史记录。产品应二选一把文案改为“清除历史记录”准确描述现有行为。增加“清除全部本地数据”明确列出历史、收藏和设置二次确认后逐项删除并重建默认状态。隐私政策中的数据主体控制最终要落到这些可操作入口而不是只写一句“用户可以删除”。十六、删除能力需要可验证的完成语义清除动作已有确认框和成功 Toast但仍应验证三个层次持久层对应 Preferences key 是否删除并 flush 状态层AppStorage/页面列表是否立即更新 重启层杀进程重启后数据是否仍为空如果做“全部清除”不要只清空 UI 数组。建议由一个LocalDataService编排现有服务// 建议方案非当前源码 async clearAllLocalData(): Promisevoid { await HistoryService.get().clearAll(); await FavoriteToolsService.get().clear(); await SettingsService.get().resetToDefaults(); }其中resetToDefaults()当前并不存在必须真实实现主题、字号、默认单位的清理和 AppStorage 回写后才能写进产品说明。十七、AGC 隐私标签必须与包内事实同源发布前至少要同时核对审核面当前源码证据AGC 应填写的事实网络无 INTERNET、无网络调用不提供网络服务不虚构实时汇率账号无登录和认证依赖无账号体系权限requestPermissions: []不声明未使用敏感权限SDK无生产依赖不虚构第三方 SDK也不漏报后来新增项本地数据三份 Preferences说明历史、收藏与偏好用途备份backup 扩展已开启先实测再决定披露或关闭联系方式当前仍为占位发布包必须替换为真实可联系信息最危险的不是“填少了”而是 AGC 写“不收集、不处理、不备份”包内却存在另一条链路。反过来为了保险而勾选大量不存在的数据采集同样会造成产品能力与声明不一致。十八、自动化检查应拦住权限漂移可以在发布前做一组轻量扫描rg -n requestPermissions|ohos.permission entry/src/main rg -n requestPermissionsFromUser|atManager entry/src/main/ets rg -n http|fetch|Web\\(|socket entry/src/main/ets rg -n your-real-email|example.com|开发者名称 entry/src/main这些命令不能替代人工审计但能防止“新增 API 忘记更新 Manifest”和“占位字段混进发布包”。更完整的门禁还应解析 JSON5 与依赖树避免简单文本搜索误报注释或漏掉构建合并结果。建议把检查结果保存为发布证据权限声明数 敏感 API 调用点 生产依赖与 SDK 清单 网络入口扫描 占位字段扫描 备份恢复配置 隐私政策入口截图 拒绝/失败路径截图十九、真机验收要覆盖拒绝、失败和卸载当前应用没有敏感权限因此验收重点不是伪造“拒绝相机”场景而是验证无权限核心流程首次安装启动无权限弹窗、无登录阻断。断网状态完成单位、生活和工程计算。汇率页明确是参考汇率不出现实时更新承诺。写入历史后重启记录仍在且不超过设计上限。收藏、主题、字号和默认单位分别持久化。点击复制成功有 Toast模拟失败时用户可见。隐私政策和用户协议可在应用内重复打开。清除历史后重启历史保持为空收藏和设置行为符合文案。实测系统备份恢复确认哪些 Preferences 被迁移。卸载后重装验证应用数据行为与系统策略一致。如果未来增加敏感权限再把“首次拒绝、再次拒绝、仅本次允许、设置中撤销、后台恢复、永久拒绝、能力不可用”加入矩阵。二十、最小收口顺序与结论基于当前源码权限与隐私不需要大改架构最小收口顺序很清楚保留requestPermissions: []继续维持离线核心流程不申请敏感权限。对实际构建产物扫描权限、网络入口和生产依赖。决定是否需要系统备份恢复不需要就关闭需要就实测并准确披露。把“清除缓存”改成“清除历史记录”或实现真正的全部本地数据清除。为剪贴板写入失败增加用户可见反馈。将反馈邮箱和著作权人占位升级为发布构建阻断。核对应用内隐私文本、AGC 隐私标签、SDK 清单和实际包行为。保存断网、清除、重启、备份恢复和卸载重装的验收证据。当前项目的优点是边界足够克制无网络、无账号、无生产 SDK、无敏感权限数据层也集中在三个 Preferences 服务里。真正需要警惕的不是复杂权限系统而是几处小差异逐渐破坏可信度备份配置没有进入隐私说明、清除文案覆盖范围过大、复制失败静默、联系信息仍是占位。权限合规不是“弹一个隐私框”而是一条从功能目的、Manifest、API 调用、数据存储、拒绝或失败路径、删除能力到 AGC 声明的连续合同。合同中的每一句话都应该能在源码、运行结果或发布后台找到对应证据。官方资料可继续参考华为开发者的 应用配置文件概述、应用隐私保护、选择和同意、向用户申请单次授权 与 应用市场审核政策。具体权限等级、授权结果、备份范围和系统设置跳转能力应以项目目标 SDK 与对应设备系统版本的官方文档和实测结果为准。AI 辅助声明本文在人工核对真实 HarmonyOS 模块配置、备份配置、隐私文案、本地存储和剪贴板调用后使用 AI 辅助整理结构、润色表达并生成配图权限状态、隐私差异和建议实现均按文中证据边界区分。CSDN-SERIES:ALL-163250154