2BAB's Engineering Blog

Android插件化笔记-2-LoadPluginClass

Demo: https://github.com/2BAB/Android-Plugin-Dev-Notes

如何获取能够被加载的 .dex 文件

准备如下两个测试类,其中TestDexInterface还需要拷贝一份到工程中

TestDexClass.java

1
2
3
4
5
6
7
8
9
10
package example.com.classeasyload;
public class TestDexClass implements TestDexInterface{
@Override
public float getPiValue() {
return 3.14f;
}
}

TestDexInterface.java

1
2
3
4
5
6
7
package example.com.classeasyload;
public interface TestDexInterface {
float getPiValue();
}
  1. javac *.java -> .class
  2. jar cvf origin.jar . -> .jar
  3. dx --dex --output=target.dex origin.jar -> .dex

按文章的步骤,自己实现了一遍,需要注意的是第二步打jar包的时候需要连包名所在的文件夹一起打进去

1
2
3
4
5
|____example
| |____com
| | |____classeasyload
| | | |____TestDexClass.class
| | | |____TestDexInterface.class

jar包里应该是如上的结构。

加载并调用.dex里面的方法

这里我先 adb shell mkdir -p /system/dex/, 然后adb push target.dex /system/dex/
如MainActivity里代码所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
File optimizedDexOutputPath = new File("/system/dex/" + "target.dex");// 外部路径
File dexOutputDir = this.getDir("dex", 0);// 无法直接从外部路径加载.dex文件,需要指定APP内部路径作为缓存目录(.dex文件会被解压到此目录)
DexClassLoader dexClassLoader = new DexClassLoader(
optimizedDexOutputPath.getAbsolutePath(),
dexOutputDir.getAbsolutePath(),
null,
getClassLoader());
try {
Class libProviderClazz = dexClassLoader.loadClass("example.com.classeasyload.TestDexClass");
TestDexInterface dexInterface = (TestDexInterface) libProviderClazz.newInstance();
Toast.makeText(this, dexInterface.getPiValue() + "", Toast.LENGTH_LONG).show();
} catch (Exception e) {
e.printStackTrace();
}

最终成功Toast出了3.14

参考资料:

本系列为笔记文,文中有大量的源码解析都是引用的其他作者的成果,详见下方参考资料。

讨论请发邮件到 xx2bab@gmail.com
自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0