本章介绍的内容适合绝大多数应用。都是关于如何保持你的代码整洁、检测你的依赖库并告诉你使用那些工具来完成这项任务。
第一步就是启用内置的混淆工具。该工具会尝试删除任何没用到的类和函数,并使用更短的名字来重命名各种标识符(类名字、函数名字、变量名字等)。这两种手段都会使最终生成的代码更小,但是后一种手段会使调试起来相当麻烦,所以建议你只在发布版本的时候,启用该功能:
build.gradle 配置如下:
Java
android { ... buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } }
android { ... buildTypes { release { minifyEnabledtrue proguardFilesgetDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } }
proguardFiles 配置了混淆规则文件。第一个文件包含在 SDK 中,里面包含了一些通用的安卓项目默认配置。查看该文件可以帮助你熟悉 proguard 的配置文件语法。例如 如下的配置保留了所有 View 之类中的 setter 和 getter 函数不被混淆:
Java
# keep setters in Views so that animations can still work. # see http://proguard.sourceforge.net/manual/examples.html#beans -keepclassmembers public class * extends android.view.View { void set*(***); *** get*(); }
# keepsettersin Viewssothatanimationscanstillwork. # seehttp://proguard.sourceforge.net/manual/examples.html#beans -keepclassmemberspublic class * extends android.view.View { void set*(***); *** get*(); }
少数情况下,你的应用不需要额外的配置即可使用该功能。在 build 过程中, AAPT 工具也会保留 Manifest 中所应用的 activity 、service 等组件的名字不被混淆。库项目可以使用 consumer Proguard 文件 来指定所使用的规则,并且在每个库项目网站上通过会告诉你该如何配置混淆规则,这种情况下,你只需要把这些规则复制到你的 app/proguard-rules.pro 文件中即可。
通常情况下,启用混淆后可能你的应用汇遇到编译或者运行时问题,例如 ClassNotFoundException 异常。要解决该问题,你需要在你的 app/proguard-rules.pro 中添加异常所显示的类或者函数。如果你使用了反射,则还需要保留这些反射的函数和类。
有些情况是在 xml 布局文件中通过 String 来引用一个类,如果该类名字被混淆了,则就会出现 ClassNotFoundException 异常。例如如下示例:
Java
<android.support.v7.widget.RecyclerView app:layoutManager=”android.support.v7.widget.GridLayoutManager” ... />
<android.support.v7.widget.RecyclerView app:layoutManager=”android.support.v7.widget.GridLayoutManager” ... />
这种情况下, AAPT 工具目前还没有这么智能,它不知道需要保留 GridLayoutManager 类,所以需要你自己添加该规则。要解决该问题,只需要在你的 app/proguard-rules.pro 中添加如下内容即可:
Java
-keep public class android.support.v7.widget.GridLayoutManager { public protected *; }
-keeppublic class android.support.v7.widget.GridLayoutManager { public protected *; }
要检查你的配置是否有用,则可以使用 ClassyShark 工具或者类似的其他工具来查看生成 apk 文件中的 classes.dex 文件。 并且还需要测试你的应用来确保是否有效 。 应用不崩溃并不能保证配置就是正确的,你必须测试所有的页面和所有的使用流程来确保混淆是没问题的。你也可以使 用安卓测试工具 来帮助你测试你的应用。
如果你在 Google Play 发布应用,你可以把你的 ProGuard mappings 文件上传到 Google play,这样当有异常发生的时候, Google Play 可以跟进 ProGuard mappings 文件还原异常堆栈信息帮助你定位 bug。
mappings 文件位于
如果你不适用 Google play,其他统计工具也包含该功能。比如友盟统计就支持上传该文件。
如果你在创建一个用于其他项目的 AAR 库。你应该在库项目中使用 consumerProguardFiles 选项来配置所使用的 ProGuard 配置文件。通过这种方式可以把 ProGuard 配置文件打包到 AAR 中。这样当使用该 库的时候,就不用手工再配置一次了。
build.gradle
Java
android { ... defaultConfig { consumerProguardFiles “proguard-rules.txt” } }
android { ... defaultConfig { consumerProguardFiles “proguard-rules.txt” } }
如果你使用了 Google Play Services 库,则你一定知道 Google Play Services 包含了几十个不同的功能,比如 定位、账号登录、应用统计、广告 、谷歌地图、翻译 等功能。如果你只需要其中的一个或者几个功能,则可以在 gradle 配置依赖项的时候,只选择需要使用的功能,这样其他不需要使用的功能代码就不会打包到你的 apk 中。详细情况参考 developers.google.com 。
开发安卓应用的好处之一是:如果你遇到了一个问题,所不定早就有人已经遇到该问题了。通过 谷歌 搜索,你很容易的发现该问题的解决方式。所以我们在开发项目的时候会使用各种第三方类库来提高开发效率。最长用的一个库可能就是 Android Support 库了,当然还有图片加载、网络请求等常用类库。
码农们常常问我:我应该使用哪个图片加载库呢?我的项目是否使用太多的第三方库了呢?这类问题没有确定的答案。如果你需要使用第三方库来解决你的问题并且你也知道该第三方库具有哪些限制,则使用吧。 你需要知道使用每个库对你项目的影响。
当你认为你只添加了一个很小的第三方库,但是突然你的 dex 文件增大了很多。则可能是该库依赖了其他的库导致的。幸运的是,有个工具可以帮助我们:
Java
$ ./gradlew app:dependencies ... compile — Classpath for compiling the main sources. + — — com.android.support:appcompat-v7:23.1.1 | / — — com.android.support:support-v4:23.1.1 | / — — com.android.support:support-annotations:23.1.1 + — — com.android.support:cardview-v7:23.1.1 + — — com.android.support:design:23.1.1 | + — — com.android.support:appcompat-v7:23.1.1 (*) | + — — com.android.support:recyclerview-v7:23.1.1 | | + — — com.android.support:support-annotations:23.1.1 | | / — — com.android.support:support-v4:23.1.1 (*) | / — — com.android.support:support-v4:23.1.1 (*) + — — com.android.support:recyclerview-v7:23.1.1 (*) / — — com.android.support.test.espresso:espresso-idling-resource:2.2.1
$ ./gradlewapp:dependencies ... compile — Classpathfor compilingthemainsources. + — — com.android.support:appcompat-v7:23.1.1 | / — — com.android.support:support-v4:23.1.1 | / — — com.android.support:support-annotations:23.1.1 + — — com.android.support:cardview-v7:23.1.1 + — — com.android.support:design:23.1.1 | + — — com.android.support:appcompat-v7:23.1.1 (*) | + — — com.android.support:recyclerview-v7:23.1.1 | | + — — com.android.support:support-annotations:23.1.1 | | / — — com.android.support:support-v4:23.1.1 (*) | / — — com.android.support:support-v4:23.1.1 (*) + — — com.android.support:recyclerview-v7:23.1.1 (*) / — — com.android.support.test.espresso:espresso-idling-resource:2.2.1
:dependencies 命令 可以让你查看每个项目中的所有依赖库。版本号旁边的 星号 (*) 告诉你该依赖项已经被使用过了,最终会包含到你的 dex 文件中, 除非你手动的删除该库的所有引用。
如果你使用了product flavors,一些库只在一种 flavor 上使用(例如 只有免费版本有广告 SDK),你可以用你的 flavor 名字作为依赖项的前缀,例如 { freeCompile ‘…’ }.
ClassyShark 可以查看 apk 中的 dex 文件,这样可以看看编译后的 dex 中都包含哪些类,同时该工具还显示了每个包里面有多少个函数。