[原創]Android Studio的Instant Run(即時安裝)原理分析和源碼淺析


Android Studio升級到2.0之后,新增了Instant Run功能,該功能可以熱替換apk中的部分代碼,大幅提高測試安裝的效率。

但是,由於我的項目中自定義了一些ClassLoader,當使用InstantRun時,經常出現class加載不正確的問題。分析后原因如下。

使用Instant Run編譯出的apk里面會多出幾個dex文件,和一個instant-run.zip,這個zip里也是一堆dex文件:

所以推測,instant Run的實現原理是:

根據代碼結構,將App的源碼分割成多個dex,然后使用自定義的classloader來加載他們,當然這個自定義的classloader也要繼承BaseDexClassLoader,因為BaseDexClassLoader里有個DexPathList,這個所謂的List里存的是多個dex的文件信息,所以當某段代碼修改時,只需編譯和替換相應的dex文件即可(這同樣也是MultiDex的實現原理)。

下面我們簡單驗證一下。

首先正常的apk運行時,其classloader打印出來是這樣的:

dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.zkw.hostdemo-1/base.apk"],nativeLibraryDirectories=[/data/app/com.zkw.hostdemo-1/lib/arm, /system/lib, /vendor/lib, system/vendor/lib, system/vendor/lib/egl, system/lib/hw]]]

而使用Instant Run運行起來的apk,其classloader打印出來長這樣:

com.android.tools.fd.runtime.IncrementalClassLoader$DelegateClassLoader[DexPathList[[dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-support-annotations-23.3.0_6be31c7c3de045eced09b0e58c45c46ba1a8b4da-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-slice_9-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-slice_8-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-slice_7-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-slice_6-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-slice_5-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-slice_4-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-slice_3-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-slice_2-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-slice_1-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-slice_0-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-ormlite-core-4.47_2aa30d6da8ed45bfc6255e592f80eb5f44eace4c-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-ormlite-android-4.47_a7ee90c985672a4cd4bdfca79190a330465fcdb0-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-lecore_4c1e07fda866033d90832ceae724962d4943e790-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-internal_impl-23.1.1_12c3206fb094d3315355dc809fcd39ad94f6e5e8-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-fastjson-1.1.45.android_317ce285230b187682809682934f3690b4d9580d-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-com.android.support-support-v4-23.1.1_1cfecee433501e7056d02c08b2393c569c575b33-classes.dex", dex file "/data/data/com.zkw.hostdemo/files/instant-run/dex/slice-com.android.support-multidex-1.0.1_a3117677a6ad7ee678ee3f3a4af434c4d08ee7ba-classes.dex"],nativeLibraryDirectories=[/data/app/com.zkw.hostdemo-1/lib/arm, /system/lib, /vendor/lib, system/vendor/lib, system/vendor/lib/egl, system/lib/hw]]]

很長吧,發個截圖:

可以看到這個ClassLoader是:com.android.tools.fd.runtime.IncrementalClassLoader$DelegateClassLoader,DexPathList對應着instant-run.zip里的所有dex。

到這里,感覺基本符合我的猜想,但是這個IncrementalClassLoader是如何添加到設備中的,又如何在運行時起作用的,我們接着分析。

instant run運行的apk里,和class有關的就是classes.dex、classes2.dex和instant-run.zip里的dex。

通過觀察命名和反編譯,我發現instant-run.zip里的dex都是和我們app代碼相關的,而classes.dex和classes2.dex是AndroidStudio編譯時自己添加的,其中classes2.dex最重要,我們反編譯看看:

終於看到了熟悉的IncrementalClassLoader,那這個classloader是怎么生效的呢,我們看看BootstrapApplication的源碼(可想而知,AndroidManifest文件中的application屬性也被Android Studio改了):

注意標綠的那行,繼續進去看看(那行下面有個createRealApplication(),其實就是通過反射獲取app自定義的Application,然后做對應的操作):

灰色的那行就是安裝IncrementalClassLoader的地方,進入IncrementalClassLoader的inject()看看,

源碼中可以看到,Studio其實就是利用反射,將自己的IncrementalClassLoader設置成app中默認ClassLoader的parent,這樣就攔截了所有類加載的動作,從而實現了對多個dex文件的動態加載。

到此,原理分析結束。

所以如果你的app里用到了自定義的ClassLoader,請謹慎使用Instant Run!

謝謝閱讀,轉載請注明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM