在android中,有一个自己的类加载器,那就是DexClassLoader.这个可以加载jar/apk/dex,也可以从SD卡中加载,也是本文的重点。需要注意的是,通过ide生成的jar包,需要进入dx处理,动态加载之后才会成功,否则将会失败。
首先,我们先建立一个工程。工程中,将动态加载jar文件,然后通过反射来调用jar包中的方法。代码很简单
File file = new File("/storage/sdcard0/liuhang123/testdex.jar"); final File optimizedDexOutputPath = getDir("temp", Context.MODE_PRIVATE); String filePath = file.getAbsolutePath(); String optimizedPath = optimizedDexOutputPath.getAbsolutePath(); DexClassLoader classLoader = new DexClassLoader(file.getAbsolutePath(), optimizedDexOutputPath.getAbsolutePath(), null, getClassLoader()); try { Class<?> iclass = classLoader.loadClass("com.ycl.lib.IClass"); Constructor<?> istructor = iclass.getConstructor(Context.class); //利用反射原理去调用 Method method = iclass.getMethod("call", new Class[ 0 ]); method.invoke(istructor.newInstance(this), new Object[]{}); Method method1 = iclass.getMethod("getData",new Class[0]); String data = (String) method1.invoke(istructor.newInstance(this),new Object[]{}); System.out.println(data); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }
找到对应jar文件的路径,然后新建一个app私有目录存放jar文件。然后初始化dexclassloader加载jar文件。对应的加载代码就是
DexClassLoader classLoader = new DexClassLoader(file.getAbsolutePath(), optimizedDexOutputPath.getAbsolutePath(), null, getClassLoader());
DexClassLoader具体参数
public DexClassLoader (String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent)
Creates a DexClassLoader
that finds interpreted and native code. Interpreted classes are found in a set of DEX files contained in Jar or APK files.
Parameters
dexPath | 需要装载的APK或者Jar文件的路径。 |
---|---|
optimizedDirectory | 优化后的dex文件存放目录,不能为null |
libraryPath | 目标类中使用的C/C++库的列表,每个目录用File.pathSeparator间隔开 ; 可以为 null |
parent | 该类装载器的父装载器,一般用当前执行类的装载器 |
创建一个DexClassLoader用来找出指定的类和本地代码(c/c++代码)。用来解释执行在DEX文件中的class文件。
加载jar之后,就可以通过反射调用jar中的方法了。
try {
Class<?> iclass = classLoader.loadClass("com.ycl.lib.IClass");
Constructor<?> istructor = iclass.getConstructor(Context.class);
//利用反射原理去调用
//加载call方法
Method method = iclass.getMethod("call", new Class[ 0 ]);
//调用call方法
method.invoke(istructor.newInstance(this), new Object[]{});
//加载getData方法
Method method1 = iclass.getMethod("getData",new Class[0]);
//调用getData方法
String data = (String) method1.invoke(istructor.newInstance(this),new Object[]{});
System.out.println(data);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
2.创建库文件,也就是jar包的源代码。我们只需要在原来的工程中,新建一个android library moudle。目录如下,包含了一个接口和他的实现类
实现类代码如下:
public class IClass implements Iinterface { private Context context; public IClass(Context context) { super(); this.context = context; } @Override public void call() { Toast.makeText(context, "call method haha", Toast.LENGTH_SHORT).show(); } @Override public String getData() { return "hello,i am from IClass aa"; } }
这样library就好了,build一下,在build目录下面生成了对应的jar文件。
当然,如果你需要指定jar文件生成的目录,可以修改library模块的build.gradle文件,在文件中加入
//Copy类型,把library编译成jar包,并导出到build/libs/目录下面 task makeJar(type: Copy) { //删除存在的 delete 'build/libs/mysdk.jar' //设置拷贝的文件 from('build/intermediates/bundles/release/') //打进jar包后的文件目录 into('build/libs/') //将classes.jar放入build/libs/目录下 //include ,exclude参数来设置过滤 //(我们只关心classes.jar这个文件) include('classes.jar') //重命名 rename ('classes.jar', 'classes.jar') } makeJar.dependsOn(build)
然后在android studio 命令行执行 gradlew makeJar,执行成功之后,会在build/libs/目录下面生成classes.jar
然后我们把这classes.jar文件复制出来。使用dx工具生成dexclassloader能够使用的jar文件。在你的android sdk对应目录C:\Users\chengliang.yu\AppData\Local\Android\sdk\build-tools\25.0.2 build-tools下面有一个androidbuild-tools版本文件夹,随便进去一个,下面有个dx.bat
没有配置环境变量就通过命令行进入该目录,然后使用dx 命令生成新的jar文件,对应命令如下
dx --dex --output=d:\test\testdex.jar classes.jar d:\test\testdex.jar对应了生成的新的jar文件对应的目录 ,后面classes.jar就是library模块生成的jar文件
然后我们把生成的testdex.jar文件放入要使用的工程,动态加载,然后反射就可以使用jar文件中的方法了。
demo下载地址:链接:http://pan.baidu.com/s/1bWge5K 密码:d6yb