十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

如何直接读取 AndroidManifest.xml?揭秘 PI 的 APK 二进制 Manifest 解析原理

如何直接读取 AndroidManifest.xml?揭秘 PI 的 APK 二进制 Manifest 解析原理 如何直接读取 AndroidManifest.xml揭秘 PI 的 APK 二进制 Manifest 解析原理【免费下载链接】PIPackageInstaller项目地址: https://gitcode.com/gh_mirrors/pi1/PIPI 是一个 Android 端的包安装器PackageInstaller支持 Android 10~17。它的核心能力之一就是直接读取任意 APK 文件中的 AndroidManifest.xml解析出包名、版本号、最低 SDK 版本、应用名称和图标等信息。本文将揭秘 PI 是如何解析 APK 中的二进制 Manifest 的。为什么 APK 里的 AndroidManifest.xml 不能直接读很多新手以为 APK 里的AndroidManifest.xml是普通 XML 文本解压出来就能看——其实不然。APK 经过 AAPT 编译后Manifest 被编译成二进制 XMLAXML格式开头是资源表的魔数字节直接打开只会看到乱码。要读取它必须借助 Android 系统内部的资源解析能力。那么问题来了一个 App 如何读另一个 APK 的 Manifest这就是 PI 要解决的问题。PI 解析 Manifest 的完整流程PI 的解析入口是 PackageParser.kt整体流程可以概括为 3 步加载 APK 资源对象把 APK 文件或其描述符加载成系统的ApkAssets对象打开二进制 Manifest调用ApkAssets.openXml(AndroidManifest.xml)得到一个XmlResourceParser解析器遍历标签提取字段通过 SAX 风格的游标解析器逐个读取manifest、uses-sdk、application标签的属性。关键代码逻辑如下val asset source.get() return asset.openXml(ResourceParser.ANDROID_MANIFEST).use { ResourceParser.parsePackage(it, assets.resources) }openXml是系统对二进制 XML 的原生解码通道返回的解析器可以直接按标签、属性访问内容不需要自己实现 AXML 解码器。ApkAssets系统原生的解析通道ApkAssets是 Android 系统内部用于访问 APK 资源的类。PI 通过它直接打开目标 APK 的 Manifest源码封装在 ApkAssetsSource.kt 中来自文件描述符Fd用ApkAssets.loadFromFd()直接加载无需复制文件性能最好这也是安装会话PackageInstaller Session的标准路径来自输入流Stream先把流内容落盘到缓存目录的临时文件再用ApkAssets.loadFromPath()加载解析完自动删除临时文件。由于ApkAssets属于隐藏 APIPI 在 stub 目录中提供了编译桩如 ApkAssets.java、AssetManagerHidden.java让代码可以顺利编译运行期则调用真实系统实现。标签解析fold 函数优雅提取字段真正的字段提取在 ResourceParser.kt 中完成。它用一个fold扩展函数封装了标签遍历逻辑manifest→ 提取package包名、versionCode、versionName、compileSdkVersion等uses-sdk→ 提取minSdkVersion、targetSdkVersionapplication→ 提取label和icon且能解析资源引用如string/app_name、mipmap/ic_launcher最终把应用图标加载为位图。这里有个细节label、icon在 Manifest 里存的是资源 ID 而不是文本PI 会把 APK 挂到新建的AssetManager上见 AssetManagerCompat.kt通过Resources.getString(resId)还原出真实的应用名称再用 AppIconLoader.kt 生成规范尺寸的图标位图。解析结果统一封装为 PackageInfoLite.kt 中的轻量数据类包含包名、版本号、SDK 版本、名称、图标并实现了Parcelable方便跨进程传递。兼容 Android 10~17 的版本处理隐藏 API 在不同版本上签名不同PI 通过版本判断做适配ApkAssets 加载Android 11 使用新版loadFromFd/loadFromPath签名低版本回退旧签名见 ApkAssetsSource.kt字节数组解析XmlBlock在 Android 12 才公开低版本则通过反射调用私有构造见 XmlBlockCompat.kt 与桩文件 XmlBlock.java。这正是直接读取 Manifest在真实设备上稳定运行的关键——所有隐藏 API 调用都有版本兜底。不止 APK还支持 XAPK 与拆分 APKPI 的loadPackage方法PackageParser.kt用 Zip 容器做了三级降级场景识别方式处理普通 APK压缩包内直接有AndroidManifest.xml直接解析XAPK内含base.apk 若干拆分 APK逐个解析 base 与 split见 SplitConfig.kt嵌套 ZIP内含任意.apk文件遍历并解析所有 APK拆分 APK 只需split、configForSplit、versionCode等少数属性由parseSplit轻量解析避免加载完整资源。总结这套方案的妙处不自己造轮子复用系统的ApkAssetsXmlResourceParser解码 AXML比手写二进制 XML 解析器更可靠零安装即可读取不需要把 APK 装进系统只要拿到文件描述符或输入流就能解析版本全覆盖从 Android 10 到 17 的隐藏 API 差异全部适配反射兜底保证兼容性格式全兼容APK、XAPK、拆分 APK、嵌套 ZIP 一套流程通吃。这套二进制 Manifest 解析能力正是 PI 作为包安装器在展示应用信息、校验版本合法性时的底层基础。如果你想进一步阅读源码可以从 core/src/main/kotlin/dev/sanmer/pi/core/parser/ 目录的解析器开始再看 su/src/main/kotlin/dev/sanmer/su/ 中的安装通道实现完整理解 PI 的架构设计。【免费下载链接】PIPackageInstaller项目地址: https://gitcode.com/gh_mirrors/pi1/PI创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表