Android APK 权限清单怎么做差异检测?用 apkanalyzer 比较原包与加固包|御盾
核心判断:若要确认加固前后 APK 请求的权限是否不同,先用 Android 官方 apkanalyzer manifest permissions 分别读取两个 APK,再比较提取出的权限集合;不要只看源码 Manifest,也不要仅凭文本相同就推断 Play 合规或运行期行为一致。御盾提供的本地权限清单比较器只比较用户粘贴的命令输出,不接收 APK,也不替代真实产物核查。本轮没有提供或测试御盾 APK,产品候选状态为 NOT_TESTED。
摘要
用同一构建变体的两份 APK 权限输出做集合比较,再对差异回溯到 Manifest 合并或产物链;本文的在线工具只比较粘贴文本,不解析 APK。
读者对象与问题边界
本文面向需要检查 Android APK Manifest 权限的开发、测试、安全和发布团队。目标是回答一个窄问题:两份已提取的 APK 权限清单有哪些新增、移除或保持不变的项目,以及发现差异后如何找到它首次进入交付链的位置。它不提供 APK 二进制解析,不检查运行时是否实际调用联系人、定位、相机等数据,也不判断 Google Play 是否批准权限用途。
核心结论
- Android 官方
apkanalyzer可读取 APK Manifest 权限和 target SDK;两份输出可形成静态清单差异。 - 源码 Manifest 不等于最终 APK Manifest,构建变体和库声明可能参与合并。
- 差异集合只能说明输入清单的不同,不能自动确定权限来源、运行时行为或政策结果。
- 本地比较器不接收 APK;御盾自有或客户产物均未测试,状态为
NOT_TESTED。
如果实际交付物是 AAB,应遵循团队的应用包验证流程,检查 Bundle 内容及面向目标设备生成的 APK 产物。此处给出的 apkanalyzer manifest permissions 命令以 APK 文件为输入;不能把某一份通用 APK 的结果外推到 AAB 生成的所有设备配置。权限静态列表有助于发布核对,但它只覆盖清单声明这一面。
快速流程:先固定两个被比较的对象
比较开始前,为原包和候选包分别记下版本、构建变体、产物类型、文件摘要与来源。应确保两者属于同一业务版本,或明确记录版本差异;若一个是 Debug、另一个是 Release,观察到的权限差异可能来自变体配置,而不是保护步骤。不同候选的产物身份若不清楚,就先停止比较,不能从文件名猜测它们的关系。
Android Developers 文档说明,apkanalyzer 可查看 APK Manifest,并提供 manifest permissions 和 manifest target-sdk 子命令。可以在受控的本地 Android SDK 环境中分别运行:
apkanalyzer manifest permissions /path/to/original.apk
apkanalyzer manifest permissions /path/to/candidate.apk
apkanalyzer manifest target-sdk /path/to/original.apk
apkanalyzer manifest target-sdk /path/to/candidate.apk
上面是工具用法示例,不表示御盾已对某个 APK 执行这些命令。请将路径替换为你有权检查的文件;不要把私有 APK 上传到不受控网站,也不要在公开报告中粘贴包名、证书、签名信息或客户产物的未脱敏标识。两份命令输出应分别保存并与被检查文件关联,之后再进入差异比较。
技术拆解:本地权限比较器能做什么
比较器面向 apkanalyzer manifest permissions 的文本输出。将原始 APK 输出贴入左侧,候选 APK 输出贴入右侧,页面会在浏览器当前会话内提取权限名称,分别列出候选新增、候选移除和两边共同存在的权限。结果可导出为 JSON,便于手动附在发布审查记录中。页面不上传两个文本框的内容,不调用服务端 API,也不读取或保存 APK 文件。
该工具刻意不尝试在浏览器里重新实现 Android 二进制 XML 解码,也不把 AAB 当成 APK。若输入为空、命令输出格式无法解析或至少一侧没有识别出权限名称,页面会提示无法比较,而不会输出“无差异”。用户应检查命令是否成功、文件路径是否正确、输出是否完整,然后重新读取。对不属于标准 Android 权限命名空间的自定义权限,或工具版本输出格式不同的行,也应人工复核解析结果。
工具返回的 JSON 记录包括输入中识别出的权限列表、差异集合、比较时间以及“仅比较粘贴文本”的边界。它不包含 APK 文件摘要,也不能证明文本确实来自所声明的文件。发布负责人应在自己的构建系统中另行记录 SHA-256、构建变体和候选身份,避免导出的列表脱离产物上下文。
Manifest Merge 为什么会改变最终权限
Android 项目可能同时包含主 Manifest、Product Flavor、Build Type、具体构建变体以及导入库的 Manifest。构建时,Manifest Merger 会按优先级合并这些声明,并把结果放入 APK 或 Android App Bundle。某个权限没有写在主 src/main/AndroidManifest.xml 中,并不能证明它不会出现在打包清单里;依赖库或某个专用变体可能引入它。
排查时应使用 Android Studio 的 Merged Manifest 视图或 Manifest Merger 报告,确认每一项声明来自哪个输入文件。主应用的 variant manifest、build type、flavor、主 Manifest 和库 Manifest 的优先级不同;实际结果还受到 tools:node 等 merge rule marker 和构建配置影响。不要看到某个权限与某个 SDK 同时出现就直接认定 SDK 是来源,必须查看合并报告或逐项构建差异。
变体比较也要保持一致。若 Original 来自 demoRelease,候选来自 fullDebug,即使它们对应同一个 Git commit,权限列表仍可能不同。要回答“加固是否改变权限”,最有说服力的比较是同一应用版本、相同构建变体、同一依赖锁定状态下,保护链前后的实际产物;如无法做到,应把差异归为“待定位”,而不是把责任归给某个环节。
从差异集合定位首次出现阶段
用五个阶段记录清单状态:源码 Manifest、合并后的 Manifest、原始 APK、受保护候选 APK、客户最终签名 APK。每一阶段都记录产物来源和检查方式。对相邻阶段进行比较,第一次出现权限新增或移除的位置,才是后续调查的起点;它不是未经复核的责任判定。
| 阶段 | 输入对象 | 主要问题 | 发现差异后的首要复核 |
|---|---|---|---|
| Source | 主 Manifest 与各源文件 | 开发者直接声明了什么 | 是否检查了正确模块和变体 |
| Merged | 目标 Variant 的合并结果 | SDK、Flavor 或规则是否带入声明 | Merged Manifest 与 merger report |
| Original APK | 保护前打包产物 | 实际构建文件包含什么 | 文件摘要、target SDK、产物来源 |
| Protected Candidate | 保护工具输出 | 保护阶段前后列表是否不同 | 相同输入、参数、工具版本和产物身份 |
| Final Signed APK | 客户签名后的交付物 | 最终准备分发的文件是什么 | 签名、版本、渠道和前一候选是否匹配 |
如果权限在 Source 没有、Merged 中出现,应先检查依赖或变体。如果 Merged Manifest 没有、Original APK 中出现,应核查实际构建任务和 APK 来源。如果 Original 无该项、Protected Candidate 出现,才有理由把保护阶段列为调查范围;还要用同一输入重跑并排除配置变化。如果 Protected Candidate 没有、Final Signed APK 出现,优先调查后续打包或渠道处理。只有证据链完整之后,才可以写明首次差异阶段。
新增、移除和一致分别能说明什么
“新增”说明候选清单比原包多出权限声明,需要进一步确认功能是否需要、声明由哪个阶段引入,以及是否涉及平台政策。它不证明应用已经滥用权限,也不自动意味着加固过程有缺陷。“移除”表示候选列表里没有原包的某项声明,但不证明相关功能仍然可用;运行时 API 调用、SDK 行为和业务路径需要另行检查。
“一致”表示两份被比较的权限集合相同。如果文本取错、输入不完整、工具输出解析失败或候选身份错误,这个结论没有意义。因此记录应包含文件身份和命令执行结果。即使权限集合一致,也不能推导 APK 字节相同、签名相同、target SDK 相同、隐私实践合规或应用商店审批通过。比较结论的表述应限于“指定两个产物的已读取权限列表相同”。
对于 READ_CONTACTS 等敏感权限,还需要将权限状态与功能用途、目标 SDK 和目标商店规则分开判断。Google Play 对面向 Android 17/API 37+ 且请求 READ_CONTACTS 的应用公布了联系人权限要求;能由用户主动选择少量联系人完成的场景,可评估 Contact Picker 等更小范围方案。Permission Diff 能指出候选清单中存在什么声明,但不能说明某个业务是否符合“核心功能必要性”,也不能提交或批准 Play Console 声明。具体政策事实和时间点请以御盾的 Android 17 联系人权限说明及 Google Play 当前规则为准。
动态时间线:把权限证据绑定到发布候选
权限比较的时间线从“选择对象”开始,而不是从粘贴清单开始。先确定业务版本和目标渠道,然后固定构建变体与依赖状态;随后保留 Original、Protected Candidate 和 Final Signed Artifact 的来源关系。每次生成的清单都应能追溯到对应文件,避免把上一轮的文本误贴到新候选。
下一步读取目标变体的 Merged Manifest,保存合并报告。完成构建后,用同一 Android SDK 工具读取 Original APK 和 Protected APK 的 Manifest 权限与 target SDK。若候选经客户正式签名或渠道侧重新处理,还应读取最后交付的 APK 并重新比较。出现差异时,沿相邻阶段回到首次出现的位置,再核查依赖版本、构建任务、保护参数或渠道处理记录。
最后,发布负责人复核列表是否完整、产物身份是否一致、差异项是否有业务依据,并把未完成项标为 UNKNOWN 或 NOT_TESTED。只有在风险和政策判断另有证据的情况下,才能决定放行。静态权限列表可以作为发布记录的一部分,但不是对用户数据访问行为的完整观测,也不替代 Play Console 的政策审核。
事实依据与脱敏证据
本节把本期用户提供的工作重点、官方公开资料、工程判断和结论边界逐项对照,帮助读者区分“为什么选择这个检查问题”与“官方资料实际证明了什么”。搜索需求方向仍是待验证的选题假设,不是已经确认的关键词流量或排名增长。
| 序号 | 公开事实或本期输入 | 工程判断 | 不能据此推出 |
|---|---|---|---|
| 1 | Google Play 对 target API 37+ 且请求 READ_CONTACTS 的应用提出联系人权限要求 |
发布门禁应检查最终产物而不只看源码 | 某个具体御盾包触发或通过该政策 |
| 2 | 报告要求建设 APK 权限差异能力,并把实际测试结果与未测试状态分开 | 先提供本地、可复核的清单比较路径 | 御盾已有 APK 自动解析或合规认证能力 |
| 3 | Android 官方 apkanalyzer 提供 Manifest 权限与 target SDK 查询命令 |
两份 APK 的静态清单可用相同工具读取后比较 | 该命令检查运行时数据访问行为 |
| 4 | Gradle 构建会合并多个源集、变体和依赖库中的 Manifest | 权限差异应沿合并阶段定位来源 | 发现新增权限就代表由某 SDK 或加固器单独引入 |
| 5 | 本期报告明确没有执行御盾 APK/AAB 权限差异测试 | 产品侧结论必须标记为 NOT_TESTED |
任何权限“PASS”或“不变”的产品结论 |
| 6 | apkanalyzer manifest permissions 文档命令以 APK 文件为输入 |
AAB 与设备交付 APK 要另按实际发布流核对 | 某个通用 APK 覆盖所有 AAB 配置 |
| 7 | Android 官方文档还提供 manifest target-sdk 命令 |
可在清单对比时并列记录 target SDK | target SDK 足以代表权限政策结论 |
report_scope: 2026-10-08
public_tool: local_comparison_of_pasted_apkanalyzer_permission_output
raw_apk_upload: false
yudun_apk_permission_diff: NOT_TESTED
play_policy_compliance: NOT_TESTED
search_demand_validation: NOT_VERIFIED
Source Report Mapping:本期问题与页面回应
下表把本期推进报告提出的问题转成可公开核对的处理范围;它记录的是选题依据和边界,不是御盾 APK 测试结果。
| 报告事实或需求 | 本页回应 | 公开边界 |
|---|---|---|
| 本期策略优先建设 APK 权限差异检测,减少重复政策解释 | 提供 apkanalyzer 输出比较流程和独立工具入口 | 工具不解析 APK 二进制 |
| 报告指出需要第一份可复核 Manifest 发布证据 | 明确列出需要记录的产物身份与状态字段 | 没有授权 APK,保持 NOT_TESTED |
| 权限差异可涉及 Manifest Merge、依赖和构建变体 | 增加逐阶段定位方法 | 不预判任何单一 SDK 或加固流程为来源 |
| READ_CONTACTS 政策是工具需求的上下文,而非唯一长期主题 | 链回 Contact Picker 政策页并说明目标 SDK/最终清单边界 | 权限清单比较不作 Play 合规结论 |
| 搜索需求方向尚未由平台数据验证 | 将搜索词作为待验证方向,不报告流量或排名增长 | 未导出 Search Console 数据 |
| 用户强调实测结果和未测试状态需区分 | 公开说明本轮只运行合成文本工具检查 | 没有御盾产品候选 PASS/FAIL |
测试目标与非目标:本地比较器的范围
本轮主目标是实现并核对一项本地权限文本比较能力;非目标是声称完成御盾 APK 评估。页面脚本可以用合成的权限列表做工具逻辑自检,但这不是御盾 APK 实测,也不能证明对所有 apkanalyzer 版本、所有权限输出格式或 AAB 产物均有覆盖。任何格式兼容问题都应回报并先人工复核,不得将空解析结果解释为无差异。
| 目标 | 输入 | 本轮状态 | 不能推出 |
|---|---|---|---|
| 比较两份命令输出 | 用户粘贴的权限文本 | 工具逻辑自检 | 不能证明来源文件身份 |
| 列出新增/移除/共有权限 | 可解析的权限名 | 工具逻辑自检 | 不能判定权限用途是否合法 |
| 识别空输入或解析失败 | 两侧文本为空或无权限行 | 代码路径已实现 | 不能将解析失败当作零权限 |
| 检查御盾实际候选 | 授权的 Original/Protected APK | NOT_TESTED |
不报告 PASS/FAIL |
非目标包括:读取客户 APK、验证签名或包名、扫描组件暴露、检查运行时权限调用、执行 Google Play 政策判定、测试 Contact Picker 功能或证明御盾加固兼容性。当前没有提供授权的自有 APK 样本、构建产物摘要和 Play Console 记录,因此产品测试结果均为 NOT_TESTED,并未生成第一方权限一致性证据。
权限差异记录建议
实际执行时至少记录:产物角色、文件摘要、应用版本、构建变体、APK/AAB 类型、Android SDK Build Tools/apkanalyzer 版本、权限集合、比较结果、检查时间、复核责任人和未覆盖项。对 AAB 应记录用于检查的具体 APK 集合或由发行流程生成的设备配置产物,不能只保留一个“通用 APK”结果。
Original Artifact: NOT_TESTED
Candidate Artifact: NOT_TESTED
Original Permission Set: NOT_TESTED
Candidate Permission Set: NOT_TESTED
Added / Removed / Unchanged: NOT_TESTED
Manifest Merge Source: NOT_TESTED
Play Policy Review: NOT_TESTED
Checked At: null
上面的记录是空白状态示例,不是御盾产品检查结论。得到真实产物后,应先在授权环境读取并保存结果,再把客户身份、包名、签名与内部路径脱敏后决定是否公开。即使第一次真实比较结果为“无差异”,也只能陈述被测的这两个候选和工具版本,不能宣传成御盾所有策略、版本和 APK 权限永远一致。
工程落地前的复核清单
比较前先确认两份 APK 都由可追溯的构建任务产生,并对文件计算本地摘要;摘要只用于固定对象,不需要公开给搜索页面。记录 SDK 工具版本和命令退出状态,确保输出不是截断的错误信息。若流水线采用自动保存或复制候选产物的方式,还应核对实际读取路径与发布目录的对应关系,避免拿到旧文件或 Debug 文件。以上检查应由拥有构建系统访问权限的团队完成。
差异出现后,先按权限名聚合并查阅官方平台文档,确认该项是 Android 系统权限、应用自定义权限还是工具输出中的其他标识。遇到目标 SDK 或平台版本相关规则时,记录采用的版本条件和复核日期。若某项权限来自依赖库,应查看 Manifest Merger 报告并与依赖版本对应;不能只凭库名称或源码中的单个片段做结论。需要移除依赖声明时,应评估库功能是否还可运行,并做构建与关键路径验证。
权限清单比较适合成为一个小型发布检查,而不是独立的“合规认证”。它能够帮助团队缩短差异定位时间,但产品决策还需要把功能必要性、用户体验、数据保留、隐私披露、商店规则和运行时行为放入评估。静态权限结果最好附在同一 Release Record 中,以便后续候选、依赖或目标 SDK 变化时可以重做比较。
工程落地:不要把静态差异合并成一个 PASS
适合的门禁至少拆成三个独立问题:第一,最终 APK 实际声明了什么权限;第二,目标商店政策和开发者声明是否已按当前规则复核;第三,受保护候选在目标设备和业务路径上的兼容情况是否已经测试。三种结论可以共同关联到版本号和候选摘要,但不应互相替代。
若新增权限无法解释、输入身份不匹配、命令输出为空、产物差异尚未定位或政策状态未知,门禁应输出 REVIEW_REQUIRED、UNKNOWN 或 NOT_TESTED,而不是默认通过。高风险权限的移除也要检查业务功能,不能为了让列表变短而破坏用户流程。策略判断和加固产品判断应分别由相应责任方完成。
御盾的产品职责是保护 App 候选并支持发布验收;Android SDK 工具提供静态 APK 检查;Google Play 对其分发政策作审核;客户发布团队负责确定业务用途、产物身份与放行。将这几项分开记录,才有可能在出现差异时定位问题并复核责任边界。
攻防视角:权限声明只是一个静态观察面
权限列表是交付物 Manifest 的声明面,既不能独立证明应用实际读取了哪些数据,也不能覆盖运行时 SDK、用户授权状态、服务端同步和业务用途。反过来,某项权限出现在清单里也不足以单独说明应用正在滥用它。防守方应先用构建产物和合并来源确定“声明了什么”,再结合代码路径、运行期验证和平台政策判断“为什么需要、何时使用、是否允许”。工具输出只支持第一步,不能被扩展成完整安全或隐私结论。
常见误区
- 误区:主 Manifest 没有声明,就说明 APK 没有该权限。应读取最终产物。
- 误区:两份权限集合相同,就说明 APK 或签名完全相同。比较器只比较清单文本。
- 误区:发现新权限就能归因某个 SDK 或加固流程。应先定位首次出现阶段。
- 误区:空白结果代表“没有权限”。解析失败和空清单不是同一结论。
- 误区:权限集合符合预期就代表 Google Play 已批准。商店审核与静态清单核对相互独立。
风险边界
本页说明的是清单差异检查方法,不是法律意见、隐私审计、应用商店审批承诺或御盾产品测试报告。工具处理用户主动粘贴的命令输出,解析范围可能受格式影响;比较结果必须结合原始产物、构建记录和合并报告人工复核。政策和 Android 工具文档可能更新,实际发布时应重新检查官方来源。
常见问题
这个网页会上传 APK 或权限清单吗?
不会。它不提供 APK 上传控件,比较逻辑在浏览器内运行;粘贴的文本用于当前页面会话内计算。请仍然避免把客户标识、私有包名或敏感日志粘贴到公共设备,并以自己的网络与浏览器安全要求为准。
比较结果一致,就能说明加固没有改变 APK 吗?
不能。结果只说明两个输入文本中识别到的权限集合相同,不比较 APK 字节、签名、组件、资源、代码或运行时行为,也不说明 Google Play 合规。产物摘要、target SDK 和签名应另行记录。
为什么源码没有权限,最终 APK 却出现了?
主 Manifest、构建变体和导入库可能在构建时合并。先查看目标 Variant 的 Merged Manifest 和 Manifest Merger 报告,再核对生成 APK 是否来自同一配置。不要根据源码单文件或 SDK 名称直接判断来源。
可以直接比较 AAB 和 APK 吗?
不可以。本页按两份 APK 的 apkanalyzer manifest permissions 文本设计。AAB 需要在实际发布流程中检查 Bundle 和由其生成的设备交付 APK;要比较权限,必须确定对比的具体产物和设备配置。
御盾是否已经证明加固前后权限集合一致?
没有。本次没有获取授权的自有 APK/AAB 和御盾候选,页面也不自动解析 APK。御盾权限差异测试状态为 NOT_TESTED;需要有明确样本、产物身份和测试记录后才能给出限定范围内的实测结论。
事实依据与延伸阅读
- Android Developers:apkanalyzer 命令行工具(含
manifest permissions与manifest target-sdk) - Android Developers:管理 Manifest 文件与合并
- Android Developers:构建变体
- Google Play:联系人权限政策提醒
- 御盾:Android 17 READ_CONTACTS 与 Contact Picker 发布检查
- 御盾:App 加固 PoC 验收指南
- 御盾:性能与兼容性中心