Android动态加载代码技术
Android动态加载代码技术
在开发Android App的过程当中,可能希望实现插件式软件架构,将一部分代码以另外一个APK的形式单独发布,而在主程序中加载并执行这个APK中的代码。
实现这个任务的一般方法是:

// 加载类cls
Context pluginContext = mainContext.createPackageContext(PLUGIN_PKG, Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE);
ClassLoader loader = pluginContext.getClassLoader();
Class<?> cls = loader.loadClass(CLASS_NAME);
// 通过反射技术,调用cls中的方法,下面是一个示例,实际代码因情况而定
Object obj = cls.newInstance();
Method method = cls.getDeclaredMethod("someMethod");
method.invoke(obj);

但是,这个方法在Android 4.1及之后的系统中存在一些问题:对于收费应用,Google Play会将其安装在一个加密目录之下(具体就是/data/app-asec),而不是一个普通目录之下(具体就是/data/app);安装在加密目 录中的应用,我们是无法使用上述方法来加载并执行代码的;而实际情况是,我们经常就是依靠插件应用来收费的。
解决上述问题的一个方案是:将插件的二进制代码拷贝到SD卡中,主程序从SD卡中加载并执行其代码。
实现这个任务的具体方法是:

Class<?> cls = null;
try { // 尝试第一种方法
cls = loadClass1(mainContext, pkg, entryCls);
} catch (Exception e) { // 尝试第二种方法
cls = loadClass2(mainContext, pkg, entryCls);
}// 示例代码Object obj = cls.newInstance();Method method = cls.getDeclaredMethod("someMethod");method.invoke(obj);
// 第一种加载方法private Class<?> loadClass1(Context mainContext, String pkg, String entryCls) throws Exception { Context pluginContext = mainContext.createPackageContext(pkg, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY); ClassLoader loader = pluginContext.getClassLoader(); return loader.loadClass(entryCls); }
// 第二种加载方法private Class<?> loadClass2(Context mainContext, String pkg, String entryCls) throws Exception { Context pluginContext = mainContext.createPackageContext(pkg, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY); String path = generatePluginDexPath(mainContext, pkg); ensureFileExist(pluginContext, pkg, path); // cacheDir必须是主程序的私有目录,否则DexClassLoader可能会拒绝加载 String cacheDir = mainContext.getApplicationInfo().dataDir; ClassLoader parentLoader = pluginContext.getClassLoader(); DexClassLoader loader = new DexClassLoader(path, cacheDir, null, parentLoader); return loader.loadClass(entryCls);}
// 获取程序版本号private int getVersionCode(Context context, String pkg) { PackageInfo info = null; int versionCode = 0; try { info = context.getPackageManager().getPackageInfo(pkg, PackageManager.GET_ACTIVITIES); versionCode = info.versionCode; } catch (Exception e) {} return versionCode;}
// 获取插件二进制代码的存储位置,注意做好版本控制;路径必须是以.dex结束,否则加载会出问题private String generatePluginDexPath(Context context, String pkg) { int version = getVersionCode(context, pkg); String path = getMyAppPath() + ".classes/" + pkg + version + ".dex"; return path;}
// 主程序在SD卡上的数据目录private String getMyAppPath() { return Environment.getExternalStorageDirectory().getAbsolutePath() + "/MyApp/";}
// 拷贝插件的二进制代码到SD卡private void ensureFileExist(Context pluginContext, String pkg, String path) throws Exception { File file = new File(path); if(file.exists()) return; file.getParentFile().mkdirs(); Resources res = pluginContext.getResources(); int id = res.getIdentifier("classes", "raw", pkg); InputStream in = res.openRawResource(id); FileOutputStream out = new FileOutputStream(file); try { byte[] buffer = new byte[1024 * 1024]; int n = 0; while((n = in.read(buffer)) > 0) { out.write(buffer, 0, n); } out.flush(); } catch (IOException e) { in.close(); out.close(); }}

插件工程这边也需要做相应的修改:
1.编译插件工程;
2.将bin目录之下的classes.dex拷贝到/res/raw目录之下;
3.重新编译插件工程;
4.发布插件APK。
来自 :frydsh
Android动态加载代码技术的更多相关文章
- Android 插件技术:动态加载dex技术初探
1.Android动态加载dex技术初探 http://blog.csdn.net/u013478336/article/details/50734108 Android使用Dalvik虚拟机加载可执 ...
- Android动态加载技术初探
一.前言: 现在,已经有实力强大的公司用这个技术开发应用了,比如淘宝,大众点评,百度地图等,之所以采用这个技术,实际上,就是方便更新功能,当然,前提是新旧功能的接口一致,不然会报Not Found等错 ...
- 深入浅出Android动态加载jar包技术
在实际项目中,由于某些业务频繁变更而导致频繁升级客户端的弊病会造成较差的用户体验,而这也恰是Web App的优势,于是便衍生了一种思路,将核心的易于变更的业务封装在jar包里然后通过网络下载下来,再由 ...
- Android 动态加载 (一) 态加载机制 案例一
在目前的软硬件环境下,Native App与Web App在用户体验上有着明显的优势,但在实际项目中有些会因为业务的频繁变更而频繁的升级客户端,造成较差的用户体验,而这也恰恰是Web App的优势.本 ...
- 从高德 SDK 学习 Android 动态加载资源
前不久跑去折腾高德 SDK 中的 HUD 功能,相信用过该功能的用户都知道 HUD 界面上的导航转向图标是动态变化的.从高德官方导航 API 文档中 AMapNaviGuide 类的描述可知,导航转向 ...
- Android动态加载jar、apk的实现
前段时间到阿里巴巴参加支付宝技术分享沙龙,看到支付宝在Android使用插件化的技术,挺好奇的.正好这几天看到了农民伯伯的相关文章,因此简单整理了下,有什么错误希望大神指正. 核心类 1.1 ...
- android动态加载
转载自: http://www.cnblogs.com/over140/archive/2012/03/29/2423116.html http://www.cnblogs.com/over140/a ...
- [转载] Android动态加载Dex机制解析
本文转载自: http://blog.csdn.net/wy353208214/article/details/50859422 1.什么是类加载器? 类加载器(class loader)是 Java ...
- Android 动态加载 (二) 态加载机制 案例二
探秘腾讯Android手机游戏平台之不安装游戏APK直接启动法 重要说明 在实践的过程中大家都会发现资源引用的问题,这里重点声明两点: 1. 资源文件是不能直接inflate的,如果简单的话直接在程序 ...
随机推荐
- Linux下安装memcached图文版
所用到的工具: putty小软件 可以远程连接主机的小软件 然后在屏幕上输入用户名root 密码:******即可连接 由于安装这两个工具需要编译所以:第一步要进行安装编译: 习惯于将下载 ...
- Objective-C中release和nil的关系
(iphone/ipad)浅谈Objective-C中release和nil的关系 分类: iPhone/iPad开发技术2011-12-09 01:40 2515人阅读 评论(4) 收藏 举报 ui ...
- oracle starup报错
今天在linux里面安装Oracle的时候出现一个报错,忽略报错安装之后,数据库启动的时候报错: 从网上找到的解决方法: 创建实例后,进入sqlplus启动报错: sqlplus / as sysdb ...
- JS 浮点计算BUG
最近做项目的时候遇到一个比较纠结的js浮点计算问题. 当时是做利率计算,因为利率大多数涉及到小数点,精度要求也很高. 0.6+0.1+0.1=? 结果出现:0.7999999999999 网上查找了一 ...
- rsync实现文件备份同步(比如服务器镜像)
[rsync实现网站的备份,文件的同步,不同系统的文件的同步,如果是windows的话,需要windows版本cwrsync] 一.什么是rsync rsync,remote synchronize顾 ...
- PowerShell 管道和对象成员
2.1 管道 在各种现代的shell中,均支持管道的概念. 管道的最大特点就是: 前一个命令的输出作为后一个命令的输入.cmd.bash均支持管道的概念,这里我就不多说了,下面我们说说PS中 管道 ...
- esxi5.5 安装,虚拟机复制
尝试在vmware workstation上安装hadoop,感觉太慢了. 好在家里的台式机配置还可以,所以就想在它上面虚拟出几台服务器出来. 台式机配置如下: 虚拟出来三个应该没问题了吧. 第一步, ...
- 给Select赋值 innerHTML 不兼容IE6\IE7\IE8\IE9
<select class="b-select" id="location-province" name="Province" def ...
- linux下添加中文输入法
一.安装环境 查看linux版本号 [ztteng@ztteng ~]$ lsb_release -aLSB Version: :core-4.0-ia32:core-4.0-noarch:gr ...
- 格而知之15:我所理解的Block(1)
1.Block 本质上是一个struct结构体,在这个结构体中,最重要的成员是一个函数(当然除函数外还有其他重要的成员). 2.在开始解析Block之前,首先来回顾一下Block的格式.Block相关 ...