Android动态加载外部jar文件

Java具有将文件、网络中的类以字节码形式加载到运行程序中的功能,基于Java的Android也可以如此实现。实现这种方法后,程序可以进行模块化设计,各种方法支持热插拔,APP可以在想要更新的情况下进行方法的后台静默更新。
以上,这种方法可以带来很大的便利,本文就来讲如何实现这个功能。
  
本文开发环境使用Eclipse。

  

###1. jar和dex文件的制作

在Eclipse里新建一个Java Project,新建一个类Maths,实现一个自定义的add(int,int)功能。

public class Maths {
    public int add(int i1, int i2){
        return i1 + i2 - 1;
    }
}

右键项目 — Export — JAR File,将这个类导出为maths.jar。

由于Android虚拟机使用的是dex的文件格式,所以在此需要使用dx.bat把导出的jar换为dex格式。本文中,Android SDK目录为F:\SDK,使用build-tools版本为21.1.1,在CMD中更改目录至”F:\SDK\build-tools\21.1.1”,输入以下命令:

dx --dex --output=output.jar input.jar 

注意将将上面的input.jaroutput.jar换成想要的文件名,并把maths.jar文件复制到dx.bat所在目录。

###2. 创建一个Android项目

复制maths.jar到Android手机卡根目录,并使用[DexClassLoader][1]加载类,使用反射获得类中的方法,并打印出来,代码如下:

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    loader(this);
}

void loader(Context context){
    try{
        //外部jar文件的路径
        File jar = new File(Environment.getExternalStorageDirectory()
                + File.separator + "Dexmaths.jar");
        //临时放置编译dex文件的位置
        File file = context.getDir("tmp", 0);

        Log.i("jar", jar.getAbsolutePath());
        Log.i("file", file.getAbsolutePath());

        //加载外部类
        DexClassLoader dcl = new DexClassLoader(
                jar.getAbsolutePath(), file.getAbsolutePath(), null, 
                context.getClassLoader());
        //将Maths类的字节码加载到maths中
        Class<?> maths = dcl.loadClass("Maths");
        //查看获得的类名
        Object math = maths.newInstance();
        Log.i("class", math.getClass().getName());
        //使用反射执行add()方法
        Method method = maths.getMethod("add", int.class, int.class);
        int k = (int) method.invoke(math, 1, 2);
        Log.i("class", "result = " + k);
    }
    catch(Exception e){
        e.printStackTrace();
    }
}

}

其中DexClassLoader是实现功能的核心,它加载了外部jar并编译成dex文件,并可以加载类的字节码到Class对象中,之后就可以通过Java基本的反射方法进行方法的执行。

DexClassLoader构造函数说明:

参数 说明
dexPath 包含类和资源文件的jar/apk文件列表,使用:分开
optimizedDirectory 放置优化后的dex文件的目录,必须不为null
libraryPath 包含本地library的目录列表,使用:分开,可以为null
parent 父类类加载器

###3. 执行结果
程序执行后LogCat显示如下:
此处输入图片的描述

在jar里定义的函数被成功执行,这就说明APP成功地加载了jar包。

查看cache文件夹,发现这里存放着生成的dex文件:
此处输入图片的描述

参考文献

  1. Android用DexClassLoader实现动态调用jar包
文章目录