一、概述
这几天要打包APK给测试,但是一打包发现APK包有23M,经理那边自然过不了,所以就开始琢磨怎么减小APK的大小。分析原因:
1. 由于UI是按照模块给的切图,所以部分模块的切图可能存在重复,不过这种情况不多,所以对apk的大小影响不大。如果想通过减少图片来减小apk的大小,那么建议只做一套切图,单独适应xhdpi的。
2. 如果不需要做国际化,建议指定只支持中文的
defaultConfig {
resConfigs "zh"
}
3. 我们的app中部分用到了h5,而h5的代码是存放到assets目录下,这个目录下的文件打包的时候是不会被压缩的,所以这个目录下的文件有多大,打包之后apk就会增加多大。目前关于h5的资源代码等还不知道怎么压缩处理,各位大神有什么好的方法请教一下。
4. 这个就是重点了,android studio默认build.gradle里面配置的 minifyEnable false,这表示是不混淆,起不到防反编译的作用。
二、配置 build.gradle 文件
1. 修改配置:
buildTypes { release { minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } debug{ minifyEnabled false shrinkResources true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } }其中release{}指的是发布版本,也就是通过android studio工具栏中Build生成的apk;debug{}指的是调试版本,也就是通过adb连接设备直接运行生成的apk。minifyEnabled表示是否启动代码混淆,shrinkResources表示是否删除代码中无用的resource文件。
注意:想要让 shrinkResources true 生效,就必须设置 minityEnabled true。否则就算shrinkResources true,而minifyEnabled fale,那么还是不会起到作用。
proguardFiles指定的是混淆的配置文件。
三、修改混淆配置文件 proguard-rules.pro
-optimizationpasses 5 # 指定代码的压缩级别0-7 -dontusemixedcaseclassnames # 是否使用大小写混合 -dontpreverify # 混淆时是否做预校验 -verbose # 混淆时是否记录日志 -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* # 混淆时所采用的算法 # 保持 AndroidManifext.xml 文件里面注册的组件不被混淆 -keep public class * extends android.app.Fragment -keep public class * extends android.app.Activity -keep public class * extends android.app.Application -keep public class * extends android.app.Service -keep public class * extends android.content.BroadcastReceiver -keep public class * extends android.content.ContentProvider -keep public class * extends android.app.backup.BackupAgentHelper -keep public class * extends android.preference.Preference -keep public class com.android.vending.licensing.ILicensingService -keep public class * extends android.support.v4.** -keep public class * extends android.support.v7.**#注解不被混淆-keepattributes *Annotation*#泛型不被混淆
-keepattributes Signature#如果引用了v4或者v7包-dontwarn android.support.**-keep class android.support.v4.**{*;}#保持 native 方法不被混淆(jni)-keepclasseswithmembernames class * { native <methods>;}#保持 Parcelable 不被混淆-keep class * implements android.os.Parcelable { public static final android.os.Parcelable$Creator *;}#保持 Serializable 不被混淆-keepnames class * implements java.io.Serializable-keepclassmembers class * implements java.io.Serializable { static final long serialVersionUID; private static final java.io.ObjectStreamField[] serialPersistentFields; !static !transient <fields>; !private <fields>; !private <methods>; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve(); }-keepclassmembers class * { public void *ButtonClicked(android.view.View);}#不混淆资源类-keepclassmembers class **.R$* { public static <fields>;}# 保持枚举 enum 类不被混淆 -keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); }
# 保持自定义控件类不被混淆-keepclasseswithmembers class * { public <init>(android.content.Context, android.util.AttributeSet);}#保持自定义控件类不被混淆-keepclassmembers class * extends android.app.Activity { public void *(android.view.View);}-keep public class * extends android.view.View { public <init>(android.content.Context); public <init>(android.content.Context, android.util.AttributeSet); public <init>(android.content.Context, android.util.AttributeSet, int); public void set*(...);}
一般我们的项目中都会用到第三方的框架,这个也是要配置,否则会报各种异常,通常情况下,瞎子第三方jar的时候都有教怎么配置的,例如:
Gson的配置:
#-------------- Gson------------------------ -keep class com.google.gson.stream.** { *; } -keepattributes EnclosingMethod #反射不混淆 #这是你定义的实体类(gson解析会通过反射的方式得到bean类) -keep class 包名.**{*;}okhttputils的配置:
#okhttp -dontwarn okhttp3.** -keep class okhttp3.**{*;} #okio -dontwarn okio.** -keep class okio.**{*;}
对于webview的混淆问题:
#解决webview和js的交互问题(#后面的是内部,JSLoadNative是js调用android的接口) -keepclassmembers class 包名.BaseActivity$JSLoadNative { public *; } -keepattributes JavascriptInterface
四、总结
1. Android 混淆原则:
反射用到的类不混淆
JNI方法不混淆
AndroidMainfest中的类不混淆,四大组件和Application的子类和Framework层下所有的类默认不会进行混淆
Parcelable的子类和Creator静态成员变量不混淆,否则会产生android.os.BadParcelableException异常
使用GSON、fastjson等框架时,所写的JSON对象类不混淆,否则无法将JSON解析成对应的对象
使用第三方开源库或者引用其他第三方的SDK包时,需要在混淆文件中加入对应的混淆规则
有用到WEBView的JS调用也需要保证写的接口方法不混淆
2. 混淆小技巧:
对于第三方的jar包直接照着提供的修改
对于有的类找不到,就直接-keep掉,然后再运行修改
build.gradle文件默认不会配置debug模式,自己添加配置debug模式,这样就可以直接通过adb来调试混淆引起的一些问题了
3. 注意:
eclipse里面是需要 -libraryjars 来导入我们使用到的jar的,但是studio里面就不需要,相反,如果你再次引用打包的时候就会报引用了两次的错误。
这样改了之后,再次打包发现apk比之前小了6M多。