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的,如果简单的话直接在程序 ...
随机推荐
- AFNetworiking与ASIHttpRequest对比
在开发iOS应用过程中,如何高效的与服务端API进行数据交换,是一个常见问题.一般开发者都会选择一个第三方的网络组件作为服务,以提高开发效率和稳定性.这些组件把复杂的网络底层操作封装成友好的类和方法, ...
- 简单的使用php多线程抓取网页
PHP 利用 Curl Functions 可以完成各种传送文件操作,比如模拟浏览器发送GET,POST请求等等,受限于php语言本身不支持多线程,所以开发爬虫程序效率并不高,这时候往往需 要借助Cu ...
- Win8.1专业版、核心板和企业版有什么区别
Win8.1核心版(一般就称之为Windows 8.1) + Win8.1 专业版(称之为Windows 8.1 Pro),根据用户输入的序列号(就是Win8密钥)来区分安装.Win8.1企业版(称之 ...
- Android之SharedPreferences两个工具类
相信Android的这个最简单的存储方式大家都很熟悉了,但是有一个小小技巧,也许你没有用过,今天就跟大家分享一下,我们可以把SharedPreferences封装在一个工具类中,当我们需要写数据和读数 ...
- eclipse编辑工具小结
eclipse编辑工具小结 这两天从myeclipse转入eclipse,整体感觉不错,速度更快些,也没在出现各种意外的调试错误.不能断点等情况,并且对整个编辑环境的使用有了更深入的认识,再次对主要几 ...
- LINQ to SQL 增,删,改
添加 InsertOnSubmit(单个对象) 或 InsertAllOnSubmit(集合) 删除 DeleteOnSubmit (单个对象) DeleteAll ...
- cStringIO模块例子
# Vorbis comment support for Mutagen # Copyright 2005-2006 Joe Wreschnig # # This program is free so ...
- Spark函数详解系列之RDD基本转换
摘要: RDD:弹性分布式数据集,是一种特殊集合 ‚ 支持多种来源 ‚ 有容错机制 ‚ 可以被缓存 ‚ 支持并行操作,一个RDD代表一个分区里的数据集 RDD有两种操作算子: ...
- Codeforces 549F Yura and Developers
probelm 题意 给定一个序列和一个mod值,定义[l,r]合法当l到r的全部元素和减去当中的最大值的结果能够整除mod.问共同拥有多少区间合法. 思路 一開始想的分治. 对于一个[l,r]我们能 ...
- [R语言画图]气泡图symbols
绘制气泡图主要使用函数symbols(x,y,circle=r).当中x.y是坐标轴,r是每一个点的半径. x<-rnorm(10) y<-rnorm(10) r<-abs(rnor ...