Android动态加载包含so文件的jar的自定义view控件
2015-05-29 15:08
621 查看
公司要求把某自定义view控件打包成jar,提供给某项目(这里叫它APP吧)通过网络下载的方式实现动态加载控件,该APP通过反射来构造出该view,并且调用里面的方法。这样通过反射动态加载的方式(暂且叫他反射方式)和普通的把自定义view的jar导入工程预先加载的方式(暂且叫它预先加载)不同的是:
1.预先加载是先把jar复制到工程下的lib目录,然后 build path,使用该自定义的方法是通过 new 这个view的构造方法来产生,然后再通过该view的实例对象来操作里面的public方法。
2.反射动态加载的方式就比较酷炫了,可以通过网络下载jar和它的一些资源文件(比如so文件、drawable资源、assets资源等等),实现动态添加APP的功能模块,首先通过dexClassLoader来加载下载下来的jar(比如保存在SD卡某目录),然后通过反射调用,从而实例出该view使用动态加载自定义view的好处:
(1)当更新APP某功能模块时,不需要用户再次下载整个APP来重新安装,只需要下载新jar来重新
动态加载就OK了(要知道,让用户下完整个APP来更新的用户体检很差的,动不动就是下载安
装)。
(2)减小APP的体积,用户需要哪些功能模块,就让他去自由的选择下载(对应jar和所需的资源文
件),反正我是不想看到APP里我不需要的功能。
开始现实动态加载
1.编写完自定义view的代码时,如果有drawable 文件,不能用普通R.来获取,不然会报找不到资源id错误,应该这么获取drawable的id:
path传入SD卡上的drawable资源(不能再把图片等资源放在drawable目录下了)
2.如果有用到JNI的,不能把so文件一起打包到jar里面,需要在程序加载view前拷贝到APP的data/data/包名下的某目录(可以自己新建),然后把所有System.loadLibrary()改成 System.load(),路径就是刚才存放so文件的路径。拷贝代码如下:
3.在APP用dexClassLoader来加载jar,拿到class后再用它获取构造方法,再用该构造方法newInstance得到view的最终实例对象。代码如下:
4.反射调用方法。
到这里就可以实现和jar里面的view交互了。
1.预先加载是先把jar复制到工程下的lib目录,然后 build path,使用该自定义的方法是通过 new 这个view的构造方法来产生,然后再通过该view的实例对象来操作里面的public方法。
2.反射动态加载的方式就比较酷炫了,可以通过网络下载jar和它的一些资源文件(比如so文件、drawable资源、assets资源等等),实现动态添加APP的功能模块,首先通过dexClassLoader来加载下载下来的jar(比如保存在SD卡某目录),然后通过反射调用,从而实例出该view使用动态加载自定义view的好处:
(1)当更新APP某功能模块时,不需要用户再次下载整个APP来重新安装,只需要下载新jar来重新
动态加载就OK了(要知道,让用户下完整个APP来更新的用户体检很差的,动不动就是下载安
装)。
(2)减小APP的体积,用户需要哪些功能模块,就让他去自由的选择下载(对应jar和所需的资源文
件),反正我是不想看到APP里我不需要的功能。
开始现实动态加载
1.编写完自定义view的代码时,如果有drawable 文件,不能用普通R.来获取,不然会报找不到资源id错误,应该这么获取drawable的id:
</pre><pre name="code" class="java">public class ResourceUtils { public static int getIdByName(Context context, String className, String name) { String packageName = context.getPackageName(); Class r = null; int id = 0; try { r = Class.forName(packageName + ".R"); Class[] classes = r.getClasses(); Class desireClass = null; for (int i = 0; i < classes.length; ++i) { if (classes[i].getName().split("\\$")[1].equals(className)) { desireClass = classes[i]; break; } } if (desireClass != null) id = desireClass.getField(name).getInt(desireClass); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } return id; }
path传入SD卡上的drawable资源(不能再把图片等资源放在drawable目录下了)
2.如果有用到JNI的,不能把so文件一起打包到jar里面,需要在程序加载view前拷贝到APP的data/data/包名下的某目录(可以自己新建),然后把所有System.loadLibrary()改成 System.load(),路径就是刚才存放so文件的路径。拷贝代码如下:
public static void copySoLib(Context context, String dexPath, String nativeLibDir) { try { ZipFile zip = new ZipFile(dexPath); Enumeration<? extends ZipEntry> entries = zip.entries(); while (entries.hasMoreElements()) { ZipEntry ze = (ZipEntry) entries.nextElement(); if (ze.isDirectory()) { continue; } String zipEntryName = ze.getName(); if (zipEntryName.endsWith(".so")) { String libName = zipEntryName.substring(zipEntryName.lastIndexOf("/") + 1); InputStream ins = zip.getInputStream(ze); FileOutputStream fos = new FileOutputStream(new File(nativeLibDir, libName)); byte[] buf = new byte[8192]; int len = -1; while ((len = ins.read(buf)) != -1) { fos.write(buf, 0, len); } fos.flush(); fos.close(); ins.close(); Log.d(TAG, "copy so lib success: " + zipEntryName); } } zip.close(); } catch (IOException e) { e.printStackTrace(); } }dexPath是so的压缩包在SD卡的路径。
3.在APP用dexClassLoader来加载jar,拿到class后再用它获取构造方法,再用该构造方法newInstance得到view的最终实例对象。代码如下:
ClassLoader dexLoader = new DexClassLoader(jarPath, dexPath, libPath, context.getClassLoader()); Class<?> mClass = dexLoader.loadClass("com.xxx.xxx.MyPluginView"); Object mViewObj = jarConstructor.newInstance(context);mViewObj就是我们实例出来的view了,可以强制类型转换成view然后直接拿来add。
4.反射调用方法。
Method method = mClass.getMethod("方法名",int.class,........); method.invoke(mViewObj, new Object[]{width});
到这里就可以实现和jar里面的view交互了。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories