【OpenHarmony/HarmonyOs 】数学学习 App 隐私保护实践:禁止 AI 识图、最小权限与精细化权限管控
项目类型:OpenHarmony / HarmonyOS ArkTS 数学学习应用
文章主题:禁止 AI 识图、精细化权限管控、隐私保护方案
核心观点:隐私保护不是最后补一页协议,而是从架构开始就少拿数据、少要权限、少做不必要识别 🔐
一、为什么数学学习应用也要认真做隐私?
很多工具类应用会觉得自己“不涉及隐私”。但只要应用里出现学习记录、收藏内容、错题、使用习惯,就已经与用户个人数据有关。
数学视界项目里有这些数据:
- 每日学习目标;
- 连续学习天数;
- 计算器历史;
- 单位换算历史;
- 收藏的公式、知识点、图形方案;
- 挑战答题结果和正确率;
- 用户反馈内容。
这些数据虽然不是身份证、定位、人脸这种高敏信息,但仍然可以反映用户的学习习惯。因此我的设计原则是:
能本地完成就本地完成,能不申请权限就不申请权限,能不用 AI 识图就不用 AI 识图。
二、项目当前权限状态:不申请高敏权限
在entry/src/main/module.json5中,当前项目没有声明requestPermissions。
节选如下:
{"module": {"name":"entry","type":"entry","mainElement":"EntryAbility","deviceTypes": ["phone","tablet"],"abilities": [ {"name":"EntryAbility","srcEntry":"./ets/entryability/EntryAbility.ets","exported": true } ] } }这意味着当前应用没有主动申请相机、麦克风、位置、通讯录、相册等高敏权限。对于一个数学学习工具来说,这是非常合理的。
功能上,项目通过以下方式避免权限依赖:
| 功能 | 实现方式 | 是否需要高敏权限 |
|---|---|---|
| 公式大全 | 本地静态数据 | 否 |
| 科学计算器 | 本地表达式计算 | 否 |
| 单位换算 | 本地换算逻辑 | 否 |
| 挑战答题 | 本地题库与计时器 | 否 |
| 曲线画板 | Canvas 本地绘制 | 否 |
| 收藏 | 内存状态管理,后续可本地持久化 | 否 |
| 学习统计 | 本地计数 | 否 |
这就是“权限最小化”的第一步:不要为了看起来高级而申请不必要权限。
三、为什么我选择“禁止 AI 识图”?
数学学习类应用很容易想到一个功能:拍照搜题、AI 识图解题。听起来很酷,但它会立刻带来一系列隐私和合规问题:
- 需要相机权限;
- 可能读取相册;
- 图片中可能包含学生姓名、学校、试卷编号;
- 如果上传云端识别,还涉及网络传输和第三方处理;
- AI 识别结果可能不准确,还会影响学习过程。
因此在当前项目阶段,我明确选择不做 AI 识图,而是采用“用户主动输入 + 本地计算 + 本地图形绘制”的方式。
例如曲线画板中,函数表达式是用户输入的文本:
drawSingleFunction(ctx:CanvasRenderingContext2D,expr:string,color:string,label:string,lineWidth:number):void{if(expr ==='')returnconstexprLower:string= expr.replace(/\s+/g,'').toLowerCase() ctx.strokeStyle= color ctx.lineWidth= lineWidth ctx.beginPath()for(letmathX:number=this.graphRange.xMin; mathX <=this.graphRange.xMax; mathX += step) {constmathY:number=this.evaluateExpr(exprLower, mathX)if(isFinite(mathY)) {constpt:DrawPoint=this.mathToCanvas(mathX, mathY)// 绘制函数曲线} } }表达式求值也是本地处理:
evaluateExpr(expr:string,x:number):number{try{lete:string= expr.replace(/x/g,`(${x})`) e = e.replace(/\^/g,'**') e = e.replace(/sin\(/g,`Math.sin(`) e = e.replace(/cos\(/g,`Math.cos(`) e = e.replace(/sqrt\(/g,`Math.sqrt(`)constfn:Function=newFunction(`"use strict"; return (${e})`)returnfn()asnumber}catch{returnNaN } }这里没有拍照、没有上传图片、没有调用云端识别。用户输入什么,应用就在本地绘制什么。
四、精细化权限管控:未来新增能力时怎么做?
当前项目没有申请权限,但后续如果真的要新增能力,应该遵循“按场景申请”的原则。
例如未来要做“导出图片到相册”,不应该一启动应用就申请相册权限,而应该在用户点击“保存到相册”时再申请,并说明原因。
一个推荐的权限策略表:
| 未来功能 | 可能需要权限 | 申请时机 | 替代方案 |
|---|---|---|---|
| 保存画板图片 | 媒体写入相关权限 | 点击保存时 | 保存到应用沙箱 |
| 拍照识别题目 | 相机权限 | 点击拍照识别时 | 手动输入题目 |
| 从相册导入题目 | 媒体读取相关权限 | 点击相册导入时 | 文本输入 |
| 语音读题 | 麦克风权限 | 点击语音输入时 | 键盘输入 |
| 学习提醒 | 通知权限 | 开启提醒开关时 | 应用内提示 |
OpenHarmony 权限配置通常需要在module.json5中声明,并按权限类型在运行时申请。官方文档也强调了requestPermissions、reason和usedScene等字段的重要性。
示意配置如下:
"requestPermissions": [ {"name":"ohos.permission.PERMISSION_NAME","reason":"$string:permission_reason","usedScene": {"abilities": ["EntryAbility"],"when":"inuse"} } ]重点不是“会写配置”,而是要问自己:这个权限是否真的必要?有没有低权限替代方案?
五、数据最小化:AppState 只保存学习所需数据
项目中统一状态管理在AppState.ets。学习统计数据结构如下:
export interfaceStudyData{totalStudyDays:numbercurrentStreak:numbertotalDrawings:numbertotalCalculations:numbertotalFunctions:numbertotalFormulasViewed:numbertotalUnitsConverted:numberlastStudyDate:stringdailyGoal:numbertodayCount:numberconsecutiveGoalMetDays:numberfunFactsViewed:number}可以看到,它只记录学习行为统计,不记录真实姓名、手机号、定位、人脸、设备通讯录等敏感数据。
收藏数据也尽量聚焦内容本身:
export interface FavoriteItem {id:stringtype:stringtitle:stringcontent:stringcategory:stringicon:stringnote:stringtags:string[] createdAt:numberupdatedAt:numbergraphData?:string}这里的graphData是曲线方案 JSON,不是图片,不包含人像或环境信息。相比“保存截图”,结构化数据更利于隐私保护,因为它只保存业务所需的数学模型参数。
六、用户可控:学习目标和反馈都由用户主动触发
在“我的”页面中,用户可以修改每日学习目标:
AppState.settings.dailyGoal= valAppState.studyData.dailyGoal= val反馈入口也提供了“隐私问题”分类:
ForEach(['功能问题','内容投诉','隐私问题','其他'],(t:string)=>{ Text(t) .onClick(()=>{ this.reportType = t }) })这个入口看似简单,但它表达了一个产品态度:隐私不是开发者单方面说“我保护了”,也要给用户反馈问题的通道。
七、本地优先:挑战结果不依赖云端
挑战答题结果在本地计算:
calculateCorrect(): number { let count =0for(let i =0; i <this.questions.length; i++) {constuserAns =this.normalizeAnswer(this.userAnswers[i])constcorrectAns =this.normalizeAnswer(this.questions[i].answer)if(userAns === correctAns) { count++ } }returncount }答题结束后构造结果数据:
constresultData: ChallengeResult = { id: Date.now().toString(), correctCount, totalCount:this.questions.length, totalTime, score, gradeId:this.config?.gradeId ??'', knowledgeIds:this.config?.knowledgeIds ?? [], isCompleted:true, }这套流程不需要把答案上传到服务器,也不需要进行用户画像。对当前项目来说,本地统计已经足够支持成就、正确率、学习进度等功能。
八、隐私保护方案总结
数学视界当前的隐私设计可以概括为五点:
- 🔐 不申请不必要权限:当前没有相机、相册、位置、麦克风等高敏权限;
- 🚫 禁止 AI 识图:不拍照搜题,不上传试卷图片;
- 🧮 本地计算优先:计算器、题库、挑战评分都在端侧完成;
- 📦 数据最小化:只保存学习统计和收藏内容;
- 🧑💻 用户可控:学习目标可修改,隐私问题可反馈。
如果未来接入 OCR、拍照识题、人脸识别等能力,也应该遵循:
- 默认关闭;
- 用户主动触发;
- 明确说明用途;
- 尽量端侧处理;
- 提供删除和关闭入口。
九、结语
隐私保护不是把功能砍掉,而是做更克制的产品设计。对于数学视界这样的学习应用来说,用户真正需要的是稳定、清晰、可信赖的学习工具,而不是每个入口都接 AI、每个场景都要权限。
先把“不该拿的数据”挡在架构之外,才是最可靠的隐私方案。✨
参考资料:
- OpenHarmony 权限申请指南
- OpenHarmony 权限声明说明