利用DexClassLoader動態載入dex檔案
阿新 • • 發佈:2019-01-23
Java中也有類載入器ClassLoader,其作用是動態裝載Class檔案,當我們從網路下載Class檔案,或者在編譯時不參與而在執行時動態呼叫時就需要用類載入器。由於Android對class檔案進行了重新打包和優化,最終APK檔案中包含的是dex檔案,載入這種檔案就需要用到DexClassLoader。
DexClassLoader(dexPath, optimizedDirectory, libraryPath, parent)
dexPath:目標類所在的APK或者jar包,/.../xxx.jar
optimizedDirectory:從APK或者jar解壓出來的dex檔案存放路徑
libraryPath:native庫路徑,可以為null
parent:父類裝載器,一般為當前類的裝載器、
外掛類Plugin用於在執行時由宿主程式呼叫
public class Plugin {
public int add(int a, int b) {
return a+b;
}
}
使用jar命令將其打包成jar檔案
jar -cvf plugin.jar com/dl/plugin/Plugin.class
使用dx命令將其轉化為android中的類格式dex檔案dx --dex --output=f:\dynamic.jar f:\Plugin.jar
將其放到手機目錄中,比如放到根目錄adb push F:\dynamic.jar /
在宿主程式中動態載入呼叫外掛類Plugin的add函式
首先動態載入Plugin類,然後通過反射呼叫add方法,完整程式碼如下DexClassLoader loader = new DexClassLoader("/dynamic.jar", getApplicationInfo().dataDir, null, this.getClass().getClassLoader()); clazz = loader.loadClass("com.dl.plugin.Plugin"); Method add = clazz.getMethod("add", Integer.TYPE,Integer.TYPE); int result = (Integer) add.invoke(clazz.newInstance(), 1,1);
private Button btn;
private Class<?> clazz;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
try {
if (clazz == null) {
DexClassLoader loader = new DexClassLoader("/dynamic.jar", getApplicationInfo().dataDir, null, this.getClass().getClassLoader());
clazz = loader.loadClass("com.dl.plugin.Plugin");
}
Method add = clazz.getMethod("add", Integer.TYPE,Integer.TYPE);
int result = (Integer) add.invoke(clazz.newInstance(), 1,1);
Toast.makeText(MainActivity.this, result+"", 0).show();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
上面使用反射進行函式呼叫有些複雜,可以使用介面進行更方便的呼叫還能保持動態載入的靈活性。專案結構如下,保證介面IPlugin類名一致,包括包名。也可以通過引入jar包的形式來做。
於是就可以通過如下方式呼叫外掛類中的程式碼了。
DexClassLoader loader = new DexClassLoader("/dynamic.jar", getApplicationInfo().dataDir, null, this.getClass().getClassLoader());
clazz = loader.loadClass("com.dl.plugin.Plugin");
IPlugin obj = (IPlugin) clazz.newInstance();
int result = obj.add(1, 1);
效果: