Android 可能你想要的APK瘦身筆記

導讀:這是在今年項目體積優化時,記錄的一些實戰筆記,文中主要針對APK的包內容優化.其中優化手段主要有:字節碼,資源,打包配置等優化手段.

前言

移動網絡從2G->4G->5G,網速一步步提升,網絡資費也逐漸便宜起來了. 記得上高中的時候5塊錢/30M流量,能happy一個月.現在給我300M流量,說不定一會刷完

前幾年開始Android開發的職業生涯,那會公司對APP的包體積還特別敏感,到了今天,對APP的包體積已經不在是特別敏感了

但是對於

  • 出海應用APP,非洲,印度那些網絡資源匱乏的地方,APP包體積還是特別敏感的
  • 日活,流量比較大的APP,如微信,抖音等APP,對包體積還是比較關注的

所以今天還是把我之前對APP瘦身的筆記分享給大家,與此共勉(內容不包含插件化,Split APK等動態下發技術,Only客戶端自己的優化)

APK包結構簡介

APK包結構主要包含

  • assets目錄:用於存放需要打包到APK中的靜態文件和res的不同點在於,assets目錄支持任意深度的子目錄,用戶可以根據自己的需求任意部署文件夾架構,而且res目錄下的文件會在.R文件中生成對應的資源ID,assets不會自動生成對應的ID(在不動業務邏輯,或者代碼邏輯的情況下,針對此項很難優化)
  • lib目錄:存放應用程序依賴的native庫文件, .so的形式存在
  • res目錄:res是resource的縮寫,這個目錄存放資源文件
  • resources.arsc文件:編譯後的二進制資源文件
  • META-INF目錄:保存應用簽名信息,此處可驗證APK的完整性,簽名等
  • AndroidManifest.xml:應件文件配置信息
  • classes.dex:

下面我們來說一下優化的具體實施有哪些.

classes.dex 中常量 R文件及內斂類的刪除 * .R$ *

我們知道,Android的Res資源會生成R文件的引用,如下

public final class R {
    private R() {
    }
    public static final class id {
        public static final int action_container = 2131165209;
        public static final int action_divider = 2131165211;
        public static final int action_image = 2131165212;
        public static final int action_text = 2131165218;
        public static final int actions = 2131165219;
        public static final int async = 2131165226;
        public static final int blocking = 2131165232;
        public static final int chronometer = 2131165246;
        public static final int forever = 2131165290;
        public static final int icon = 2131165299;
        public static final int icon_group = 2131165300;
        public static final int info = 2131165305;
        public static final int italic = 2131165309;
        public static final int normal = 2131165373;
        public static final int notification_background = 2131165374;
        public static final int notification_main_column = 2131165375;
        public static final int notification_main_column_container = 2131165376;
        public static final int right_icon = 2131165405;
        public static final int right_side = 2131165406;
        public static final int tag_transition_group = 2131165453;
        public static final int text = 2131165456;
        public static final int text2 = 2131165457;
        public static final int time = 2131165461;
        public static final int title = 2131165462;

        private id() {
        }
    }

    public static final class drawable {
        .......
    }

    public static final class dimen {
    ...
    }
   ....
}

這都是些常量,那我們有沒有辦法刪除這個文件呢,引用的地方直接使用常量的值?事實是可以的.
根據APK打包的編譯過程,在編譯過程中使用Android的Transform替換所有的類裏面的常量. BuildConfig, Rid,Rid, Rlayout, R$string,AppConstans, etc

目前滴滴開源了一個booster 可以直接使用,不用在自己造輪子
booster-transform-shrink

效果

組件化後或者依賴第三方 R文件越來越多,常量比較多時,效果比較顯著
據抖音的一哥們說,他們項目針對此項目優化後,包體積減少2M左右.

在我們項目上使用,不是很明顯,優化體積1M左右.

注意事項

因爲是刪除常量,所有使用反射的地方也需要keep住,如果使用滴滴的booster,可以參考 issues

Res資源

Android Lint 去除無用資源

當我們項目迭代不斷迭代,總有些資源逐漸不在使用,成爲了冗餘,當很多時候又懶得刪,或者怕刪了出問題. Android Studio自帶lint工具可以幫助我們清楚這些無用資源.(這裏的清楚和shrinkResources去除無用是不一樣的)

使用方法入口

除了Android Studio Analyze下的Android Lint(Inspect Code) 用來去除無用資源,包體積優化,對於我們的代碼一些自動優化也有很明顯的效果. (性能,安全,bug預防等)

  • Android > Lint > Correctness (可能影響程序正確性)
  • Android > Lint > Performance (可能影響程序性能)
  • Android > Lint > Security (可能影響程序安全性)

Lint詳細使用說明:google.cn/studio/lint

還有Code Cleanup也很強大,可以減少一些人爲代碼review不規範的地方.

圖片

針對圖片的優化,主要有一下幾點

.9圖片

使用.9圖片來代替一些可重複區域的大圖,可以藉助Android Studio或者sdk下的.9工具來製作.9圖片

xh-dpi

國內應用除了應用的icon,大部分應用只設置了一套資源xh-dpi,所以推薦使用一套圖片資源

Android原生對於WebP的支持

我們知道Webp的壓縮比例要比 png,jpg/jpeg的壓縮比高,使用webp能減少一些包體積.

  • Android 4.0開始(sdk >= 14 ),原生的ImageView開始支持Webp,但是未支持透明通道
  • Android 4.2開始 (sdk >= 18)開始前面支持Webp

也就是說你項目的 minSdk是4.2以上 >= 18 那麼恭喜你,你可以把所有圖片轉成webp格式,方法直接圖片右鍵就可以轉換.
如果只是在4.0與4.2之間的那麼,你就只能轉一些不帶透明通道的圖片,如果其他你還想要Webp接入一個庫,那增大包體積,和原生ImageView不支持,帶來的成本挺大.

圖片壓縮

圖片壓縮也是隻要的一個環節. 圖片壓縮的工具很多,png,webp都可以很容易的壓縮,對於應用質量體積有較高要求的,建議使用有損壓縮,對圖片視覺上的效果影響不大.

這裏還是推薦 使用booster的壓縮工具,可以png和webp壓縮,針對webp的壓縮針對了不同minSdk版本,進行了不同壓縮策略.
booster-task-compression

resources.ars優化

我們知道 res裏面的資源文件名引用一般是這樣的,例如將res/drawable/welcome.png那麼打包的時候,是不是可以改成這樣r/s/a.png.
事實是可以的,類似java的混淆規則去混淆資源,這樣,所佔用的字節數就會降低.
但是存在一個問題就是,這些資源資源ID已經被編譯成32位int值,放入了resources.arsc.那麼混淆的同時就要修改resources.arsc.
張紹文 tinker作者,前微信的技術大年,開源了AndResGuard,可以解決這樣的方案,並且優化還可以.具體使用詳解 AndResGuard

build.gradle 配置

com.android.tools.build:gradle 是Android打包的工具,在打包時也可以對生成的APK包,體積優化,這裏列舉了一些常見的優化策略.

buildTypes {
        release {
            buildConfigField 'String', 'TINKER_APP_ID', '"d499a164a6"'
            debuggable false //debug false 
            shrinkResources true //移除無用資源
            zipAlignEnabled true //開啓壓縮
            resConfigs "zh"  //表示只使用中文
            resConfigs "xhdpi" // 表示只是用xhdpi目錄下的資源文件
            minifyEnabled true //開啓混淆
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release

            ndk {
                //選擇要添加的對應cpu類型的.so庫。
                abiFilters 'armeabi-v7a'
            }
        }
 }

以上是一些常用的配置,其中需要注意的是

  • 開啓混淆,必須主要項目中的keep規則是否考慮全面
  • resConfigs 需要和產品設計協商後,在開啓
  • ndk中,目前國內大部分應用都只支持了armabi-v7a(支持浮點類型,精度更高),我所在的應用也只使用了aremabi-v7a架構,這種架構幾乎所有的arm手機都支持.

文末

APP瘦身就介紹完了,上述方案都在項目中實踐過的.如果文中存在錯誤,請各路大神指教.

推薦閱讀

Android 繪製原理淺析【乾貨】
Flutter 高性能原理淺析

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章