1. 程式人生 > >利用DexClassLoader動態載入dex檔案

利用DexClassLoader動態載入dex檔案

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函式

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);
首先動態載入Plugin類,然後通過反射呼叫add方法,完整程式碼如下
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);

效果: