为了应付面试,简单了解一下,顺便记录
原理
利用 DexClassLoader
loadClass
加载 Apk dex
中的 class
文件 拿到目标Class
,再通过反射执行目标Class
的方法
简单实现
plugin
App
package com.zy.plugin.utils
class Utils {
private Utils() {
}
private void hello(Context context) {
Toast.makeText(context, "Plugin --> Utils --> hello", Toast.LENGTH_SHORT).show();
System.out.println("Plugin --> Utils --> hello");
}
}
宿主 App
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
File pluginApk = new File(getExternalFilesDir("pluginApks"), "plugin-debug.apk");
try (Source source = Okio.source(getAssets().open("plugin-debug.apk"));
BufferedSink bufferedSink = Okio.buffer(Okio.sink(pluginApk))
) {
bufferedSink.writeAll(source);
} catch (IOException e) {
e.printStackTrace();
}
DexClassLoader classLoader = new DexClassLoader(pluginApk.getAbsolutePath(), pluginApk.getAbsolutePath(), null, null);
try {
Class<?> utilsClass = classLoader.loadClass("com.zy.plugin.utils.Utils");
Constructor<?> constructor = utilsClass.getDeclaredConstructors()[0];
constructor.setAccessible(true);
Object utils = constructor.newInstance();
Method helloMethod = utilsClass.getDeclaredMethod("hello", Context.class);
helloMethod.setAccessible(true);
helloMethod.invoke(utils, this);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
- 将插件apk保存到手机存储中
- 通过
DexClassLoader.loadClass()
加载目标class
文件,得到目标Class
对象 - 反射执行具体操作
参考了凯哥扔物线课堂的Demo