插件框架篇一之jar插件加载方式

来源:互联网 发布:c语言中char使用例子 编辑:程序博客网 时间:2024/04/30 14:50

随着项目的不断扩大,遇到问题如下:
1、代码也将变得臃肿,而且每次应用更新都需要下载很大的应用包;
2、多项目之间模块重用;
3、项目管理复杂度增加;
4、每次修改模块bug都需要提交应用商店审核。
为了解决以上问题,接下来将分别研究jar插件(dex)和apk插件两种框架。
本文主要介绍jar插件的两种加载方式:静态加载和动态加载。
准备工作如下:
1、win7 64位环境下;
1、测试代码如下:

package com.demo.jar;public class AddFunc{    public AddFunc(){}    public int Add(int a, int b){        int c  = a + b;        return c;    }}

2、将D:\work\sdk\build-tools\19.1.0添加到环境变量中,方便使用dx命令。

一、静态jar插件加载
(1)生成静态插件:
如果是简单的java类文件,可以通过命令来编译生成jar插件库:
D:>javac com/demo/jar/AddFunc.java //编译生成AddFunc.class
D:>jar cvf AddFunc.jar com/demo/jar/AddFunc.class //压缩生成jar文件
标明清单(manifest)
增加:com/demo/jar/AddFunc.class(读入= 267) (写出= 213)(压缩了 20%)
D:>jar tvf AddFunc.jar //查看生成的jar文件里有哪些内容
0 Fri Sep 05 10:22:36 CST 2014 META-INF/
71 Fri Sep 05 10:22:38 CST 2014 META-INF/MANIFEST.MF
267 Fri Sep 05 10:20:44 CST 2014 com/demo/jar/AddFunc.class
如果是工程代码的话,可以通过Eclipse导出为jar库,步骤如下:
1. 首先在Eclipse中打开项目, 右键点击项目,选择“Export”;

  1. 选择Java/JAR file,Next;

  2. Select the resources to export中可以选择你想要包含的项目文件夹,一些不必要的文件夹就无需放进去了,免得增大空间;

这里有几个选项:

* Export generated class files and resources 表示只导出生成的.class文件和其他资源文件* Export all output folders for checked projects 表示导出选中项目的所有文件夹* Export java source file and resouces 表示导出的jar包中将包含你的源代码*.java,如果你不想泄漏源代码,那么就不要选这项了* Export refactorings for checked projects 把一些重构的信息文件也包含进去

在Select the export destination中选择导出的jar的路径,Next

  1. 下一页可以选择是否导出那些含有警告warning或者错误errors的*.class文件。一般不用理他,Next

  2. 下一个页面里可以对项目做一些配置

    • Generate the manifest file是系统帮我们自动生成MANIFEST.MF文件,如果你的项目没有引用其他class-path,那可以选择这一项;

    • Use existing mainfest from workspace。这是可以选择我们自定义的.MF文件,格式如上所写;

    • Seal content。要封装整个jar或者指定的包packet;

    • Main class。这里可以选择你的程序入口,将来打包出来的jar就是你这个入口类的执行结果;

配置完点击Finish,工程的jar文件就生成了。

(2)静态插件的使用:
通过Eclipse的Build Path–> Libraries–> Add JARs进行加载jar插件。

二、动态加载jar插件
(1)jar插件的生成:
D:>javac com/demo/jar/AddFunc.java //编译生成AddFunc.class
D:>dx –dex –output=AddFunc.jar com/demo/jar/AddFunc.class //压缩生成jar文件
D:>jar tvf AddFunc.jar //查看生成的jar文件里有哪些内容
72 Fri Sep 05 10:38:28 CST 2014 META-INF/MANIFEST.MF
556 Fri Sep 05 10:38:28 CST 2014 classes.dex
通过以上命令可以生成AddFunc.jar。在这里需要说明的是AddFunc.class必须按照包名放置,否则生成jar会报错。
其实假如本身就在Android工程下面,那么可以现在eclipse下面先编译程序,后在Bin目录下面,自然就按包名,放置了class文件,再将需要的class文件包含文件目录拷贝至D:/com/demo/jar目录下就好了。
假设我们需要打包两个class,就可以通过如下命令实现:
D:>dx –dex –output=AddFunc.jar com/demo/jar/AddFunc.class com/demo/jar/GameView.class
假如现有静态加载jar文件,如果需要转化成动态加载文件可以通过dx命令转化:
这里写图片描述
(2)动态jar插件的使用:
应用中jar存放路径:
1、sd卡中(代码暴露,容易代码注入);
2、应用程序安装目录下data/data/包名/(相对比较安全,context.getDir(“dex”, Context.MODE_PRIVATE))。
这里我们采取第二种方式,jar文件可以通过下载或放到assets中等方式进行包装,本文为了简单化就放到assets下,原理大致一样。
代码流程如下:
1、将jar文件复制到/data/data/包名/dex/目录下:

/** * @author chenlifeng1 * @param context * @param jarname * @return jar存放路径 * 将jar插件存放到应用目录下,不放到扩展存储设备中,防止代码注入 */public static String copyJar(Context context, String jarname){    File dexInternalStoragePath = new File(context.getDir("dex", Context.MODE_PRIVATE), jarname);    BufferedInputStream bis = null;    OutputStream dexWriter = null;    final int BUF_SIZE = 8 * 1024;    try {        bis = new BufferedInputStream(context.getAssets().open(jarname));        dexWriter = new BufferedOutputStream(new FileOutputStream(dexInternalStoragePath));        byte[] buf = new byte[BUF_SIZE];        int len;        while((len = bis.read(buf, 0, BUF_SIZE)) > 0) {            dexWriter.write(buf, 0, len);        }        dexWriter.close();        bis.close();    } catch (Exception e) {    }    return dexInternalStoragePath.getAbsolutePath();}

2、通过反射机制进行调用:

/** * @param context * @param jarname  插件文件名 *.jar * @param packagename 插件包名 * @param classname  插件包名后面的路径 不需要.class后缀 * @return 返回class实例 */public static Class loadClass(Context context, String jarname, String packagename, String classname){    File dexInternalStoragePath = new File(context.getDir("dex", Context.MODE_PRIVATE), jarname);    File optimizedDexOutputPath = context.getDir("outdex", Context.MODE_PRIVATE);    Class myClass = null;    if(dexInternalStoragePath.exists()){        try {            DexClassLoader cl = new DexClassLoader(dexInternalStoragePath.getAbsolutePath(),                    optimizedDexOutputPath.getAbsolutePath(), null, ClassLoader                    .getSystemClassLoader().getParent());            String clazzname = packagename+"."+classname;            AppLog.log("aa","...clazzname is "+clazzname);            myClass = cl.loadClass(clazzname);        } catch (Exception e) {            AppLog.log("aa","...ex is "+e.getMessage());        }    }    return myClass;}
//Test1Util.copyJar(getApplicationContext(), "dexed.jar");Class clazz = JarLoader.loadClass(getApplicationContext(), "dexed.jar", "cn.com.iresearch.mapptracker", "IRMonitor");try {    Method action = clazz.getMethod("getInstance", new Class[]{Context.class});    Object iRmonitor = action.invoke(clazz, new Object[]{MainActivity.this});    AppLog.log("aa", "...iRmonitor is "+iRmonitor);    String makey = "440e9707b1c3669a";    String deviceId = "12345678";    boolean isDebug = true;    Method iRmethod = clazz.getMethod("Init", new Class[]{String.class, String.class, boolean.class});   //boolean.class小写    AppLog.log("aa", "...iRmethod is "+iRmethod);    iRmethod.invoke(iRmonitor, new Object[]{makey, deviceId, isDebug});    textview1.setText("class is "+iRmonitor.getClass().getSimpleName());} catch (Exception e) {    textview1.setText("error is "+e.getMessage());}//test2Util.copyJar(getApplicationContext(), "AddFunc.jar");Class clazz2 = JarLoader.loadClass(getApplicationContext(), "AddFunc.jar", "com.demo.jar", "AddFunc");try {    Object obj2 = clazz2.newInstance();    Method addMethod = clazz2.getMethod("Add", new Class[]{int.class, int.class});    int rt = (Integer) addMethod.invoke(obj2, new Object[]{20, 21});    textview2.setText("20+21="+rt);} catch (Exception e) {    textview2.setText("error is "+e.getMessage());}

运行结果如下:
这里写图片描述
其实从原理上来说,如上生成的动态jar插件,跟apk的生成是同一个道理,所以假设我们不想通过繁琐的dx工具,那么也可以直接由eclipse生成apk,然后通过动态加载的方法来使用apk中的类和方法。

0 0
原创粉丝点击