android 安装包大小优化

一、如何优化?

1:确定需要优化哪些内容

 使用android APK Analyze分析APK各个部分的大小,5.1.1版本apk大小分布如下:

        

                分析的结果是需要优化三个地方

  1. res(app资源包括图片和xml资源)           
  2. classes.dex(javac编译后的文件)   
  3. 引入的第三方lib库

1.1:res优化

         1.1.1   使用TinyPNG对图片资源进行压缩

         tinypng 是一个支持压缩png和jpg图片格式的网站,通过其独特的算法(通过一种叫“量化”的技术,把原本png文件的24位真彩色压缩为8位的索引演示,是一 种矢量压缩方法,把颜色值用数值123等代替。)

可以实现在无损压缩的情况下图片文件大小缩小到原来的30%-50%。

          使用TinyPNG对大小超过10KB的图片进行压缩,处理的结果是apk大小减少了0.6M左右

         

         1.1.2   使用Android lint对代码中无用的资源进行清理

         在项目中,点击菜单栏的Analyze -> Run Inspection by Name ...  →输入unused resources  lint分析删除的资源约0.2M

         

         1.1.3   只保留中文相关的资源

         在android support库中包含了国际化的字符串,点评管家现在不需要支持国际化, 所以对除中文以外的资源进行删除

         在module下的builde.gradle文件中的defaultConfig闭包中加入 :

    resConfigs "zh-rCN"

        1.1.4  配合ProGuard工具使用shrinkResources对无用代码清理后的无引用资源的清理

         在proguard工具删除项目中没有使用到的class和class中的成员之后,会产生一些没有被引用到的资源需要被删除,在

         build.gradle中编译release版本时加入 shrinkResources true 来开启缩减无用资源的功能

         

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

1.2:class.dex优化

   自定义proguard规则在proguard-rules.pro中指定哪些类和哪些类的成员需要被保留,不能被删除和重命名。

   具体的规则如下:

-ignorewarnings

##start------------------------------android系统相关----------------------------------------------
-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------------------------------android系统相关-------------------------------------------------

##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------------------------------继承自View的控件----------------------------------------------
-keep public class * extends android.view.View {
    public (android.content.Context);
    public (android.content.Context, android.util.AttributeSet);
    public (android.content.Context, android.util.AttributeSet, int);
    public *** set*(...);
    public *** get*(...);
}

-keepclasseswithmembers class * {
    public (android.content.Context, android.util.AttributeSet);
}

-keepclasseswithmembers class * {
    public (android.content.Context, android.util.AttributeSet, int);
}
##end------------------------------继承自View的控件------------------------------------------------

##start-----------------------------native方法----------------------------------------------------
-keepclasseswithmembernames,includedescriptorclasses class * {
    native ;
}
-keepclasseswithmembernames class * {
    native ;
}
##end--------------------------------native方法--------------------------------------------------

##start------------------------------Parcelable CREATOR变量---------------------------------------
-keepclassmembers class * implements android.os.Parcelable {
    static ** CREATOR;
}
-keepclassmembers class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator CREATOR;
}
##end------------------------------Parcelable CREATOR变量-----------------------------------------

##start-----------------------------Serializable----------------------------------------------------
#保持 Serializable 不被混淆
-keepnames class * implements java.io.Serializable

#保持 Serializable 不被混淆并且enum 类也不被混淆
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    !static !transient ;
    !private ;
    !private ;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}
##end--------------------------------Serializable---------------------------------------------------

##start------------------------------R文件的静态成员-----------------------------------------------
-keep class **.R$* {
    public static ;
}
-keep class **.R
##end------------------------------R文件静态成员---------------------------------------------------

##start-----------------------------EventBus--------------------------------------------------------
-keepclassmembers class ** {
    @org.greenrobot.eventbus.Subscribe ;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
-keep class de.greenrobot.event.** {*;}
-keepclassmembers class ** {
    public void onEvent*(**);
    void onEvent*(**);
}
##end-------------------------------EventBus--------------------------------------------------------

##start-----------------------------使用keep相关注解-----------------------------------------------
-keep class android.support.annotation.Keep

-keep @android.support.annotation.Keep class * {*;}

-keepclasseswithmembers class * {
    @android.support.annotation.Keep ;
}

-keepclasseswithmembers class * {
    @android.support.annotation.Keep ;
}

-keepclasseswithmembers class * {
    @android.support.annotation.Keep (...);
}
##end--------------------------------使用keep相关注解----------------------------------------------


##start------------------------------alipapy--------------------------------------------------------
#paysdk-alipay (实际测试,不写支付宝的keep也可以支付宝支付。不过还是按照支付宝文档写上吧)
-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---------------------------------------------------------

  ##不混淆泛型
-keepattributes Signature
  ##不混淆注解
-keepattributes *Annotation*
  ##抛出异常时保留代码行号,在异常分析中可以方便定位
-keepattributes SourceFile,LineNumberTable
##end---------------------------------keepattributes相关------------------------------------------

##start---------------------------------华为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
##end-------------------------------------华为push------------------------------------------------

##start----------------------------greendao---------------------------------------------------------
-keep class de.greenrobot.dao.** {*;}
#保持greenDao的方法不被混淆 用来保持生成的表名不被混淆
-keepclassmembers class * extends de.greenrobot.dao.AbstractDao {
 public static java.lang.String TABLENAME;
}
 -keep class **$Properties
##end-------------------------------greendao--------------------------------------------------------

##start------------------------------百度地图-----------------------------------------------------
-keep class com.baidu.mapapi.**{*;}
##end---------------------------------百度地图----------------------------------------------------


##start--------------------------实体model-------------------------------------------------------
      #gauserinfo
-keep class com.dianping.widget.view.GAUserInfo{*;}
     ##不混淆model文件夹及其子文件夹下的java文件
-keepnames class com.dianping**model.**{
    *;
}
     ##不混淆entity文件夹及其子文件夹下的java文件
-keepnames class com.dianping**entity.**{
    *;
}
##end------------------------------实体model-----------------------------------------------------

##start----------------------------SNAPSHOT---------------------------------------------------------
##com.meituan.android.common.analyse:library:2.4.4-SNAPSHOT
-keep class com.meituan.android.common.analyse.mtanalyse.dao.* {
    ;
}
-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 { *; }

       ##注意需要指定所要Keep的Model

##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注解的方法---------------------
-keepclassmembers class * {
    @android.webkit.JavascriptInterface ;
}
##end-----------------------------@android.webkit.JavascriptInterface注解的方法--------------------

##start-------------------------依赖注入roboguice2.0----------------------------------------------
 -keep class com.google.inject.**{
     *;
 }
 -keep public class roboguice.**{
     *;
 }
 -keep class * extends com.google.inject.Module{
     *;
 }

 -keepclassmembers class * {
     @javax.inject.Inject (...);
     @com.google.inject.Inject (...);
     @javax.inject.Inject ;
     @com.google.inject.Inject ;
     ();
 }
##end---------------------------依赖注入roboguice2.0----------------------------------------------

##start----------------------------小米-----------------------------------------------------------
-keep class com.dianping.base.push.pushservice.MiPushMessageReceiver {*;}
##end--------------------------------小米---------------------------------------------------------

##start--------------------------新浪微博---------------------------------------------------------
-keep class com.sina.weibo.sdk.**{*;}
##end-----------------------------新浪微博--------------------------------------------------------

##start-------------------------下拉刷新----------------------------------------------------------
-keep class com.handmark.pulltorefresh.library.**{
     *;
}
##end----------------------------下拉刷新---------------------------------------------------------

##start---------------------------腾讯上传--------------------------------------------------------
#for tencent upload sdk
-keep class * extends com.qq.taf.jce.JceStruct { *; }
##end-------------------------------腾讯上传------------------------------------------------------

##start-----------------------------其它----------------------------------------------------------
-keep class com.dianping.picasso.ParsingJSHelper{*;}

-keep class org.mozilla.javascript.** { *; }
##end--------------------------------其它---------------------------------------------------------



########################################抑制警告##################################################
-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.**
########################################抑制警告##################################################
-dontnote **

在开启混淆之后会自动生成四个文件:

  1.  dump.txt 用于描述每个class的文件结构
  2. mapping.txt 用于描述混淆前和混淆后的映射关系
  3. seeds.txt用于描述哪些类和成员没有被混淆
  4. usage.txt用于描述哪些类和类成员被删除

通过分析这些文件就可以了解混淆的细节 apk大小如下:

1.3:第三方lib库的清理

1.3.2:只保留apk包中lib下的armabi目录

在builde.gradle中加入

ndk {
    //如果需要在模拟器上运行替换下行为
 // abiFilters "armeabi","x86"
 abiFilters "armeabi"
}

2:优化后的各个部分的对比

 

 

你可能感兴趣的:(android技术)