插件化目前火的不要不要的,因此作为一个开发人员,十分有必要把这门技术掌握。
先从基本的宿主apk中加载插件apk的资源,及调用插件中的方法开始探讨。
首先,先总结一下classloader,插件化可离不开这个东西。
android中的classloader主要有两个:PathClassLoader 和 DexClassLoader, 前者只能加载当前已安装的apk的class,后者可以加载未安装的插件apk的class。
这里只讨论DexClassLoader,因为它的应用场景更广泛。
宿主apk中的代码:
public void test() {
try {
//1、初始化dexpath和构建DexClassLoader的outpath
String outpath = getDir("dex", Context.MODE_PRIVATE).getAbsolutePath();
String dexpath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/test/test.apk";
//2、反射创建AssetManager,并调用addAssetPath方法将插件dex包路径加入到宿主环境
AssetManager assetManager = AssetManager.class.newInstance();
Method method = AssetManager.class.getDeclaredMethod("addAssetPath", String.class);
method.setAccessible(true);
method.invoke(assetManager, dexpath);
//3、使用创建好的AssetManager创建Resources
Resources resources = new Resources(assetManager, getResources().getDisplayMetrics(), getResources().getConfiguration());
//4、获取插件中的图片资源,default_splash为图片名称,drawable为图片类型,com.plugin.test为插件包名
int pluginDrawableId = resources.getIdentifier("default_splash", "drawable", "com.plugin.test");
Drawable drawable = resources.getDrawable(pluginDrawableId);
//5、将获取到的资源图片设为当前View背景
findViewById(R.id.root).setBackground(drawable);
//调用插件中的方法
//1、初始化DexClassLoader
DexClassLoader classLoader = new DexClassLoader(dexpath, outpath, null, getClassLoader());
Class clazz = classLoader.loadClass("com.plugin.test.People");//加载插件中的类
//2、反射调用插件中的方法
Method pluginMethod = clazz.getDeclaredMethod("getName", String.class);
pluginMethod.setAccessible(true);
String result = (String) pluginMethod.invoke(clazz.newInstance(), "zhangsan");
Log.i("PluginTest", "result=" + result);
} catch (Exception e) {
}
}
插件apk中的代码主要就是一个类:com.plugin.test.People
及里面实现一个getName方法:
public String getName(String pre) {
return pre + " end";
}
然后在drawable目录下添加名为default_splash的图片。