天天看點

【朝花夕拾】Android性能篇之(四)Apk打包

APK,即Android Package,apk打包是将android程式和資源整合在一起,形成的一個.apk檔案。相信所有的Android程式員是在IDE的幫助下,完成打包輕而易舉,但對打包流程真正清楚的可能并不多。要更好地了解android性能優化,就要對Android虛拟機有一定的了解,而要比較好地了解Android虛拟機,就需要清楚apk的打包流程。

前言

        轉載請聲明,轉自【https://www.cnblogs.com/andy-songwei/p/9721337.html】,謝謝!

        APK,即Android Package,是将android程式和資源整合在一起,形成的一個.apk檔案。相信所有的Android程式員是在IDE的幫助下,完成打包輕而易舉,但對打包流程真正清楚的可能并不多。本章的内容比較簡單,也是非常基礎的内容,但是對了解android應用的結構卻有很大的幫助。筆者寫這篇文章的目的,一方面是為了彌補這方面的盲點,回顧和梳理apk打包方面的理論知識點;第二方面,是為了給後續寫Android虛拟機知識做鋪墊,進而去研究android的性能優化,這也是把這篇文章放到Android性能優化系列文章當中的原因;第三方面,也是為了友善讀者了解Android虛拟機的相關内容。

       對于在IDE,如Android Studio上操作打包的過程,本文不做示範,對于更深入的源碼分析,也不在本文讨論之列,出于前面說到的原因,本文隻簡單闡述其打包流程,本文主要内容如下:

【朝花夕拾】Android性能篇之(四)Apk打包

一、apk建構流程圖

     以下截圖為Google官方提供的詳細的apk建構過程圖,其中包含了各個環節所用到的工具和中間相關的檔案。

【朝花夕拾】Android性能篇之(四)Apk打包

                         apk建構過程(綠色部分為對應環節工具,藍色部分為相關檔案)

二、建構過程中所用工具

        如下截圖展示了apk建構過程中所使用的部分工具,這些工具大部分都在sdk/build-tools/檔案夾下:

【朝花夕拾】Android性能篇之(四)Apk打包
【朝花夕拾】Android性能篇之(四)Apk打包
                    代碼混淆所用工具
【朝花夕拾】Android性能篇之(四)Apk打包

                                   打包所用工具所在的jar包

三、apk打包流程詳解

       依據如上的流程圖和工具圖,下面咱們按照流程順序對其進行講解。

  1、aapt打包資源

  • 工具:aapt(Android Asset Package Tool Android資源打包工具)
  • 工具路徑:sdkpath/build-tools/版本号/aapt.exe和aapt2.exe
  • 輸入:Android資源檔案、AndroidManifest.xml
  • 輸出: R.java類、二進制的resource.arsc,res檔案夾(包括二進制的xml、沒被改變的圖檔和res/raw檔案)、二進制的AndroidManifest.xml檔案、沒有改變的assets檔案夾。

        Android的資源檔案包含了兩類:1)assets類資源。該類資源放在工程目錄的assets根目錄下,存放一些原始檔案,這些檔案不會被編譯為二進制檔案,而是被原封不動地打包在apk檔案中,同樣也不能通過資源ID來查找,不儲存在R檔案中。2)res類資源,10種目錄。這類資源儲存在工程目錄中的res目錄下,包含了animator(屬性動畫資源)、anim(補間動畫資源)、color(對象顔色狀态選擇資源)、drawable(xml或Bitmap檔案的圖像資源)、layout(布局檔案資源)、menu(程式菜單資源)、mipmap(圖示資源,推薦閱讀:drawable與mipmap的差別)、raw(不被編譯成二進制檔案的資源,注意和assets資源的差別,推薦閱讀:assets和raw的差別)、values(6種不同的值:數組arrays.xml、顔色值colors.xml、尺寸dimens.xml、字元串strings.xml和樣式值styles.xml)、xml(描述應用程式配置資訊的資源)。

       如下截圖展示了R.java的内容,其中包含了各種靜态内部類,分别對應了某種資源的類型。

【朝花夕拾】Android性能篇之(四)Apk打包

                            R.java結構圖

      以R.string類為例,其中展示了字元串名稱對應的id值,就是對應在res/values檔案夾下,string字元串資源。

【朝花夕拾】Android性能篇之(四)Apk打包

                                                                    R.string結構圖

        推薦閱讀:apk打包安裝過程

  2、aidl生成跨程序通信的java檔案

  • 工具:aidl(Android Interface Definition Language安卓接口定義語言)
  • 工具路徑:sdkpath/build-tools/版本号/aidl.exe
  • 輸入:aidl字尾的檔案,位于工程項目src/main/aidl目錄下
  • 輸出:可用于程序間通信的C/S端java代碼,位于build/generated/source/aidl
【朝花夕拾】Android性能篇之(四)Apk打包

                                       工程項目中的aidl原始檔案

【朝花夕拾】Android性能篇之(四)Apk打包

                                       aidl工具處理後生成的java檔案

  3、Java編譯源碼

  • 工具:javac.exe
  • 工具路徑:jdk/bin/javac.exe
  • 輸入:java source檔案夾、aapt中生成的R.java檔案、aidl生成的java檔案、BuildConfig.java檔案
  • 輸出:對于gradle編譯,生成的class檔案儲存在build/intermediates/classes裡
【朝花夕拾】Android性能篇之(四)Apk打包

                               BuildConfig.java和R.java檔案

【朝花夕拾】Android性能篇之(四)Apk打包

                                              輸出的class檔案

  4、proguard代碼混淆

        完成javac編譯之後,一般還會對其進行代碼的混淆,其實就是類似于加密的功能,作用就是增加反編譯的難度,同時也将一些代碼的命名進行了縮短,減少代碼占用的空間。推薦閱讀:Android代碼混淆零基礎入門。

  • 工具:ProGuard
  • 工具路徑:sdk/tools/proguard/bin/proguard.bat
  • 輸入:被編譯過的class檔案、混淆配置檔案proguard-rules.pro
  • 輸出:被混淆過的.class檔案、混淆前後映射檔案
【朝花夕拾】Android性能篇之(四)Apk打包

  5、将所有.class檔案轉化為classes.dex檔案

  • 工具:dx.bat
  • 工具路徑:sdkpath/build-tools/版本号/dx.bat
  • 輸入:編譯後生成的所有.class檔案、第三方庫和.class檔案
  • 輸出:可以在Android虛拟機上使用的.dex檔案

       調用dx.bat将所有的class檔案轉化為classes.dex檔案,将二進制碼轉化為Android虛拟機(Android4.4以前虛拟機是Dalvik,4.4上是Dalvik和ART可以切換、Android5.0及以後是ART)上的位元組碼、生成常量池、消除備援資料等。由于Android虛拟機是一種針對嵌入式裝置而特殊設計的java虛拟機,所有dex檔案與标準的class檔案在結構設計上有着很大的差別,當javac将java程式編譯成class後,dx工具将所有的class檔案整合到一個dex檔案中,這樣做使得各個類能夠共享資料,在一定程度上降低了容易,同時也使文結構更加緊湊,實驗表明,dex檔案時傳統jar檔案的50%左右。class檔案結構和dex檔案結構比對如下(該部分還會在後文講Android虛拟機時提到):

【朝花夕拾】Android性能篇之(四)Apk打包

                     .class檔案和.dex檔案結構對比圖

  6、apkbuilder打包生成apk

  • 工具:ApkBuilder類
  • 工具路徑:sdkpath/tools/lib/sdklib_xxx.jar
  • 輸入:上一步生成的classes.dex檔案,aapt時生成的resources.arsc、被編譯後的res檔案夾、AndroidManifest.xml,Other Resouces(assets檔案夾)
  • 輸出:.apk檔案(Android Package)

  7、對apk進行簽名

  • 工具:apksigner.bat
  • 工具路徑:sdkpath/build-tools/版本号/apksigner.bat
  • 輸入:上一步中生成的.apk檔案、簽名檔案(Debug or Release Keystore)
  • 輸出:簽名後的.apk檔案

      簽名是一個apk身份的證明,Android系統在安裝apk的時候,首先會檢驗apk的簽名,如果發現簽名檔案不存在或者校驗簽名失敗,就會拒絕安裝。對一個apk檔案簽名後,apk檔案根目錄下回增加META-INF目錄,該目錄下有三個檔案:

【朝花夕拾】Android性能篇之(四)Apk打包

               META-IINF檔案夾結構

      Android系統就是根據這三個檔案的内容對apk檔案進行簽名驗證的:

      MANIFEST.MF中包含對apk中除了/META-INF檔案夾外所有檔案的簽名值。

【朝花夕拾】Android性能篇之(四)Apk打包

                                                 MANIFEST.MF内容截圖

      CERT.SF是對MANIFEST.MF檔案整體簽名以及其中各個條目的簽名。一般地,如果是使用工具簽名,還多包括一項,就是對MANIFEST.MF頭部資訊簽名。

【朝花夕拾】Android性能篇之(四)Apk打包

                                                               CERT.SF内容截圖

      CERT.RSA包含用私鑰對CERT.SF的簽名以及包含公鑰資訊的數字證書。用一般的文本打開後,會顯示亂碼。

【朝花夕拾】Android性能篇之(四)Apk打包

                          CETR.RSA内容截圖

      推薦閱讀:Android簽名有什麼用?

                      Android簽名過程詳解

  8、zipalign優化

      如果是在release mode下,還會對apk進行align,即對簽名後的apk進行對齊處理,這種方式是對apk進行整理和優化。

  • 工具:zipalign
  • 工具路徑:sdkpath/build-tools/版本号/zipalign.exe
  • 輸入:上一步中簽名後的apk檔案
  • 輸出:優化後的apk檔案

四、APK檔案結構

      一個apk解壓後,其典型的結構如下所示,分别在apk打包流程中appt資源打包、javac編譯、簽名階段所産生:

【朝花夕拾】Android性能篇之(四)Apk打包

繼續閱讀