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);
效果:

