博文地址

我的GitHub 我的博客 我的微信 我的邮箱
baiqiantao baiqiantao bqt20094 baiqiantao@sina.com

APK文件分析

官方文档

使用 APK 分析器分析您的编译版本

[Analyze your build with APK Analyzer]

Android Studio包含一个APK分析器,可在构建过程完成后立即深入了解APK的组成。使用APK分析器可以减少您调试应用的DEX文件资源相关问题所花费的时间,并有助于减少您的APK大小。您也可以通过命令行 apkanalyzer 使用。

使用APK分析器,您可以完成以下操作:

  • 查看APK中文件的绝对大小和相对大小,例如DEX和Android资源文件。
  • 了解DEX文件的组成。
  • 快速查看APK中文件的最终版本,例如AndroidManifest.xml文件。
  • 对两个APK进行并排比较[side-by-side comparison]。

项目打开时,有三种方法可以访问APK Analyzer:

  • 将APK拖到Android Studio的编辑器窗口中。
  • 在 Project 窗口中切换到 Project 透视图,然后在默认的 build/output/apks/ 目录中双击相应 APK。
  • 在菜单栏中选择Build> Analyze APK,然后选择您的APK。

重要:分析调试版本时,请使用通过选择Build> Build APKgradle命令创建的APK。单击工具栏中的 Run 会生成启用了Instant Run的APK,这些APK不应与APK Analyzer一起用于优化任务,因为它们仅供开发使用,并动态加载大多数资源。您可以通过是否有 instant-run.zip 文件嵌入在APK中来识别即时运行APK。

查看文件和大小信息

[View file and size information]

APK是遵循ZIP文件格式的文件[APKs are files that follow the ZIP file format]。APK 分析器将每个文件或文件夹显示为一个实体,这些实体具有可用于导航到文件夹中的展开功能。这些实体的层次结构反映了 APK 中的文件和文件夹的结构。

APK 分析器会显示每个实体的原始文件大小下载文件大小值,如图 1 所示。Raw File Size 表示实体在磁盘上未经压缩时的大小,而 Download Size 则表示实体由 Google Play 提供时估计压缩后的大小。% of Total Download Size 表示实体占 APK 总下载大小的百分比。

Gradle 翻译 Analyzer APK文件分析 [MD]

图 1. APK 分析器中的文件大小

查看 AndroidManifest.xml

如果您的项目包含多个 AndroidManifest.xml 文件(如 product flavors 的清单文件)或者包含的库也提供清单文件,这些文件会在您的 APK 中合并成一个文件。此清单文件通常是 APK 中的二进制文件,但在 APK 分析器中选择此文件后,会重构并呈现此实体的 XML 格式。在此查看器中,您可以了解在编译期间可能对您的应用所做的任何更改。例如,您可以看到应用所依赖的某个库中的 AndroidManifest.xml 文件是如何合并到最终 AndroidManifest.xml 文件中的。

此外,此查看器还提供了一些 Lint 功能,并且会在右上角显示相关警告或错误。图 2 显示了正在报告选定清单文件中的一条错误。

Gradle 翻译 Analyzer APK文件分析 [MD]

图 2. 选定清单文件的右侧空白处显示了一个错误图标

查看 DEX 文件

在 APK 分析器的 DEX 文件查看器中,您可以立即查看应用的 DEX 文件中的底层信息。该查看器中提供了类、软件包、总引用和声明计数,这有助于决定是否使用 multidex 或如何移除依赖项以低于 64K DEX 限制

图 3 描绘了一个低于 64k DEX 限制的中等大小的应用。

  • Defined MethodsReferenced Methods 列中列出了 DEX 文件中每个软件包、类和方法的相关计数。
  • Referenced Methods 列统计由 DEX 文件引用的所有方法。这通常包括在您的代码和依赖项库中定义的方法以及在代码使用的标准 Java 和 Android 软件包中定义的方法 - 这些方法计入每个 DEX 文件中的 64k 方法限制。
  • Defined Methods 列仅统计在某一个 DEX 文件中定义的方法,所以此数字是 Referenced Methods 的子集。

请注意,如果将某个依赖项打包在 APK 中,这两个方法计数都会加上在该依赖项中定义的方法。
另请注意,缩减大小[minification]和 Proguard 压缩 功能也会在源代码经过编译后大大改变 DEX 文件的内容。

Gradle 翻译 Analyzer APK文件分析 [MD]

Figure 3. A medium-sized app

过滤DEX文件树视图

[Filter the DEX file tree view]

Class 列表正上方,APK 分析器提供了用于查看选定 DEX 文件内容的过滤器。

要使用过滤器来显示某个类中的所有方法和字段,请执行以下操作:

  1. File 列表中,选择 classes.dex 文件。
  2. Class 列表中,导航到一个类并选择该类。
  3. 点击小三角形展开您选择的类。
  4. 切换 Show fields 图标 Gradle 翻译 Analyzer APK文件分析 [MD] 以显示或隐藏类字段。
  5. 切换 Show methods 图标 Gradle 翻译 Analyzer APK文件分析 [MD] 以显示或隐藏类方法。
  6. 切换 Show all referenced methods or fields 图标 Gradle 翻译 Analyzer APK文件分析 [MD] 以显示或隐藏引用的软件包、类、方法和字段。在树状视图中,斜体节点是在选定 DEX 文件中没有定义的引用

Gradle 翻译 Analyzer APK文件分析 [MD]

DEX 文件可以引用在其他文件中定义的方法和字段。例如,System.out.println() 是对 Android 框架中的 println() 方法的引用。

加载 Proguard 映射文件

过滤器图标旁边是 Proguard 映射图标。它们处于灰显状态,直到您加载一组 Proguard 映射文件来向 DEX 查看器添加一些功能,如对名称进行反混淆处理 (mapping.txt)、显示已移除的节点 (usage.txt),以及指示无法移除的节点 (seeds.txt)。

Proguard 映射文件将应用于在启用了 Proguard 的情况下编译的 APK,并且它们来自的编译版本必须与生成相应 APK 的编译版本相同。

要加载 Proguard 映射文件,请执行以下操作:

  1. 点击 Load Proguard Mappings
  2. 导航到包含映射文件的项目文件夹,然后加载所有文件、文件的任意组合或包含文件的文件夹

映射文件通常位于 project/app/build/outputs/mappings/release/。如果文件选择器检测到此项目结构,会默认选择 release 文件夹。首先,文件选择器会检查与 mapping.txtseeds.txtusage.txt 完全匹配的文件名。接下来,文件选择器会检查在任意位置包含文本 mappingusageseeds 且以 .txt 结尾的文件名。例如,release-seeds-1.10.15.txt 就是一个匹配项。

Gradle 翻译 Analyzer APK文件分析 [MD]

Gradle 翻译 Analyzer APK文件分析 [MD]

以下列表介绍了映射文件:

  • seeds.txt:Proguard 配置阻止在压缩过程中移除的节点以粗体显示
  • mapping.txt:启用 Deobfuscate names(点击 Gradle 翻译 Analyzer APK文件分析 [MD] 图标),以便恢复由 Proguard 进行了混淆处理的节点的原始名称。例如,您可以将 abc 之类进行了混淆处理的节点名称恢复为 MyClassMainActivitymyMethod()
  • usage.txt:启用 Show removed nodes(点击 Gradle 翻译 Analyzer APK文件分析 [MD] 图标),以便显示 Proguard 在压缩过程中移除的类、方法和字段。恢复的节点带删除线

例如以下工程中,MainActivity、SecondActivity是不被混淆的类(以粗体显示),OtherClass为未被使用、会被移除的类(带删除线),OtherClass为会被混淆的类:

Gradle 翻译 Analyzer APK文件分析 [MD]

反混淆前:
Gradle 翻译 Analyzer APK文件分析 [MD]

反混淆后:
Gradle 翻译 Analyzer APK文件分析 [MD]

如需详细了解如何使用 Proguard 对代码进行混淆处理并最大限度地减小其大小,请参阅 压缩代码和资源

显示字节码,查找用法,生成Keep规则

[Show bytecode, find usages, and generate Keep rule]

Class 列表视图中的节点具有一个上下文菜单,其中包含以下选项,可用于查看字节码、查找用法以及显示一个对话框(其中显示了您可以为选定节点复制并粘贴的 Proguard 规则)。右键点击 Class 列表视图中的任意节点即可显示其上下文菜单。

Gradle 翻译 Analyzer APK文件分析 [MD]

Show bytecode:对选定的类、方法或字段进行反编译,并在对话框中显示 smali 字节码(而不是 Java 代码)表示形式,如下所示:

.class public Lcom/bqt/lock/MainActivity;
.super Landroid/support/v4/app/FragmentActivity;
.source "MainActivity.java"


# static fields
.field private static final REQUEST_PACKAGE_USAGE_STATS:I = 0x44d


# direct methods
.method public constructor <init>()V
    .registers 1

    .line 18
    invoke-direct {p0}, Landroid/support/v4/app/FragmentActivity;-><init>()V

    return-void
.end method

原始代码:

public void a() {
    System.out.println("GoodBye");
}

对应的 smali 字节码:

.method public a()V
    .registers 3

    sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;

    const-string v1, "GoodBye"

    invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V

    return-void
.end method

Find usages:显示 DEX 代码的哪些其他部分对选定的类或方法进行了引用(图 7)。如果加载了 seeds.txt,以粗体显示的节点表示 Proguard 配置阻止在压缩过程中移除这些节点:

Gradle 翻译 Analyzer APK文件分析 [MD]

Gradle 翻译 Analyzer APK文件分析 [MD]

Gradle 翻译 Analyzer APK文件分析 [MD]

Generate Proguard Keep rule:显示您可以复制并粘贴到项目 Proguard 配置文件中的 Proguard 规则,这些规则可阻止在 Proguard 压缩阶段移除给定的软件包、类、方法或字段(图 8)。如需了解详情,请参阅 自定义要保留的代码

例如对于 OtherClass2,在弹窗中生成的信息为:

# Add *one* of the following rules to your Proguard configuration file.
# Alternatively作为选择, you can annotate classes and class members with @android.support.annotation.Keep

# keep the 【class and specified members】 from being removed or renamed 类和类成员不可以被移除也不可以被重命名
-keep class com.bqt.test.OtherClass2 { *; }

# keep the 【specified class members】 from being removed or renamed only if the class is preserved
-keepclassmembers class com.bqt.test.OtherClass2 { *; }

# keep the 【class and specified members】 from being 【renamed】 only 类和类成员不可以被重命名,但可以被移除
-keepnames class com.bqt.test.OtherClass2 { *; }

# keep the 【specified class members】 from being 【renamed】 only 类成员不可以被重命名,但可以被移除
-keepclassmembernames class com.bqt.test.OtherClass2 { *; }

查看代码和资源实体

各种编译任务会更改 APK 文件中的最终实体。例如,Proguard 压缩规则可以改变您的最终代码,而图片资源可以由 product-flavors 中的资源替换。使用 APK 分析器可以轻松查看文件的最终版本:只需点击相应实体,下方便会显示文本或图片实体的预览,如图 9 所示。

Gradle 翻译 Analyzer APK文件分析 [MD]

APK 分析器还可以显示各种文本和二进制文件。例如,在 resources.arsc 实体查看器中,您可以查看配置专用的值,如字符串资源的语言翻译。在图 10 中,您可以看到每个字符串资源的翻译。

Gradle 翻译 Analyzer APK文件分析 [MD]

Gradle 翻译 Analyzer APK文件分析 [MD]

Gradle 翻译 Analyzer APK文件分析 [MD]

Gradle 翻译 Analyzer APK文件分析 [MD]

PS:如果你没有设置不同语言下的值,则只有 default 列有值,其他类没有值。

Gradle 翻译 Analyzer APK文件分析 [MD]

比较APK文件

APK 分析器可以比较两个不同 APK 文件中的实体大小。当您需要了解为什么您的应用较之先前版本有所增大时,这非常有用。在发布经过更新的 APK 之前,请执行以下操作:

  1. 将要发布的 APK 版本加载到 APK 分析器中。
  2. 点击 APK 分析器右上角的 Compare With
  3. 在选择对话框中,找到上次发布给用户的 APK,然后点击 OK

此时将显示一个类似于图 11 中的对话框,帮助您评估更新可能会对用户产生的影响。

Gradle 翻译 Analyzer APK文件分析 [MD]

图 11 显示了特定应用的调试版本和发布版本之间的差异。这两种版本类型使用不同的编译选项,因而会以不同的方式改变底层实体。

2019-10-20

相关文章: