权限声明与最小权限原则
聊到第三方 SDK 的权限问题,我脑子里立刻蹦出几年前的一个项目。当时我们集成了一家地图 SDK,结果发现 App 一启动就弹「读取通讯录」的授权框——用户直接差评刷屏。后来一查,SDK 里躺着一行没人注意的权限声明。这事让我彻底明白,权限这玩意儿,你想着「反正声明了也没用」,用户可不这么想。
Android 与 iOS 权限模型差异
说白了,两个系统对权限的态度完全不同。Android 走的是「先声明、后申请」的路子,你在 AndroidManifest.xml 里列了哪些权限,安装时或运行时系统才允许你申请。iOS 则更霸道——不允许「静默声明」,任何权限必须在调用系统 API 时实时弹出对话框,而且用户随时可以去设置里关掉。
核心区别一句话:Android 的权限是「授权后一直有效直到撤销」,iOS 的权限是「每次使用都可能被拒绝」。
| 对比维度 | Android | iOS |
|---|---|---|
| 权限声明方式 | Manifest 静态声明 + 运行时请求 | Info.plist 描述 + 运行时实时弹窗 |
| 权限类型 | 普通 / 危险 / 签名 / 系统 | NS* 前缀,每个权限独立描述 |
| 用户可撤销性 | Android 6.0+ 可单独关闭 | 设置中随时关闭,且系统会重置 |
| 第三方 SDK 行为 | SDK 可直接声明权限(需审计) | SDK 不能自动声明,宿主 App 必须主动添加 NSCameraUsageDescription 等键值 |
| 最小权限原则 | 需手动检查 SDK 额外权限 | 审核更严,但也是人工审查 |
Android 权限模型细节
我习惯把 Android 权限分成三层:
- Normal Permissions——系统自动授予,比如
INTERNET。SDK 声明了也不弹窗,但容易被滥用。 - Dangerous Permissions——比如
ACCESS_FINE_LOCATION、CAMERA。必须运行时请求,用户能拒绝。 - Signature / System——系统级权限,第三方 SDK 通常拿不到。
你看,问题出在「普通权限」上。很多 SDK 偷偷加上 READ_EXTERNAL_STORAGE(危险权限)还写在 Manifest 里,实际上根本用不到。我在审计时发现过一个社交分享 SDK,居然声明了 RECORD_AUDIO——就问一个分享按钮为什么需要录音?
审计小技巧:用 aapt dump permissions your.apk 列出所有声明的权限,然后一行行核对 SDK 功能。别信文档,信二进制。
iOS 权限模型细节
iOS 这边的关键点在 Info.plist。每个权限必须写一个「使用说明」字符串,例如 NSCameraUsageDescription 的值是「此应用需要相机权限以拍摄头像」。用户弹窗时能看到这段话。
但坑也在这里——很多开发者觉得「随便写一句就行」。我曾经见过一个购物 App 的相机权限描述写的是「为了更好的体验」——用户根本不知道你什么时候会偷拍。更严重的是,有些 SDK 会要求宿主 App 在 plist 里添加某些 key,但宿主自己不知道,结果审核被拒。
注意:iOS 14.5 之后,App 追踪透明度(ATT)权限也被纳入隐私框架。如果你集成广告类 SDK,必须在 plist 里声明 NSUserTrackingUsageDescription,否则直接无法获取 IDFA。
权限滥用的典型案例
我把项目中踩过的坑整理成几类,你想想看是不是很眼熟:
| 类型 | 具体表现 | 真实案例 |
|---|---|---|
| 过度声明 | SDK 声明了与核心功能无关的权限 | 某推送 SDK 声明了 READ_CONTACTS,官方说「用于优化消息送达」,实际没任何代码用到 |
| 隐蔽授权 | SDK 在后台静默申请权限,不弹窗解释 | 某统计 SDK 在 Android 6.0 以下版本偷偷读取设备标识 |
| 拒绝降级 | 用户拒绝权限后,SDK 功能直接崩溃或无限弹窗 | 某视频 SDK 拒绝相机权限后,每次启动都弹窗「请授权」,无法关闭 |
| 数据关联 | 将获取的权限数据与用户 ID 关联后外传 | 某广告 SDK 获取位置后,连同 IMEI 一起发送到第三方服务器 |
为什么这些案例频发?说白了,SDK 开发者总想「多拿点数据,反正不影响用户」。但合规审计就是要把这些「顺手牵羊」的行为揪出来。
最小权限原则落地
我个人认为,最小权限原则不是一句口号,而是可以量化的标准。我每次审计都按三步走:
- 列出所有权限——通过反编译或 API 日志,抓出 SDK 实际申请的所有权限。
- 匹配功能点——把每个权限对应到 SDK 的某个具体功能。对不上的就是可疑项。
- 测试拒绝场景——模拟用户拒绝该权限,看 SDK 是否正常降级。如果崩溃或报错,说明强依赖不该有的权限。
举个例子,一个图片加载库(比如 Glide 或 SDWebImage)只需要 INTERNET 和文件存储权限。如果它在 AndroidManifest 里加上 CAMERA,那就直接亮红灯。
黄金标准:SDK 声明的权限数量 ≤ 其核心功能所需的最小权限数。多一个都不行。
知识体系总览
下面这张图把整个权限审计的逻辑串起来了。你跟着箭头走一遍,基本上就能形成自己的审计框架。
避坑指南与实战心得
我最后分享几条亲自踩过的坑,希望能帮你省掉不少排查时间。
- [Android] 别信 merge 后的 manifest——有时候 SDK 通过
tools:replace覆盖宿主的权限声明。一定要看最终的 merged manifest 文件,位置在build/intermediates/merged_manifest/下。 - [iOS] 注意 Privacy Info 的完整路径——iOS 16 之后,Apple 要求所有隐私相关权限都要在
PrivacyInfo.xcprivacy文件中声明,否则审核不通过。SDK 文档如果不提这个,你就得主动追问。 - [通用] 测试用户拒绝权限后的表现——不要只测授权场景。我曾见过一个支付 SDK,用户拒绝位置权限后直接闪退,导致线上支付功能无法使用。正确的做法是降级为无位置服务,而不是强制要求。
- [一句话总结] 如果 SDK 的文档里没有「权限声明列表」和「最小权限说明」,这个 SDK 的合规性就要打问号。
紧急提醒:2024 年 Google Play 和 App Store 都加强了对权限的审核。一旦发现 SDK 超范围申请权限,不仅 App 会被拒,开发者的账号也可能被标记。对于历史遗留的 SDK,建议尽快升级到最新版本,并重新审计权限清单。
好了,权限这个话题说深了能写一本书,但掌握以上几条,应付日常审计完全够用。下一件事就是动手把项目里的权限清单拉出来,对照着看一遍——你会发现,问题比你想象的要多。不信?试试看。