如何使用Proguard缩小Android代码

时间:2015-07-19 23:56:36

标签: android android-proguard dex-limit

由于我在我的应用程序中使用了很多依赖项,因此我达到了65k方法限制(我达到了76k方法)。我在android.developer上读过,proguard用于缩小代码。

那么 - proguard只会缩小我的应用程序代码还是缩小我的依赖项代码呢?使用proguard缩小代码时,是否需要警惕某些事情?我该怎么做?

我的Gradle Build:

apply plugin: 'com.android.application'

android {
compileSdkVersion 21
buildToolsVersion "21.1.2"

defaultConfig {
    applicationId "some.Path"
    minSdkVersion 15
    targetSdkVersion 21
    versionCode 1
    versionName "1.0"
}

packagingOptions {
    exclude 'META-INF/DEPENDENCIES'
    exclude 'META-INF/NOTICE'
    exclude 'META-INF/NOTICE.txt'
    exclude 'META-INF/LICENSE'
    exclude 'META-INF/LICENSE.txt'
}

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

configurations {
compile.exclude group:  'org.apache.xmlbeans'
}

repositories {
maven { url "https://jitpack.io" }
}

dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:appcompat-v7:21.0.3'
compile 'com.github.PhilJay:MPAndroidChart:v2.1.0'
compile 'com.opencsv:opencsv:3.4'
compile 'org.apache.poi:poi:3.12'
compile 'org.apache.poi:poi-ooxml:3.12'
}

6 个答案:

答案 0 :(得分:11)

<强> TL; DR:反转您的-keep选项,除非您 麻烦

首先:我相信,通过使用Proguard来克服dex限制,你正在做出正确的选择。在任何情况下我都不建议使用multidex支持库:它会在您的应用程序中引入多个类加载器的问题,并且可能会以许多非显而易见的方式适得其反。

以下是我个人有效缩小应用程序的方法:

  • 选择几个最大的第三方依赖项;
  • 检查那些是否支持Proguard;
  • 如果他们这样做,请用Proguard缩小它们;
  • 如果您仍然不适合最大方法计数,请执行以上步骤以了解其余一些依赖项;
  • 如果你仍然不适合,可能会重新评估一些支持Proguard,可能会阅读他们的源代码以更好地了解他们为什么不< / em>,并自己申请Proguard;
  • 在最坏的情况下,将Proguard应用于您自己的代码;
  • 如果上述内容完全无效,请使用multidex。

选择收缩的依赖关系

在您的情况下,首先没有很多(直接)依赖关系。您可能希望查看gradlew dependencies的输出以更好地了解您的间接依赖关系,其中一些可能是应用程序总大小的最大贡献者。然后你可以继续使用&#34; Dex&#34;中列出的一些工具。 Android Arsenal的一节,以了解哪些库对dex方法计数贡献最大。你似乎已经对它有了一个大概的想法,所以我不太关注这一部分。

请记住:缩小的可执行代码在库内部进行了一些非平凡的干预,因此您可以减少收缩以避免将来出现神秘问题。如果有疑问,请从公开声明的图书馆开始,他们正式支持Proguard(在您的情况下,这将是Android支持库)。

注意,&#34;支持Proguard&#34;可能对不同的开发者来说意味着不同您可以期待Android支持库开发人员至少基本上能够胜任,但许多其他人将提供这样的消费者Proguard规则:

-keep class com.example.library.** { *; }

如果你想知道,上面的配置基于许多现实配置,例如Square's Leak Canary Proguard配置。它没有说明有关开发人员的整体能力,只是提醒说使用Proguard可能 hard 。是的,这种配置将完全防止库的缩小和混淆,除非您从源代码构建它的本地副本并从那里删除这样的有用的 consumer-proguard-rules.pro。 / p>

评估Proguard的依赖关系

如上所示,即使是经验丰富的开发人员有时也会选择忽略Proguard。如果谷歌搜索图书馆并且它与Proguard的兼容性没有任何回报(即使他们返回一些结果!),您可能必须自己判断Proguard的使用情况。以下是我个人的做法:

  • 如果有词语&#34;框架&#34;,&#34;企业&#34;,&#34;反思&#34;在图书馆网站的任何地方,它很可能与Proguard不兼容;
  • 如果库与编译时代码生成有关(a-la Butterknife,Dagger等),请在使用Proguard前三思而后行;
  • 如果图书馆与JNI混淆,那么在使用Proguard之前多想几次,并考虑Google对Proguard 的影响,即使你不缩小图书馆本身
  • 如果有疑问,谷歌会为它和/或阅读库源代码:使用Class.forName以及Proxy.getInvocationHandler和类似的反射代码通常是不好的迹象。

提供Android UI组件(例如MPAndroidChart)的库通常可以缩小,至少如果你在Gradle配置中保留getDefaultProguardFile('proguard-android.txt')

最重要的部分

许多开发人员(包括Proguard开发人员本身!)将为您提供误导的建议,从空的Proguard配置+默认Android Proguard配置开始,并在必要时最终添加-keep规则。

请勿这样做!

这些建议来自人们,他们要么太难以理解普通开发人员的问题(阅读:&#34; Proguard开发人员自己&#34;)或者没有关于正确使用Proguard的线索。事实上,这种被误导的做法就是这个问题的原因,为什么这个问题的许多答案都警告你不要使用Proguard:它的默认行为就像是建议某人开始登山以扩展珠穆朗玛峰。

默认的Proguard配置将模糊,缩小和优化所有内容 - 除了您明确排除的某些类之外的所有依赖项。除非您对项目中的每个库和代码行有绝对理解:它们如何工作以及如何相互交互,内部使用哪些技术等等,否则您不希望这样。

相反,您希望在尽可能小的范围内(几个最大的库)进行最小限度的必要干预(缩小代码以减少dex方法计数),并且结果最小(只有在已知Proguard工作的情况下)。以下是我的Proguard配置:

-dontoptimize
-dontobfuscate

# Prints some helpful hints, always add this option
-verbose

-keepattributes SourceFile,LineNumberTable,Exceptions,InnerClasses,Signature,Deprecated,*Annotation*,EnclosingMethod


# add all known-to-be-safely-shrinkable classes to the beginning of line below
-keep !com.android.support.**,!com.google.android.**,** { *; }

将上述规则添加到您应用的proguard-rules.pro,它们只会缩小您明确允许缩小的类。为其他安全可收缩的软件包添加通配符(完全如上所述 - !.**部分)到-keep行的开头。

答案 1 :(得分:1)

作为ProGuard的替代方案,您可以通过关闭ProGuard来使用built-in Gradle shrinker,但仍然可以参考ProGuard配置。这将删除未使用的代码,但不会混淆或做任何其他“魔术”。虽然建议仅用于Debug版本,但我不明白为什么你不能将它用于Release版本,如果你不认为你需要混淆。

与ProGuard(在我看来)相比,主要的好处是可以避免ProGuard配置与代码库结构和第三方依赖关系之间的紧密耦合。

build.gradle:

minifyEnabled true
useProguard false
proguardFiles ('proguard-basic.pro', getDefaultProguardFile('proguard-android.txt'))

proguard-basic.pro:

-dontwarn javax.**
-keep class com.mycompany.** { *; }

答案 2 :(得分:0)

如果您通过ProGuard启用缩小功能,它还会缩小您的依赖关系。

ProGuard通常不会对库进行混淆/缩小。如果对它们进行模糊处理,默认情况下某些库将无法正常工作,因此您应该检查用于查看是否有任何有关ProGuard的文档的库。例如,Butterknife有一些特殊的ProGuard规则,您需要包含这些规则以确保其继续正常工作。

答案 3 :(得分:0)

对我来说,你应该寻找multidex,超过65k的限制,而不是像长跑一样,后者不是你的问题的解决方案。

请参阅文档:https://developer.android.com/tools/building/multidex.html

答案 4 :(得分:0)

如果在build.grade文件中启用缩小,那么它也会缩小您的依赖项。

请记住,Proguard可能会引入不必要的副作用。并不是所有的库/依赖都可以缩小,因为Proguard也会混淆代码。 (即将String name转换为String n)并删除未使用的代码。

看看这个Github项目:https://github.com/krschultz/android-proguard-snippets

作为替代方案,您可以考虑使用MultiDex。您可以在此处阅读:https://developer.android.com/tools/building/multidex.html

答案 5 :(得分:0)

根据3.2版中新的Android Studio更新,新代码收缩器也会通过将以下行添加到项目的 gradle.properties 文件

中来进行模糊处理

添加此行:

android.enableR8 = true