☰
【中国方言题库|18】HarmonyOS ArkTS 权限与隐私实战:让 module.json5、功能说明和拒绝路径一致
2026/10/27 1:40:04 网站建设 项目流程

【中国方言题库|18】HarmonyOS ArkTS 权限与隐私实战:让 module.json5、功能说明和拒绝路径一致

**证据边界:**本文基于D:/huawei/one11当前文件静态复核。module.json5 仅声明ohos.permission.INTERNET;PracticePage 先创建离线 TTS,失败后再尝试在线 TTS。功能异常整改说明记录了为在线兜底增加网络权限,而两份更早自检报告仍声称没有 INTERNET,已经与当前工程不一致。INTERNET 是普通权限,没有运行时授权弹窗;失败路径应覆盖离线、服务不可用和引擎创建失败。本轮未构建、运行或在线回读 AGC 隐私标签。

权限合规最常见的问题,不是代码里偷偷申请了大量敏感权限,而是“声明、行为和说明”没有对上:module.json5保留了网络权限,源码却完全使用本地题库和 Preferences;应用介绍写“离线可用”,安装包仍带有不必要的网络能力;设置页能清除学习数据,但隐私说明没有列出收藏、笔记、错题和考试历史;未来增加相机或位置功能时,只设计授权成功路径,没有处理拒绝和永久拒绝。

中国方言题库的真实源码目前呈现出一个很清晰的审计结果:47 个 ArkTS 源文件中没有发现 HTTP、Web、Socket、上传、下载、账号、广告、推送、分析、相机、麦克风、定位或通讯录调用;题库数据来自本地 mock,用户收藏、笔记、错题、进度、考试历史和学习设置保存在本机 Preferences;根包没有运行时第三方依赖。但entry/src/main/module.json5仍声明了ohos.permission.INTERNET。这意味着“功能是本地的”与“安装包具备网络权限”之间存在可以消除的不一致。

本文面向 HarmonyOS 5.0 及以上版本,结合module.json5、EntryAbility、UserDataManager、设置页和本地题库真实实现,讲清如何完成权限最小化、隐私字段盘点、删除路径核验与未来拒绝路径设计。本文唯一核验标记:权限声明必须能被真实功能解释,隐私说明必须能被真实数据验证。

从权限声明到发布资料的闭环

先读取声明,再定位真实调用,区分普通权限与敏感权限,随后为服务失败设计降级,最后同步功能说明、隐私资料并在线回读。

权限、功能与文案三层映射

当前网络权限服务于在线 TTS 兜底,核心文字答题仍应可继续。历史自检文档不能覆盖当前配置,发布材料要以候选工程和实际包为准。

一、先从清单而不是页面文案开始

权限审计的第一证据是模块清单。当前entry/src/main/module.json5包含:

"requestPermissions":[{

"name": "ohos.permission.INTERNET"

}]

同时声明支持:

"deviceTypes":["phone",

"tablet",

"2in1"]

INTERNET是唯一声明的权限。清单中没有相机、麦克风、位置、联系人、日历、媒体文件或通知权限,也没有对应的权限用途说明字段。

仅看清单还不能得出“应用使用网络”的结论。权限声明表示应用具备调用相关能力的条件,不代表代码一定调用。下一步必须把它与源码和依赖一起核对。

二、源码侧没有找到网络调用

对 entry、librarya 和 libraryb 的 ArkTS 源码执行聚焦检索后,没有发现:

HTTP 请求fetch

Web 组件

WebviewSocket

文件上传或下载

云数据库账号登录

广告 SDK

分析 SDK推送 SDK

在线图片地址

根oh-package.json5的dependencies也是空对象,只有测试相关 devDependencies。应用自己的两个 library 模块由工程内部引用,不是在线运行时 SDK。

因此,从当前可见源码看,INTERNET没有对应功能。最小权限原则下,更合理的处理是从requestPermissions中移除它,而不是为了“以后可能用到”先保留。

这里需要保持证据边界:静态检索能说明当前源码与声明不一致,但不能替代对最终 release 包和所有二进制依赖的审计。如果构建产物还打入了未被源码检索覆盖的原生库或三方 SDK,应继续检查包内容;当前根依赖与模块结构没有显示这类能力。

三、为什么一个普通网络权限也不该无理由保留

有人会认为INTERNET不弹运行时授权框,保留也没有用户体验成本。但应用商店审核和隐私一致性关心的不只是弹窗,还关心“安装包能做什么”和“产品声称做什么”。

对一个本地题库应用,不必要的网络权限会带来三个问题:

  1. 与“数据保存在本机”或“离线使用”的产品说明冲突。
  2. 增加审核人员对数据是否上传、是否存在在线服务的疑问。
  3. 未来排查隐私行为时,需要额外证明网络能力没有被使用。

权限最小化不是为了少写一行配置,而是减少需要解释、测试和披露的能力边界。没有真实网络功能时,删除权限是最简单、最可验证的方案。

四、当前本地数据到底有哪些

UserDataManager使用:

preferences.getPreferencesSync(context,

{ name: 'dialect_quiz' }

)

建立本地 Preferences。持久化键包括:

favoriteRecordsnoteRecords

wrongRecords

bankProgressexamHistory

chapterProgress

dailyReminderTimeexamDurationSec

autoNextQuestion

这些键对应的数据是:

收藏记录:题目 ID、题库 ID、创建时间笔记记录:题目 ID、题库 ID、用户输入内容、更新时间

错题记录:题目 ID、题库 ID、答错时间

题库进度:已答数、正确数、最近章节、更新时间章节进度:章节已答数和正确数

考试历史:分数、题量、正确数、用时、完成时间

学习设置:提醒时间、考试时长、自动下一题

其中笔记内容属于用户主动输入的数据;学习记录虽然不一定是敏感个人信息,也属于用户产生的数据。隐私说明应至少告诉用户数据种类、用途、存储位置、是否上传、如何删除。

五、本地存储不等于“没有隐私问题”

数据不上传可以显著降低风险,但仍需要回答:

数据为什么被保存保存在什么位置

应用卸载后如何处理

用户能否主动清除是否会被备份或迁移

是否与账号关联

是否提供导出

当前源码没有账号体系、云同步或跨设备同步,数据只通过本地 Preferences 读写。文章不会把它描述成加密数据库,也不会声称已经实现备份、导出或恢复。

UserDataManager使用普通 Preferences,没有显示自定义加密。收藏、错题、进度这类低敏学习数据通常可以使用 Preferences,但隐私说明不能写成“所有数据均加密存储”,除非实现和验证了对应加密能力。

六、设置页已经提供删除入口

SettingsPage展示收藏、笔记、错题、学习进度和考试历史数量,并提供“清除所有学习数据”。删除不是一次误触即执行,而是两步确认:

privaterequestClearAll():void{if(this.pendingClear) {

this.clearAllLearningData()

}else{this.pendingClear=true

this.showTip('再次点击红色按钮确认清除所有学习数据')

}}

第二次点击后,页面依次清空:

this.favRecords=UserDataManager.clearFavorites()this.noteRecords=UserDataManager.clearNotes()

this.wrongRecords = UserDataManager.clearWrong()

this.progressList=UserDataManager.clearProgress()this.chapterProgressList=

UserDataManager.clearChapterProgress()

this.examHistory=UserDataManager.clearExamHistory()

这条路径覆盖了主要学习数据。但三个设置值没有在“清除所有学习数据”中恢复默认:

dailyReminderTimeexamDurationSec

autoNextQuestion

因此按钮文案“所有学习数据已清除”基本符合收藏、笔记、错题和进度语义,却不等于“清除应用全部本地数据”。隐私说明和 UI 文案应明确删除范围,避免把偏好设置也描述为已删除。

七、删除成功反馈与持久化失败边界

clearAllLearningData()最后会显示:

this.showTip('所有学习数据已清除')

但UserDataManager.persist()的异常处理是:

try{prefs.putSync(key,JSON.stringify(value))

prefs.flushSync()

}catch(_) {}

写入失败被静默吞掉,方法也不返回成功或失败状态。页面会立即把@StorageLink数组设为空,所以当前界面看起来已经删除;如果磁盘写入失败,重新启动后旧数据仍可能恢复。

这不是说正常路径一定失败,而是删除反馈没有和持久化结果绑定。隐私删除属于需要可靠确认的操作,建议让清除方法返回布尔值或明确结果对象:

interfaceClearResult {success:boolean

failedKeys: string[]

}

只有所有目标键落盘成功后显示“已清除”;失败时保留可重试提示。这样删除承诺才与真实持久化结果一致。

八、清除多类数据不是原子事务

设置页按键逐个调用清空方法。每个方法都会putSync和flushSync。如果清除收藏、笔记成功,清除错题时失败,就会出现部分数据已删、部分仍在的状态。

Preferences 适合轻量键值,不代表多个独立写入自动具备事务。对于“全部清除”这种跨键操作,可以考虑:

方案一:使用 Preferences 的整体 clear 能力方案二:统一写入后只 flush 一次

方案三:增加清除版本标记并在启动时完成恢复

选择哪种方式要依据官方 API 和现有数据迁移策略。关键是页面不能把多步操作当成天然原子操作。

九、当前权限没有运行时拒绝路径

因为当前清单只有INTERNET,源码也没有调用权限管理 API,所以应用不会出现相机、位置、麦克风那类运行时授权弹窗,也没有“用户拒绝后怎么办”的代码路径。

这本身与当前离线题库功能一致:如果移除无用INTERNET,应用可以做到不申请任何权限,用户也无需面对拒绝场景。

文章标题中的“拒绝路径一致”不能被误解为当前源码已经实现权限拒绝 UI。准确说法是:现有功能不需要敏感权限,因此最佳拒绝路径是“不发起不必要的请求”;未来新增能力时,必须把拒绝路径与功能一起交付。

十、未来新增权限时先写功能契约

假设未来增加“朗读录音”功能,可能需要麦克风权限。开发前应先定义:

触发动作:用户主动点击“开始录音”用途说明:录制本次方言练习

处理位置:仅本机分析或明确的在线服务

保存周期:即时处理后删除,或由用户管理拒绝行为:仍可使用文字题与其他题库功能

再次请求:在用户再次点击功能时说明原因

永久拒绝:提供前往系统设置的明确入口

权限不能在应用启动时无场景地批量申请。应在用户触发相关功能时,先解释用途,再调用系统授权。

十一、拒绝不能把整个应用锁死

如果某个新功能只占应用的一部分,用户拒绝权限后应降级该功能,而不是让首页无法进入。以录音为例:

允许->进入录音流程

拒绝

->提示“未获得麦克风权限”->保留文字练习、收藏和考试

永久拒绝

->说明可在系统设置中开启->不循环弹窗

拒绝提示必须和功能真实依赖一致。不要用“为了提供更好的服务”这种泛化文案,也不要把非必要权限包装成必需条件。

十二、module.json5 只是权限真源之一

完整一致性至少需要核对四层:

模块清单->声明了哪些能力

运行时代码

->实际调用了哪些能力

功能与 UI

->用户从哪里触发、拒绝后怎样

隐私与上架材料

->如何描述用途、数据、处理位置和删除

任何一层不一致都可能造成审核或信任问题。例如清单删除了网络权限,但隐私政策仍写“通过服务器同步题库”;或者清单保留定位,页面却没有任何位置功能入口。

十三、应用说明应该怎样描述当前版本

结合真实代码,当前版本可以准确描述为:

题库内容内置于应用收藏、笔记、错题、学习进度和考试历史保存在本机

无需登录账号

不提供云同步用户可在设置中清除主要学习数据

不能未经验证宣称:

所有数据均加密支持跨设备同步

支持云端备份

不包含任何网络权限清除按钮会删除全部偏好

其中“不包含任何网络权限”必须等module.json5移除INTERNET、重新构建并检查最终包后才能写入发布材料。

十四、隐私说明至少应列出哪些字段

对当前本地题库,隐私说明可以按数据用途组织:

收藏与错题

用于在本机展示收藏列表、错题复习和统计数量。数据包含题目 ID、题库 ID 与记录时间。

学习笔记

用于保存用户对题目的自定义文字。笔记只在本机展示,不应写成公开内容或社区内容。

学习进度

用于计算已答题数、正确率、章节完成度和最近练习状态。

考试历史

用于展示分数、正确数、题量、用时与完成时间。

学习设置

用于记住提醒时间、考试时长和是否自动进入下一题。当前代码只保存“提醒时间设置”,没有看到通知权限或定时通知实现,不能宣称已经发送系统提醒。

十五、提醒设置暴露出的功能说明边界

设置页允许选择“每天 09:00”“每天 12:00”“每天 21:00”或关闭,并把值保存到 Preferences。但源码检索没有发现通知权限、通知请求或后台提醒调度。

因此当前实现的真实能力是“保存每日学习提醒时间偏好”,不是“系统会在指定时间发送通知”。如果 UI 对用户展示为已设置提醒,可能形成期待差异。

解决方式有两个:

如果暂不实现通知->把文案改为“计划学习时间”

-> 不声称会系统提醒

如果实现通知->增加真实通知能力

-> 核对通知权限、授权流程、拒绝路径

->更新隐私和功能说明

不能仅凭保存了时间字符串就把通知能力写入上架材料。

十六、页面路由参数也要按数据最小化检查

应用使用router.pushUrl()在页面间传递题库 ID、章节 ID、练习模式和答题记录等参数。考试结果页会把答题记录 JSON 传给错题解析。

这些数据在同一应用内用于页面导航,没有看到上传行为。但仍应遵守最小化:

只传目标页面需要的数据避免在日志中打印完整用户笔记

避免把大数组长期挂在路由历史

对JSON解析失败提供默认值

当前ExamResultPage对 records 的 JSON 解析使用try/catch,失败时保留空数组。它是输入容错,不涉及系统权限。

十七、日志也属于隐私审计范围

EntryAbility使用 hilog 记录生命周期和错误原因。当前日志主要是 Ability 启动、窗口加载和避让区错误,没有输出收藏、笔记内容、题目答案或用户标识。

后续开发时应保持这个边界:

可以记录错误类型和流程节点不要记录完整笔记正文

不要记录签名秘密或账号凭证

不要记录权限授权结果之外的敏感数据release 版本避免无必要调试日志

权限合规不仅看清单,也看敏感数据是否通过日志、缓存或错误上报外泄。

十八、第三方依赖为什么必须单独审计

当前根 dependencies 为空,这降低了隐私审计复杂度。未来一旦加入统计、广告、推送、崩溃上报、在线语音识别或账号 SDK,不能只看应用自己是否调用网络。

需要核对:

SDK 初始化时机是否自动采集设备信息

是否启动即联网

域名和服务器位置个人信息字段

隐私政策披露

用户同意前是否运行是否可关闭或延迟初始化

SDK 可能间接引入权限或网络行为。上架材料中的 SDK 列表、隐私标签和包内依赖必须一致。

十九、移除 INTERNET 后怎样验证

修改清单后应重新构建 release 包,并执行最小烟测:

安装应用冷启动进入首页

浏览题库和分类

随机练习与模拟考试保存收藏、笔记和错题

退出并重新启动,确认本地恢复

进入设置并清除学习数据无网络环境下重复核心流程

卸载应用

还应检查构建产物中的权限清单,确认不是只改了源码文件却仍使用旧包。无网络环境测试可以验证核心流程确实不依赖在线资源,但不能替代清单检查。

二十、权限审计的自动化清单

可以把以下检查加入发布前脚本或 CI:

读取 module.json5.requestPermissions扫描 @kit.NetworkKit、Web、Socket等导入

扫描权限请求 API

扫描第三方依赖扫描远程 URL 与域名

列出 Preferences / RDB / 文件存储键

核对隐私说明中的数据类别核对删除入口和真实删除键

核对 release 包权限

自动化不能判断文案是否误导,但能快速发现“清单有权限、源码无调用”或“源码调用能力、清单没有声明”的明显偏差。

二十一、当前项目最小整改建议

按风险和成本排序:

1.确认最终包确实没有网络功能或网络 SDK2.从 module.json5移除无用 INTERNET 权限
  1. 重新构建并检查 release 包权限
4.将提醒时间文案与真实通知能力对齐5.明确“清除学习数据”不包含三个设置偏好
  1. 让持久化清除返回真实成功/失败
7.在隐私说明列出本地数据类别和删除路径8.保持上架隐私标签、功能说明与包行为一致

如果后续确认确实有在线更新题库的需求,则不能简单移除网络权限;应实现真实网络服务、加载失败和离线回退,并同步更新隐私材料。当前源码没有这条链路。

二十二、拒绝路径的测试用例模板

当前版本没有敏感权限,因此不需要运行此模板。未来新增权限时可直接复用:

首次点击功能,授权允许首次点击功能,授权拒绝

再次点击,解释用途后重试

永久拒绝,提供系统设置入口从系统设置返回,重新检查状态

授权后关闭权限,功能降级

拒绝权限时其他页面仍可使用应用重启后不循环弹窗

每条都应验证 UI 文案、权限状态和业务结果,而不是只确认系统弹窗出现过。

二十三、隐私一致性不是一次性文档工作

每次增加以下能力,都要重新审计:

联网账号

云同步

相机麦克风

位置

通知广告

分析

反馈上传第三方 SDK

数据导出或备份

权限、隐私和功能是同一份产品契约的不同表现。代码变化后,清单、隐私政策、用户协议、应用详情和审核备注都要一起更新。

二十四、结语

中国方言题库当前核心流程是本地题库加本地 Preferences,用户无需登录,也没有可见的网络调用和敏感权限请求。真正需要修正的是module.json5中未被真实功能解释的INTERNET权限,以及“提醒”和“清除全部”文案与实际能力的边界。

可以把整套审计浓缩成一句话:权限声明必须能被真实功能解释,隐私说明必须能被真实数据验证。不需要的权限直接移除,需要的权限在用户触发场景中申请;本地数据如实列出用途和删除范围;未来增加敏感能力时同时交付允许、拒绝、永久拒绝和降级路径。只有清单、代码、页面和上架材料互相证明,权限与隐私才真正一致。

普通权限也需要解释用途

INTERNET 不要求用户在运行时点击授权,但这不等于可以省略用途说明。只要应用可能通过在线 TTS 发起网络访问,功能介绍、隐私说明和 AGC 标签就应说明触发条件、处理目的、失败影响以及是否上传用户输入。若无法从源码证明数据去向,文章应标记为待核对,不能自行补写“不会上传”或“仅在本地处理”。

拒绝路径在这里应改称失败路径

当前源码没有相机、位置、麦克风等需要运行时授权的敏感权限申请,因此不存在用户点击拒绝 INTERNET 弹窗的流程。更准确的测试是关闭网络、让离线引擎不可用、让在线引擎创建失败,并确认文字题仍可作答、播放按钮给出状态且不会无限加载。把不存在的授权弹窗写进教程,会误导实现和审核材料。

历史文档要绑定版本

自检报告应记录生成日期、源码提交、bundleName、versionCode 和候选包哈希。后续增加在线兜底或权限时,旧报告保留为历史证据,但结论必须重新生成。此次可以确认配置与旧报告发生漂移;只有重新构建并回读包清单、再核对 AGC 在线字段后,才能给出发布结论。

最小验收矩阵

至少覆盖离线引擎成功、离线失败在线成功、两者均失败、设备无网络、重复点击播放和页面离开时释放引擎。每条用例记录实际调用路径、用户提示、文字答题是否可继续、网络请求与日志证据。未运行统一写作 not run,不把代码中存在 catch 当作测试已经通过。


需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询