首先介绍一下要实现的效果:静默更新所有客户端应用程序中的jar包。

产生这个需求的原因:当做好的jar包发布出去,开发者已经在使用的情况下,有一天我们发现jar包中有个bug,这是我们就要去更新jar包,但是如果开发者需要更新jar包的话,那代价无疑是巨大的。出于减少开发者更新jar包的代价的目的。我们想到了使用这种方式来解决。整个项目的结构如下图:

Android 项目修改远程git android 远程更新_Android

插件管理框架工作流程:

客户端app启动时,插件管理框架读取本地所有插件信息,例如插件版本,提供者等等,并将该信息发送到插件管理服务端,在服务端监测是否有新的插件需要更新。如果有新的插件插件管理框架负责下载等操作。

具体的实现的话,为了统一,我们在插件管理框架中定义好接口,所有插件都要实现该接口,实现该接口的插件,我们就认为它是一个合法的插件。这样在application中我们就可以通过插件管理框架中的方法来调用插件中的方法。

插件管理框架主要模块:

1.插件管理:读取插件信息和服务端交互,根据返回判断是否下载新的插件。

2.调用插件中的方法。

       关于第一点就不多少了,就是一些网络访问和下载的东东。我们主要说一下调用插件中的方法。在使用jar包的使用我们知道如果是放在lib目录下,通过build path 加载到项目中,我们可以直接通过import导入使用jar包中的类和方法。但是插件的类和方法该怎么使用呢?这是我们就要使用到android的类加载器。android中有两种类加载器 DexClassLoader和PathClassLoader,两者的区别就是PathClassLoader只能加载已经安装到android系统中的apk文件,也就是/data/app/下的apk文件,加载其他位置的文件会报ClassNotFoundException ,DexClassLoader可以加载apk、jar和dex文件,而且可以加载sdcard下的文件。

先介绍一下我们的插件项目,该项目就是简单的做个加法运算。


package com.apkplug;

public class plugClass {

    public plugClass() {
        
    }
    public int  add(int a, int b){
        return a+b;
        
    }

    
}




在下面的介绍中我们使用DexClassLoader.首先我们来打包jar包并转换成dex文件,首先将写好的jar包导出,Export->java jarfile ->Next 然后选择jar的存放目录。然后我们将jar包转成dex格式,为了方便我们将jar包放到SDK的安装目录plarform-tools下,DOS进入这个目录,执行命令: dx --dex -ouput=classes.jar  Myplug.jar 这样我们就将Myplugin.jar转成了dex格式,我们将classes.jar 放到SDcard目录。下面在程序中我们使用DexClassLoader来加载classes.jar中的类

package com.apkplugtest;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;

import java.lang.reflect.Method;

import dalvik.system.DexClassLoader;
import dalvik.system.PathClassLoader;

public class MainActivity extends Activity {
    TextView tv = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById(R.id.tv);
        useDexClassLoader();
    }

    private void useDexClassLoader() {
       
        String dexPath = "/mnt/sdcard/classes.jar";
        String dexOutputDir = "/data/data/com.apkplugtest";

        DexClassLoader pathClassLoader = new DexClassLoader(dexPath, dexOutputDir, null, this
                .getClass().getClassLoader());
        // dexPath 目标jar或apk的路径 ; dexOutputDirdex 文件路径 ;null 目标类中使用的c/c++库存放的路径
        // ; 第四个参数 父装载类
        try {
            Class<?> class1 = pathClassLoader.loadClass("com.apkplug.plugClass");
            Object object = class1.newInstance();
            Class[] params = new Class[2];
            params[0] = Integer.TYPE;
            params[1] = Integer.TYPE;
            Method action = class1.getMethod("add", params);
            Integer ret = (Integer) action.invoke(object, 12, 13);
            tv.setText("method : " + action.getName() + ", return :" + ret);
        } catch (Exception e) {
            // TODO: handle exception
        }

    }

   

}



程序运行结果如下图:

Android 项目修改远程git android 远程更新_jar包_02

同时我们看到在data/data/com.apkplugtest下生成了.dex 文件如下图:

Android 项目修改远程git android 远程更新_Android 项目修改远程git_03


整个思路就是这样了。