插件框架篇一之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”;
选择Java/JAR file,Next;
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
下一页可以选择是否导出那些含有警告warning或者错误errors的*.class文件。一般不用理他,Next
下一个页面里可以对项目做一些配置
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中的类和方法。
- 插件框架篇一之jar插件加载方式
- 插件框架篇一之插件so库的加载
- 插件框架篇一之jar和apk打包
- 插件框架篇一之问题解决汇总
- 插件框架篇一之scrollbars
- Android插件技术——(一)动态加载jar
- VLC之加载插件(一)
- android中加载jar插件
- 插件框架篇一之Activity和Service
- 插件框架篇一之三星手机Dialog样式问题
- 插件框架一之ContentProvider和BroadcastReceiver
- 插件框架篇一之解决系统语言切换插件语言不变的问题
- 插件加载---之二
- CloudCompare插件编写一(插件框架)
- Android app中加载jar插件
- Android app中加载jar插件
- Android app中加载jar插件
- [转]Android app中加载jar插件
- DroidPlugin源码分析插件运行环境初始化
- 自动释放池
- 工作第二周 : 认识自己,踏实落地
- C - Push!!
- HDU5734 Acperience
- 插件框架篇一之jar插件加载方式
- 插件框架篇一之Activity和Service
- 插件框架一之ContentProvider和BroadcastReceiver
- 工厂方法(一)
- 插件框架一之主工程Application中theme使用主工程资源问题
- 类的定义
- android:关于自定义不能滑动的ViewPager后在使用View加载其所在的的布局时报错:Error inflating class view.NoscrollViewPager
- 区间最大频率
- 【leetcode】40Combination Sum II(回溯方法)