如何使用Proguard缩小Android代码 [英] How do I shrink Android code with Proguard

查看:84
本文介绍了如何使用Proguard缩小Android代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Since I am using many dependencies in my app, I am reaching the 65k Method Limit (I am reaching 76k methods). I've read on android.developer that proguard is used to shrink the code.

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

So - does proguard only shrink my application code or does it shrink the code of my dependencies too? Do I need to be wary of something when shrinking code with proguard? How do I do that?

我的Gradle版本:

My 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'
}

推荐答案

TL; DR:反转您的-keep选项,除非您 遇到麻烦

TL; DR: invert your -keep option unless you love troubles

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

Firstly: I believe, that you are making right choice by using Proguard to overcome the dex limitation. I would not recommend using multidex support library under any circumstances: it introduces problem of multiple classloaders in your application, and that may backfire in many non-obvious ways.

这是我个人有效地缩小应用范围的方法:

Here is my personal approach to shrinking the app efficiently:

  • 选择您拥有的两个最大的第三方依赖项;
  • 检查那些是否真的支持Proguard;
  • 如果这样做,请使用Proguard缩小它们;
  • 如果您仍然无法满足最大方法数量的要求,请对剩余的某些依赖项执行上述步骤;
  • 如果您仍然不适合,可能会重新评估一些内容,表示不支持Proguard,请阅读他们的源代码以更好地了解为什么他们不,并亲自将Proguard应用于他们;
  • 在最坏的情况下,将Proguard应用于您自己的代码;
  • 如果以上绝对没有帮助,请使用multidex.
  • Pick a couple of hugest third-party dependencies you have;
  • Check if those really support Proguard;
  • If they do, shrink them with Proguard;
  • If you still don't fit in maximum method count, do steps above for some of remaining dependencies;
  • If you still don't fit, possibly reevaluate some, that do not support Proguard, possibly read their source code to get better idea why they don't, and apply Proguard to them yourself;
  • In the worst case, apply Proguard to your own code;
  • If absolutely nothing of above helps, use multidex.

在您的情况下,首先没有太多(直接)依赖项.您可能希望查看gradlew dependencies的输出,以更好地了解间接依赖关系,其中一些可能是导致应用程序总大小的最大因素.然后,您可以继续使用 Android Arsenal 的"Dex"部分中列出的一些工具来了解哪些库对dex方法计数贡献最大.您似乎已经对此有了一个大致的了解,所以在这一部分我将不做过多介绍.

In your case, there aren't many (direct) dependencies in the first place. You may want to look at output of gradlew dependencies to get better idea of your indirect dependencies, some of which may be biggest contributors to total app size. Then you may proceed to use some of tools listed in "Dex" section of Android Arsenal to learn which libraries contribute most to dex method count. You seem to already have a general idea of it, so I won't dwell much on this part.

请记住:缩减可执行代码对库内部而言并非是不平凡的干预,因此您宁愿减少压缩量,以避免将来出现神秘问题.如有疑问,请从公开声明它们正式支持Proguard的库开始(在您的情况下为Android支持库).

Remember: shrinking executable code is somewhat non-trivial intervention in library internals, so you'd rather shrink less to avoid mysterious problems in future. If in doubt, start from libraries, that openly declare, that they do support Proguard officially (in your case that would be Android Support libraries).

请注意,支持Proguard"对于不同的开发人员可能意味着不同的含义.您可以期望Android支持库开发人员至少具有基本的能力,但是许多其他人将附带消费者Proguard规则,如下所示:

Note, that "supporting Proguard" may mean different things for different developers. You can expect Android Support Library developers to be at least basically competent, but many others will ship with consumer Proguard rules like this:

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

以防万一,上述配置基于许多实际配置,例如

In case you wonder, the above config is based upon many real-life configs, such as Square's Leak Canary Proguard configuration. It does not say anything about overall competency of developers in question, just reminder that using Proguard can be hard. And yes, this kind of configuration will completely prevent shrinking and obfuscation of the library, unless you build it's local copy from source code and remove such helpful consumer-proguard-rules.pro from there.

如上所示,即使是经验丰富的开发人员有时也会选择忽略Proguard.如果Google搜索有关该库的内容,并且它与Proguard的兼容性没有任何回报(即使他们 do 返回了一些结果!),您可能必须对使用Proguard做出自己的判断.这是我个人的做法:

As shown above, even experienced developers sometimes choose to ignore Proguard. If Google searches regarding the library and it's compatibility with Proguard return nothing (and even if they do return some results!) you may have to make your own judgement regarding usage of Proguard. Here is how I personally do:

  • 如果图书馆站点上的任何地方都有框架",企业",反射"一词,则可能与Proguard的兼容性不佳;
  • 如果该库与编译时代码生成(a-la Buttknife,Dagger等)有关,请在使用Proguard之前三思;
  • 如果该库与JNI混淆,请在使用Proguard之前再考虑几次,Google也会对Proguard产生影响即使您不收缩该库本身;
  • 如果有疑问,Google会为此和/或阅读库源代码:Class.forName以及Proxy.getInvocationHandler和类似的反射代码的使用通常是不好的迹象.
  • If there are words "framework", "enterprise", "reflection" anywhere on the library site, it is likely to be poorly compatible with Proguard;
  • If the library has anything to do with compile-time code generation (a-la Butterknife, Dagger etc.), think twice before using Proguard;
  • If the library messes with JNI, think a couple more times before using Proguard on it, and Google for it's effects on Proguard even if you don't shrink the library itself;
  • If in doubt, Google for it and/or read library source code: usage of Class.forName as well as Proxy.getInvocationHandler and similar reflection code are usual bad signs.

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

Libraries, that offer Android UI components (such as MPAndroidChart) are usually ok to shrink, at least if you keep getDefaultProguardFile('proguard-android.txt') in your Gradle config.

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

A lot of developers (including Proguard developers themselves!) will offer you a misguided recommendation to start from empty Proguard config + default Android Proguard configuration, and eventually add -keep rules when necessary.

不要这样做!

这些建议来自人们,他们要么太笨拙,无法理解普通开发人员的问题(请阅读:"Proguard开发人员本人"),要么对正确使用Proguard毫无头绪.实际上,这些错误的做法是正当的原因,为什么这个问题的许多答案警告您不要使用Proguard:这是默认行为,就像建议某人从扩展Everest来开始登山.

Those advices come from people, who are either too badass to understand problem of average developer (read: "the Proguard developer himself") or don't have a clue about using Proguard properly. In fact, these kind of misguided practices are the very reason, why many answers to this question warn you against using Proguard: it's default behavior is like suggesting someone to start mountaineering from scaling the Everest.

默认的Proguard配置将混淆,缩小和优化所有内容-您的整个应用程序具有所有依赖关系,但您明确排除的某些类除外.除非您对项目中的每个库和代码行都有绝对的了解,否则您将不会想要它们:它们如何工作和相互交互,内部使用哪些技术等.

Default Proguard configuration will obfuscate, shrink and optimize everything—your entire application with all dependencies except some classes you explicitly exclude. You don't want that, unless you have absolute understanding of every library and line of code in your projects: how they work and interact with each other, which techniques they internally use etc.

相反,您希望在最小可能范围(很少有最大的库)中进行最小的必要干预(缩减代码以减少dex方法的数量),并且后果最小(仅在确定Proguard有效的情况下).这是我针对此类情况的Proguard配置:

Instead you want to do the minimal necessary intervention (shrinking the code to reduce dex method count) in the minimal possible range (few hugest libraries) with minimal consequences (only where Proguard is known to work for sure). Here is my Proguard config for such cases:

-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 class !com.android.support.**,!com.google.android.**,** { *; }

将上述规则添加到应用程序的proguard-rules.pro中,它们将仅收缩您明确允许收缩的类.将其他可安全收缩的软件包的通配符(与上述完全相同-带有!.**部分)添加到-keep行的开头.

Add the above rules to your app's proguard-rules.pro, they will shrink only classes, that you explicitly allow to shrink. Append wildcards for other safely shrinkable packages (exactly as above—with ! and .** parts) to beginning of the -keep line.

这篇关于如何使用Proguard缩小Android代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆