本文中插件APK工具类包名:cn.kang.plugin.PluginUtil
工具类中的方法也很简单,两个int类型的数相加
MainActivity代码:
public class MainActivity extends AppCompatActivity {
private String cacheDir;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
cacheDir = getCacheDir().getPath();
try {
// 将 插件APK 保存在本地路径
LoadUtils.copyAssetAndWrite(this, "plugin-debug.apk");
// 创建 插件APK 的 类加载器
DexClassLoader dexClassLoader = new DexClassLoader(cacheDir + "/plugin-debug.apk",
getDir("dex", 0).getAbsolutePath(), null, getClassLoader());
// 用 类加载器 加载 插件APK中的类
Class<?> pluginClass = dexClassLoader.loadClass("cn.kang.plugin.PluginUtil");
Method method = pluginClass.getDeclaredMethod("pluginMethodAdd", int.class, int.class);
Object result = method.invoke(null, 3, 4);
Log.i("kang", "执行结果: " + result); // I/kang: 执行结果: 7
} catch (Exception e) {
e.printStackTrace();
}
}
}
copyAssetAndWrite方法:
/**
* 将 asset 的文件拷贝到缓存中
*/
public static String copyAssetAndWrite(Context context, String fileName) throws Exception {
File cacheDir = context.getCacheDir();
if (!cacheDir.exists()) {
cacheDir.mkdirs();
}
File outFile = new File(cacheDir, fileName);
if (!outFile.exists()) {
boolean res = outFile.createNewFile();
if (res) {
InputStream is = context.getAssets().open(fileName);
FileOutputStream fos = new FileOutputStream(outFile);
byte[] buffer = new byte[is.available()];
int byteCount;
while ((byteCount = is.read(buffer)) != -1) {
fos.write(buffer, 0, byteCount);
}
fos.flush();
is.close();
fos.close();
Toast.makeText(context, "加载成功", Toast.LENGTH_SHORT).show();
return outFile.getAbsolutePath();
}
} else {
Toast.makeText(context, "文件已存在", Toast.LENGTH_SHORT).show();
}
return outFile.getAbsolutePath();
}
核心思想:拷贝assets目录下的插件APK到本地,创建一个插件APK的DexClassLoader加载它,拿到插件APK里的工具实体类后,运用反射执行插件APK的方法。
在开发的过程中可以直接从网络下载插件APK到本地,然后进行加载反射执行操作