在学习Java反射的技术后,我们可以开始由浅入深探究插件化开发了。
我们可以从最基本的加载外部apk开始,然后再到加载插件中的类,然后在通过优化前面实现的时候发现的问题,一步步探究插件化的本质。
加载流程如下:
将插件 apk 放到主 app 的 assets 目录中,app启动后把 assets 目录中的插件 apk 复制到内存。
读取插件 apk 中的 dex,生成对应的 DexClassLoader。
使用 DexClassLoader 的 loadClass 方法读取插件的 dex 中的任何一个类。
1. 打包插件 apk 并放到宿主 assets 目录
插件apk可以按照正常打包应用的方式打包。
例如在插件apk里面写一个bean类:
public classBean {private String name = "jianqiang";publicString getName() {returnname;
}public voidsetName(String paramString) {this.name =paramString;
}
}
打包完成后,放到宿主app项目目录下的assets目录下。
2. 将assets目录下的apk复制到/data/data/files目录下
/*** 把Assets里面得文件复制到 /data/data/files 目录下
*
*@paramcontext
*@paramsourceName*/
public static voidextractAssets(Context context, String sourceName) {
AssetManager am=context.getAssets();
InputStream is= null;
FileOutputStream fos= null;try{
is=am.open(sourceName);
File extractFile=context.getFileStreamPath(sourceName);
fos= newFileOutputStream(extractFile);byte[] buffer = new byte[1024];int count = 0;while ((count = is.read(buffer)) > 0) {
fos.write(buffer,0, count);
}
fos.flush();
}catch(IOException e) {
e.printStackTrace();
}finally{
closeSilently(is);
closeSilently(fos);
}
}
3. 读取插件 apk 中的 dex,生成对应的 DexClassLoader
DexClassLoader classLoader = new DexClassLoader(dexpath, fileRelease.getAbsolutePath(), null, getClassLoader());
4. 使用 DexClassLoader 的 loadClass 方法读取插件的 dex 中的类
Class mLoadClassBean;try{
mLoadClassBean= classLoader.loadClass("jianqiang.com.plugin1.Bean");
Object beanObject=mLoadClassBean.newInstance();
Method getNameMethod= mLoadClassBean.getMethod("getName");
getNameMethod.setAccessible(true);
String name=(String) getNameMethod.invoke(beanObject);
mTextView.setText(name);
Toast.makeText(getApplicationContext(), name, Toast.LENGTH_LONG).show();
}catch(Exception e) {
e.printStackTrace();
}
当我们看到输出了我们在插件apk定义的内容后,就说明我们成功的加载外部的dex并进行调用。