📜  Android 中的 ProGuard

📅  最后修改于: 2022-05-13 01:58:44.249000             🧑  作者: Mango

Android 中的 ProGuard

在为您的 Android 应用程序编写代码时,可能会有一些不必要的代码行,并且可能会增加您的应用程序 APK 的大小。除了无用的代码之外,您可能已经在程序中合并了许多库,但并未使用每个库提供的所有功能。此外,您可能已经开发了一些将来会过时的代码并且未能将其删除。这些因素是导致应用程序 APK 大小增加的原因。 Android 具有 Proguard 功能以最小化 APK 的大小。 ProGuard 是一款适用于 Android 的免费Java应用程序,它允许我们执行以下操作:

  1. 减少(最小化)代码:应该删除项目中未使用的代码。
  2. 代码混淆:重命名类、字段等的名称。
  3. 改进代码:例如内联函数。

综上所述,ProGuard 对我们项目的影响如下:

  1. 它缩小了应用程序的大小。
  2. 它删除了导致 Android 应用程序的 64K 方法计数限制的未使用的类和方法。
  3. 通过混淆代码,很难对应用程序进行逆向工程。

它对我们的应用有何帮助?

Proguard 是在 Android 中创建生产就绪应用程序的绝佳工具。它帮助我们减少代码并使应用程序更快。 Proguard 默认包含在 Android Studio 中,可以通过多种方式提供帮助,下面列出了其中的一些。

  1. 它混淆了代码,这意味着它将名称更改为更小的名称,例如 MainViewModel 的 A。混淆应用程序后,逆向工程变得困难。
  2. 它缩小了资源,忽略了我们的 Class 文件没有调用的资源,没有在我们的 Android 应用程序中使用,例如来自 drawable 的图像等。这将显着减小应用程序的大小。为了让您的应用程序轻巧快速,您应该始终缩小它。

我们应该如何将它应用到我们的项目中?

要在您的项目中启用 Proguard,请构建应用程序,然后在 .gradle 中包含:

buildTypes {
    release {
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}

它在发布块中,所以它只会应用于我们生成的版本的发布。

但是,有时当 proguard 删除太多代码时,它可能会太多,这可能会破坏您的流代码。所以,在配置代码的时候,一定要添加一些自定义的规则,保证这组代码不再混淆。我们可以通过在我们的 proguard 中定义自定义规则来解决这个问题,这些规则将在生成构建时遵循。让我们看看如何在 Proguard 中创建自定义规则。

1.维护类文件

假设我们有一些 API 需要的数据类,但我们通过生成构建来混淆它。例如,我们有一个用户数据类。

Kotlin
data class GFG(val course: String = "")


Kotlin
@Keep
data class GFG(val course: String = "")


Kotlin
data class GFG(@SerializedName("course")
                 val course: String = "")


如果我们不想混淆生成构建的类,可以使用@Keep注解防止混淆,更新代码如下:

科特林

@Keep
data class GFG(val course: String = "")

此注释允许在使用 proguard 缩小时忽略该类。这将使类及其成员函数即使在不使用时也保持活动状态。

我们还可以雇用:

-keep

在生成构建时保留类选项当我们使用 -keep 而不是 @Keep 时,我们可以更好地控制我们保留的内容和不保留的内容。不过我们也可以通过@SerializedName(使用Gson库时)保留数据模型类中id字段的key,如下图。

科特林

data class GFG(@SerializedName("course")
                 val course: String = "")

2. 保留班级成员

如果我们想在收缩时只保留类成员而不是整个类,我们可以使用,

-keepclassmembers

在 proguard 的规则文件中这将允许我们忽略特定类的成员。考虑上面描述的 User 类;我们希望保留它的所有公共方法。我们将规则写成如下:

-keepclassmembers class com.gfg.sample.course
{
    public *;
}

3. 跟踪班级和成员的姓名

假设我们想要保留类的所有相同课程和类的成员(如果它在代码中使用),即如果该类未使用,它将被 proguard 缩小但不会混淆,因为它已经被缩小了并且不需要混淆。我们使用以下工具来完成上述任务:

-keepcourses

4. 使用 Android 中的任何库

在使用任何库时,我们可能想为 proguard 编写一些自定义规则。库可能会在 logcat 中发出警告,或者他们甚至可能没有自己的 proguard 规则!为了纠正这个问题,我们必须向我们的应用程序添加自定义规则。例如,如果我们开始收到来自任何库的警告,我们可以添加:

-dontwarn com.someOtherLib.annotations.*

5. 只使用混淆来隐藏你的项目

考虑一个非常罕见的用例,您只想在不压缩任何资源的情况下混淆代码。这是一个非常罕见的用例,但它可能对一些小型库有用;在这种情况下,我们编写标志如下:

-dontshrink
-dontoptimize

6. 保留注释

ProGuard 在构建应用程序时会删除所有注释,但它可能仍适用于您项目中的某些代码。但是,如果我们不希望删除注释,我们可以选择如下:

-keepattributes *Annotation*

7. 增强

在 ProGuard 中编写了这么多规则之后,我们可能需要为我们的应用程序提供额外的优化层。首先,我们修改build.gradle文件如下:

android {
  buildTypes {
    release {
      proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
    }
  }
}

一般来说,我们不使用此选项,但在这种情况下,我们需要执行额外的优化级别。为了增加优化周期的数量,例如,如果我们要检查优化是否正确完成,如果没有,它将再次优化直到一定次数,我们使用:

-optimizationpasses 10

在这种情况下,它将运行优化多达 10 次,以使其更加优化。考虑以下示例:如果我们想在比以前更细的级别上优化最终类,我们使用,

-optimizations class/marking/final

结论

  1. 作为片段标签,不要使用 MainFragment.class.getSimpleName() 之类的东西。在混淆时,Proguard 可以为不同包中的两个不同片段分配相同的名称(A.class)。在这种情况下,两个片段将具有相同的 TAG。这将导致您的应用程序出现错误。
  2. 保留您的 Proguard 映射文件,以便追溯到原始代码。您可能需要将其上传到不同的位置,例如 PlayStore 控制台,以查看崩溃的原始堆栈跟踪。