本文通過學習聊聊 APK —— Dex 熱修複與 Classpath 總結
在将java檔案直接運作在JVM和Dalvik中,中講解了java程式如何在JVM和Dalvik中運作,其中在Android部分實作是,先将java檔案轉為dex檔案,導入至安卓手機中,通過Dalvik對該檔案編譯運作,實作将java檔案運作在手機中功能。本文重點講解如何利用該功能實作簡易熱修複的效果。
熱修複的根本原理是通過修改DexClassLoader 中dexPathList 的dex順序,達到熱修複的效果。
1.制作帶有bug的dex
首先建立一個帶有列印bug的類test.java,如下所示:
package xiaohan;
public class Test {
public void test (){
System.out.println("This a BUG!");
}
}
這裡需要注意,由于此類需要在帶有main的類中引用,需要自定義一個package,否則無法正常引用該類。
建立一個帶有main的主類HelloWorld.java,該類中需要引用Test,通過import的形式引入。
import xiaohan.Test;
public class HelloWorld {
public static void main (String [] args){
Test test = new Test();
test.test();
}
}
由于需要加載兩個java檔案,需要通過以下語句執行,注意cp之後有個 “.”的修飾符。
javac -cp . HelloWorld.java Test.java
将生成的兩個class檔案,生成一個dex檔案,這例需要注意,如果直接按照之前的語句:
dx --dex --output=xiaohan.dex HelloWorld.class Test.class
則會出現以下錯誤:
E:\ProgramFiles\Android\build-tools\28.0.3>dx --dex --output=xiaohan.dex HelloWorld.class Test.class
PARSE ERROR:
class name (xiaohan/Test) does not match path (Test.class)
...while parsing Test.class
1 error; aborting
原因是由于在建立Test.java檔案時,為其指定了包名為xiaohan,與HelloWorld不在同一包下,是以需要建立一個xiaohan的檔案夾,将Test.class拷貝進去,然後執行如下語句:
dx --dex --output=xiaohan.dex HelloWorld.class xiaohan/Test.class
就會生成一個的xiaohan.dex檔案,将其拷貝至手機後,運作如下語句:
dalvikvm -cp xiaohan.dex HelloWorld
結果如下:
2. 制作更新檔包
重新建立一個新的test.java檔案,修改其内容如下:
package xiaohan;
public class Test {
public void test (){
System.out.println("Fix a BUG!");
}
}
制作一個新的class檔案,注意隻需要制作Test.class檔案,與HelloWorld.class無關,制作語句如下,去除“.”,包含HelloWorld因為在編譯時會報錯。
javac -cp HelloWorld.java Test.java
将新制作的Test.class檔案制作成功獨立的dex檔案,這裡命名為new.dex,通過執行如下語句:
dx --dex --output=new.dex xiaohan/Test.class
該dex的是制作更新檔包,隻包含test.class檔案,不包含HelloWorld.class檔案。
将生成的new.dex檔案,推送至手機存放HelloWorld.dex的目錄下,執行修複後的語句,如下所示。
dalvikvm -cp new.dex:xiaohan.dex HelloWorld
注意,這裡需要将更新檔包放置前面,然後再添加xiaohan.dex(包含main的dex檔案),否則如果先添加new.dex或者不添加,則無法到達修複效果,如下語句。
dalvikvm -cp xiaohan.dex:new.dex HelloWorld
以上隻是簡單的示範在Dalvik虛拟機中,通過修改DexClassLoader 中dexPathList 的dex加載順序,實作修複的效果,實際使用中,一般我們的APP是安裝在data/data/包名/ 目錄下, 如果需要熱修複檔案,在制作好更新檔檔案(更新檔.dex檔案)後推送至應用端,在應用使用時,判斷是否有該更新檔檔案,再通過反射形式,修改dexPathList中更新檔包的順序,實作APP熱修複的效果。可參考Android學習——手把手教你實作Android熱修複