First, how to optimize?
1: Identify what needs to be optimized
Using Android APK Analyzer to analyze the size of each part of APK, the size distribution of version 5.1.1 APK is as follows:
The result of the analysis is that three areas need to be optimized
- res(app resources include images and xml resources)
- classes.dex(javac compiled file)
- Introduced third party lib Library
1.1: res optimization
1.1.1 Compression of image resources using TinyPNG
tinypng It is a website that supports compression of png and jpg image formats. Through its unique algorithm (through a technology called "quantization", the 24-bit true color of the original png file is compressed into an 8-bit index demonstration, which is a vector compression method, and the color value is replaced by a numerical value 123, etc.).
In the case of lossless compression, the image file size can be reduced to 30% - 50% of the original size.
TinyPNG is used to compress pictures over 10 KB in size, and the result is that the size of apk is reduced by about 0.6 M.
1.1.2 Use Android lint to clean up unused resources in code
In the project, click Analeze - > Run Inspection by Name... enter unused resources link to analyze the deleted resources by about 0.2M
1.1.3 Retain only Chinese-related resources
Internationalized strings are included in the android support library. The comment manager does not need to support internationalization now, so resources other than Chinese are deleted.
Add defaultConfig closure in builde.gradle file under module:
resConfigs "zh-rCN"
1.1.4 Cleaning of unreferenced resources with shrinkResources in conjunction with ProGuard tools
After the proguard tool deletes members of classes and classes that are not used in the project, some unreferenced resources need to be deleted.
When compiling release version in build.gradle, add shrinkResources true to turn on the function of reducing useless resources
buildTypes { release { shrinkResources true minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' debuggable false jniDebuggable false renderscriptDebuggable false } } |
1.2:class.dex optimization
Custom Proguard rules specify in proguard-rules.pro which classes and members of which classes need to be retained and cannot be deleted and renamed.
The specific rules are as follows:
-ignorewarnings ##Start - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -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 ##End------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ##start---------------------------Context----------------------------------------------------------- -keepclassmembers class * extends android.content.Context { public void *(android.view.View); public void *(android.view.MenuItem); } ##end-----------------------------Context----------------------------------------------------------- ##start - -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); } ##end - ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ##start - -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -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 *** set*(...); public *** get*(...); } -keepclasseswithmembers class * { public <init>(android.content.Context, android.util.AttributeSet); } -keepclasseswithmembers class * { public <init>(android.content.Context, android.util.AttributeSet, int); } ##end - ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ##Start - ----------------------------------------------- Native method - ------------------------------------------------------------------------------------------------------------------------------ -keepclasseswithmembernames,includedescriptorclasses class * { native <methods>; } -keepclasseswithmembernames class * { native <methods>; } ##End - --------------------------------------------------- Native method - ---------------------------------------------------------------------------------------------------------------------------- ##Parcelable CREATOR variable - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -keepclassmembers class * implements android.os.Parcelable { static ** CREATOR; } -keepclassmembers class * implements android.os.Parcelable { public static final android.os.Parcelable$Creator CREATOR; } ##Parcelable CREATOR variable - --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ##start-----------------------------Serializable---------------------------------------------------- #Keep Serializable unambiguous -keepnames class * implements java.io.Serializable #Keep Serializable unambiguous and enum classes unambiguous -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(); } ##end--------------------------------Serializable--------------------------------------------------- ##Start - -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -keep class **.R$* { public static <fields>; } -keep class **.R ##End - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ##start-----------------------------EventBus-------------------------------------------------------- -keepclassmembers class ** { @org.greenrobot.eventbus.Subscribe <methods>; } -keep enum org.greenrobot.eventbus.ThreadMode { *; } -keep class de.greenrobot.event.** {*;} -keepclassmembers class ** { public void onEvent*(**); void onEvent*(**); } ##end-------------------------------EventBus-------------------------------------------------------- ##start - ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -keep class android.support.annotation.Keep -keep @android.support.annotation.Keep class * {*;} -keepclasseswithmembers class * { @android.support.annotation.Keep <methods>; } -keepclasseswithmembers class * { @android.support.annotation.Keep <fields>; } -keepclasseswithmembers class * { @android.support.annotation.Keep <init>(...); } ##end - ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ##start------------------------------alipapy-------------------------------------------------------- #paysdk-alipay (actual test, not Alipay's keep can also be paid by Alipay. But write it according to the Alipay document. -keep class com.alipay.android.app.IAlixPay{*;} -keep class com.alipay.android.app.IAlixPay$Stub{*;} -keep class com.alipay.android.app.IRemoteServiceCallback{*;} -keep class com.alipay.android.app.IRemoteServiceCallback$Stub{*;} -keep class com.alipay.sdk.app.PayTask{ public *;} -keep class com.alipay.sdk.app.AuthTask{ public *;} ##end--------------------------------alipay--------------------------------------------------------- ##Unconfused generics -keepattributes Signature ##No confusion of annotations -keepattributes *Annotation* ##Keep the line number of the code when throwing an exception. It is easy to locate in exception analysis. -keepattributes SourceFile,LineNumberTable ##End - -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ##Huawei push - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -keep class com.huawei.android.pushagent.**{*;} -keep class com.huawei.android.pushselfshow.**{*;} -keep class com.huawei.android.microkernel.**{*;} -dontwarn com.huawei.android.pushagent.** -dontwarn com.huawei.android.pushselfshow.** -dontwarn com.huawei.android.microkernel.Activator ##Huawei push - -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ##start----------------------------greendao--------------------------------------------------------- -keep class de.greenrobot.dao.** {*;} #The method of keeping greenDao unambiguous is used to keep the generated table names unambiguous. -keepclassmembers class * extends de.greenrobot.dao.AbstractDao { public static java.lang.String TABLENAME; } -keep class **$Properties ##end-------------------------------greendao-------------------------------------------------------- ##Beginning - -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -keep class com.baidu.mapapi.**{*;} ##end - ----------------------------------------------- Baidu Map - -------------------------------------------------------------------------------------------------------------------------------- ##start-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- #gauserinfo -keep class com.dianping.widget.view.GAUserInfo{*;} ##Do not confuse the java files under the model folder and its subfolders -keepnames class com.dianping**model.**{ *; } ##Do not confuse entity folders and java files under their subfolders -keepnames class com.dianping**entity.**{ *; } ##end - -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ##start----------------------------SNAPSHOT--------------------------------------------------------- ##com.meituan.android.common.analyse:library:2.4.4-SNAPSHOT -keep class com.meituan.android.common.analyse.mtanalyse.dao.* { <fields>; } -keep class com.meituan.android.common.analyse.mtanalyse.bean.* { *; } ##end-------------------------------SNAPSHOT-------------------------------------------------------- ##start - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ #weixin-libammsdk.jar #If you use obfuscated code, add the following to proguard.cfg to ensure that your app runs properly: -keep class com.tencent.mm.sdk.modelmsg.WXMediaMessage {*;} -keep class com.tencent.mm.sdk.modelmsg.** implements com.tencent.mm.sdk.modelmsg.WXMediaMessage$IMediaObject {*;} ##end - -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ##start---------------------------gson-------------------------------------------------------------- -keep class sun.misc.Unsafe { *; } ##Note that you need to specify the Model for the Keep you want ##end-----------------------------gson-------------------------------------------------------------- ##start---------------------------support-v4-------------------------------------------------------- -keep class android.support.v4.app.Fragment{*;} -keep class * extends android.support.v4.app.Fragment{*;} ##end------------------------------support-v4------------------------------------------------------- ##start - -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ##Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager"); ##Method mth = cls.getDeclaredMethod("isInBackStack"); -keep class android.support.v4.app.Fragment{ ** mChildFragmentManager; final ** isInBackStack(); } ##Field scrollerField = ViewPager.class.getDeclaredField("mScroller"); ##Field interpolatorField = ViewPager.class.getDeclaredField("sInterpolator"); -keep class android.support.v4.view.ViewPager{ private ** mScroller; private static final ** sInterpolator; } ##Field field = dialogInterface.getClass().getSuperclass().getDeclaredField("mShowing"); -keep class android.app.Dialog{ private ** mShowing; } ##Method getGaUserInfo = view.getClass().getMethod("getGAUserInfo"); ##Method getGAString = view.getClass().getMethod("getGAString"); -keep class **Nova*{ public ** getGAUserInfo(); public ** getGAString(); } ##Method m = WebView.class.getMethod("setWebContentsDebuggingEnabled", Boolean.TYPE); -keep class **.WebView{ ** setWebContentsDebuggingEnabled(...); } ##Method m = MessageQueue.class.getDeclaredMethod("next"); -keep class android.os.MessageQueue{ ** next(); } ##Method method = Message.class.getDeclaredMethod("recycleUnchecked"); -keep class android.os.Message{ ** recycleUnchecked(); } ##end - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ##start - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -keep class com.iflytek.cloud.**{*;} -keep class com.iflytek.msc.**{*;} -keep interface com.iflytek.**{*;} ##end - ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ##Start - ------------------------------------------------ @android. webkit. JavascriptInterface annotation method---------------------------------------------------------------------------------------------- -keepclassmembers class * { @android.webkit.JavascriptInterface <methods>; } ##End - -------------------------------------------- - @android. webkit. JavascriptInterface annotation method - -------------------------------------------------------------------------------------------------- ##start - ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -keep class com.google.inject.**{ *; } -keep public class roboguice.**{ *; } -keep class * extends com.google.inject.Module{ *; } -keepclassmembers class * { @javax.inject.Inject <init>(...); @com.google.inject.Inject <init>(...); @javax.inject.Inject <fields>; @com.google.inject.Inject <fields>; <init>(); } ##end - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ##start - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -keep class com.dianping.base.push.pushservice.MiPushMessageReceiver {*;} ##end - -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ##start---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -keep class com.sina.weibo.sdk.**{*;} ##Sina Weibo - ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ##start - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -keep class com.handmark.pulltorefresh.library.**{ *; } ##end - -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ##start---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- #for tencent upload sdk -keep class * extends com.qq.taf.jce.JceStruct { *; } ##end - --------------------------------------------------- Tencent Upload - -------------------------------------------------------------------------------------------------------------------------------- ##start - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -keep class com.dianping.picasso.ParsingJSHelper{*;} -keep class org.mozilla.javascript.** { *; } ##end - -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ########################################Suppression warning################################################## -dontwarn org.apache.thrift.transport.* -dontwarn org.apache.thrift.server.* -dontwarn org.apache.http.entity.mime.** -dontwarn org.slf4j.* -dontwarn okio.DeflaterSink -dontwarn okio.Okio -dontwarn uk.co.senab.photoview.** -dontwarn com.squareup.okhttp.internal.huc.** -dontwarn com.meituan.android.common.fingerprint.** -dontwarn com.alipay.android.phone.mrpc.core.i -dontwarn com.tencent.tencentmap.mapsdk.maps.a.au -dontwarn com.tencent.tencentmap.mapsdk.maps.a.bc -dontwarn com.tencent.tencentmap.mapsdk.maps.a.co -dontwarn com.qihoo.** -dontwarn com.handmark.pulltorefresh.library.** ########################################Suppression warning################################################## -dontnote ** |
After the confusion is opened, four files are automatically generated:
- dump.txt is used to describe the file structure of each class
- Map.txt is used to describe the mapping relationship before and after confusion.
- seeds.txt is used to describe which classes and members are not confused
- usage.txt is used to describe which classes and class members are deleted
By analyzing these files, you can see the details of the confusion apk size as follows:
1.3: Cleaning of third party lib Libraries
1.3.2: Keep only the armabi directory under lib in the apk package
Add in builde.gradle
ndk { //If you need to run on the simulator, replace the downstream behavior // abiFilters "armeabi","x86" abiFilters "armeabi" }
2: The comparison of the optimized parts