☰
用 booster-task-list-permission 一键列出 Android 工程中的权限清单
2026/10/15 3:47:27 网站建设 项目流程
  • 移动开发
  • 质量保障
  • 构建工具

【免费下载链接】booster

🚀Optimizer for mobile applications

项目地址:https://gitcode.com/gh_mirrors/bo/booster
点击查看免费下载

导读:在 Android 多模块工程中,权限往往分散声明在各个依赖 AAR 的AndroidManifest.xml里,手工汇总极易遗漏。booster 的booster-task-list-permission模块通过在构建期解析合并后的 Manifest,将整个工程实际生效的 Android 权限(含uses-permission、uses-permission-sdk-23、uses-permission-sdk-m三种声明形式)一次性打印出来。读完本文,你将掌握该模块的安装接入方式、listPermissions与按变体粒度任务的用法,并理解其从 Gradle 任务注册到 SAX 解析的完整实现原理。

模块定位:回答"我的 APK 里到底申请了哪些权限"

booster-task-list-permission是 Booster 任务体系中的一个小而实用的模块,其职责(见 模块 README)是:

显示本工程依赖的 AAR 中使用的 Android 权限列表。

它解决的实际问题是:主工程AndroidManifest.xml中写的权限只是最终权限的"入口",构建时 Gradle 的 Manifest Merger 会把所有直接/传递依赖 AAR 中声明的<uses-permission>一并合并进最终产物。因此在提审、合规自查或排查权限滥用时,需要一份基于合并后 Manifest的权限清单,而该模块正是以这一真实产物为数据源,而不是简单扫描主模块源码。

该模块在仓库中与两个同族模块互为对照:booster-task-list-artifact(列出工程 artifacts)、booster-task-list-shared-library(列出 native 动态库)。三者共同展示了 Booster 通过 Gradle task 扩展构建信息可视化的思路。

快速开始:一个 Gradle 任务拿到全部权限

接入方式与 Booster 其他模块一致:将该模块加入工程的 buildscript classpath 后,在工程根目录执行:

./gradlew listPermissions

执行后任务会把权限清单直接打印到控制台,输出形如:

- android.permission.ACCESS_FINE_LOCATION - android.permission.INTERNET - android.permission.READ_EXTERNAL_STORAGE

每条权限前带-前缀,便于直接复制到文档或提审清单中。如果合并后的 Manifest 中没有任何权限声明,任务将静默结束、不输出任何条目(源码中通过ifNotEmpty仅在集合非空时才遍历打印,见 ListPermission.kt)。

按变体粒度查看:list<Variant>Permissions

与单一入口任务listPermissions配套,该模块还会为工程中的每一个 Android Variant注册一个专属任务,任务名遵循list${VariantName}Permissions命名规则(源码见 ListPermissionVariantProcessor.kt)。

任务名作用范围说明
listPermissions全部分支聚合任务,依赖于所有变体任务
listDebugPermissionsdebug变体仅打印 debug 构建下合并 Manifest 的权限
listReleasePermissionsrelease变体仅打印 release 构建下合并 Manifest 的权限
list<VariantName>Permissions任意自定义变体flavor 场景下按flavor + buildType维度生成,例如listChinaDebugPermissions

这里有一个值得注意的工程实践:listPermissions任务名是硬编码常量(private const val TASK_NAME = "listPermissions"),而变体任务名由variant.name.capitalized()动态拼装,capitalized来自 Booster 的booster-kotlinx扩展库。两个任务都注册在BOOSTER任务分组下(it.group = BOOSTER),执行./gradlew tasks时会在 Booster 分组中看到它们,并带有 "List the permissions declared in AndroidManifest.xml" 的描述信息。

背后的机制:VariantProcessor SPI 与任务注册

该模块并非在 plugin 里写死逻辑,而是遵循 Booster 的任务扩展规范,通过Java SPI将自身挂载到 Gradle 构建生命周期中:

  1. 实现VariantProcessor接口(定义见 VariantProcessor.kt),该接口是 Booster 的 task 管理 SPI,提供beforeProcess(variantBuilder)与process(variant)两个扩展点;
  2. 使用@AutoService(VariantProcessor::class)注解标注ListPermissionVariantProcessor(ListPermissionVariantProcessor.kt),编译期自动生成META-INF/services注册文件;
  3. Booster 插件在apply时通过 ServiceLoader.kt 的loadVariantProcessors(project)从 buildscript classloader 加载全部VariantProcessor实例;
  4. 随后在 BoosterPlugin.kt 的onVariants回调中,对每个 variant 调用processor.process(variant),此时每个变体的任务便完成了注册。

在process(variant)内部,注册逻辑有一个优雅的"先查后建"处理:先尝试tasks.named(TASK_NAME)查找是否已存在聚合任务,若抛出UnknownTaskException(即尚未注册)才tasks.register创建;随后为当前变体注册ListPermission类型的任务,并通过listPermissions.dependsOn(it)建立聚合任务依赖变体任务的关系,保证执行listPermissions时所有变体的权限都会依次被收集(源码见 ListPermissionVariantProcessor.kt)。

任务的数据源通过 AGP 的Variant Artifacts API注入:

it.mergedManifest.set(variant.artifacts.get(SingleArtifact.MERGED_MANIFEST))

即直接消费 AGP 提供的MERGED_MANIFEST产物,该产物正是最终合并了所有依赖 AAR 声明的 Manifest 文件。这意味着无论权限来自主工程还是某个传递依赖的 AAR,只要最终进入了合并结果,就会被统计到,这正是该模块比"扫描主模块源码"更可靠的原因。

核心实现:SAX 流式解析合并后的 Manifest

任务本体ListPermission继承 Gradle 的DefaultTask,通过@get:InputFile声明mergedManifest作为输入文件(ListPermission.kt),并在此基础上配置了一个非验证、支持命名空间感知的 SAXParserFactory:

factory.isXIncludeAware = false factory.isNamespaceAware = true factory.setFeature("http://xml.org/sax/features/namespace-prefixes", true) factory.setFeature("http://xml.org/sax/features/xmlns-uris", true) factory.isValidating = false

这些配置的含义与必要性:

  • isNamespaceAware = true:AndroidManifest 使用android:命名空间,必须开启命名空间感知才能正确解析android:name属性;
  • namespace-prefixes与xmlns-uris特性:确保 SAX 回调中能同时拿到qName与前缀映射,从而可靠地读取命名空间属性;
  • isValidating = false与isXIncludeAware = false:关闭 DTD 校验与 XInclude 处理,避免无谓的校验开销和潜在的安全面,保证解析只做"读取属性"这一件事。

@TaskAction方法打开 Manifest 输入流,交给PermissionUsageHandler进行流式解析(内存友好,不将整个 XML DOM 载入),解析完成后对权限集合排序并逐行打印。

权限收集规则:三种 Manifest 声明形式全覆盖

解析的核心逻辑集中在 PermissionUsageHandler.kt 中,它继承DefaultHandler,重写startElement并在遇到三种元素时收集android:name属性:

Manifest 元素语义是否被收集
uses-permission无条件声明权限,安装即生效✅
uses-permission-sdk-23仅 Android 6.0(API 23)及以上生效,低版本忽略✅
uses-permission-sdk-m同uses-permission-sdk-23(旧命名,M = Marshmallow)✅

收集结果保存在mutableSetOf<String>()中,天然去重——同一个权限无论被多少 AAR 重复声明,最终清单中只会出现一次;由于使用Set,最终输出顺序不确定,因此任务在打印前会调用.sorted()保证输出稳定可读。

值得强调的是,该 Handler 只关心权限声明(uses-permission*标签),并不解析<permission>(自定义权限的定义)或<uses-feature>(功能需求),这是模块定位决定的:它回答的是"申请了哪些系统权限",而非"定义了哪些自定义权限"。

源码地图与进阶扩展

想深入阅读或二次开发,可对照以下文件:

  • 模块 README —— 模块用途与快速开始命令;
  • ListPermissionVariantProcessor.kt —— 任务注册、命名规则、聚合依赖关系;
  • ListPermission.kt —— Gradle task 定义、SAXFactory 配置与输出逻辑;
  • PermissionUsageHandler.kt —— 权限元素提取与去重;
  • VariantProcessor.kt —— 任务扩展 SPI 接口定义,模块通过它接入构建生命周期。

如果你需要自定义类似的"清单类"任务(例如列出 AAR 中的 Activity、Service 或广播接收器),完全可以照搬本模块的骨架:实现VariantProcessor并通过@AutoService注册,用SingleArtifact.MERGED_MANIFEST作为输入,再写一个针对目标元素的 SAX Handler 即可。Booster 官方推荐的扩展流程与此一致(实现VariantProcessor接口并以 SPI 注册,见 CLAUDE.md)。

小结

booster-task-list-permission用最简的接入成本(一条 Gradle 命令)解决了 Android 工程权限清单统计的常见痛点:以 AGP 合并后的 Manifest 为唯一数据源,借助 SAX 流式解析覆盖三种权限声明形式,通过 VariantProcessor SPI 与任务依赖机制同时提供全局视图(listPermissions)和变体级视图(list<Variant>Permissions)。无论是日常自查、提审准备,还是对依赖 AAR 做合规审计,它都能成为构建流程中一个随时可用的信息工具。

  • 移动开发
  • 质量保障
  • 构建工具

【免费下载链接】booster

🚀Optimizer for mobile applications

项目地址:https://gitcode.com/gh_mirrors/bo/booster
点击查看免费下载
上一篇:Sass 函数命名提案解析:function-name 草案如何收窄保留函数名禁令
下一篇:基于 Airbyte 声明式 CDK 构建 Mailjet SMS 数据源连接器:manifest.yaml 深度解析与本地开发指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

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

立即咨询