在android中,有一个自己的类加载器,那就是DexClassLoader.这个可以加载jar/apk/dex,也可以从SD卡中加载,也是本文的重点。需要注意的是,通过ide生成的jar包,需要进入dx处理,动态加载之后才会成功,否则将会失败。
首先,我们先建立一个工程。工程中,将动态加载jar文件,然后通过反射来调用jar包中的方法。代码很简单
File file = newFile("/storage/sdcard0/liuhang123/testdex.jar");finalFile optimizedDexOutputPath = getDir("temp",Context.MODE_PRIVATE);String filePath = file.getAbsolutePath();String optimizedPath = optimizedDexOutputPath.getAbsolutePath();DexClassLoader classLoader = newDexClassLoader(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", newClass[ 0]);method.invoke(istructor.newInstance(this), newObject[]{});Method method1 = iclass.getMethod("getData",newClass[0]);String data = (String) method1.invoke(istructor.newInstance(this),newObject[]{});System.out.println(data);} catch(Exception e) {
//TODO Auto-generated catch blocke.printStackTrace();}
找到对应jar文件的路径,然后新建一个app私有目录存放jar文件。然后初始化dexclassloader加载jar文件。对应的加载代码就是
DexClassLoader classLoader = newDexClassLoader(file.getAbsolutePath(),optimizedDexOutputPath.getAbsolutePath(), null,getClassLoader());
DexClassLoader具体参数
publicDexClassLoader (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", newClass[ 0]);//调用call方法method.invoke(istructor.newInstance(this), newObject[]{});//加载getData方法Method method1 = iclass.getMethod("getData",newClass[0]);//调用getData方法String data = (String) method1.invoke(istructor.newInstance(this),newObject[]{});System.out.println(data);} catch(Exception e) {
//TODO Auto-generated catch blocke.printStackTrace();}
2.创建库文件,也就是jar包的源代码。我们只需要在原来的工程中,新建一个android library moudle。目录如下,包含了一个接口和他的实现类
实现类代码如下:
public classIClass implementsIinterface {
privateContext context;publicIClass(Context context) {
super();this.context= context;}
@Overridepublic voidcall() {
Toast.makeText(context,"call method haha",Toast.LENGTH_SHORT).show();}
@OverridepublicString 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