`

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。

分享到:
评论

相关推荐

    apk加壳和动态加载技术

    动态加载技术 该技术在Java中是一个比较成熟的技术,而Android中该技术还没有被大家充分利用起来。该技术思想主要分为以下几步: 1.将核心代码编译成dex文件的Jar包 2. 对jar包进行加密处理 3.在程序主入口利用NDK...

    《Android系统源代码情景分析》

    《Android系统源代码情景分析》随书光盘内容(源代码) 目录如下: 第1篇 初识Android系统 第1章 准备知识 1.1 Linux内核参考书籍 1.2 Android应用程序参考书籍 1.3 下载、编译和运行Android源代码 ...

    Android高级编程--源代码

    作为使用androidsdk构建这些应用程序的实用指南书籍,《android高级编程》从始至终穿插了一系列示例项目,每个项目都引入android的新功能和新技术,以助您达到最圆满的学习效果。书中介绍android的所有基本功能,并...

    Android 3D游戏开发技术宝典-OpenGL ES 2.0 (吴亚峰) 源代码

    第1章 新一代的王者——android概览 1 1.1 智能手机市场现状 1 1.1.1 五大智能手机操作系统 1 1.1.2 智能手机市场的新星 2 1.2 android平台的特点及未来的趋势 3 1.2.1 全新理念带来的体验风暴 3 ...

    Android系统源代码情景分析光盘

    Android系统源代码情景分析光盘资料 目录 第1篇初识Android系统 第1章 准备知识................................................................ 2 1.1 Linux内核参考书籍......................................

    Android系统源代码情景分析-罗升阳-源码

    《Android系统源代码情景分析》随书光盘内容(源代码) 目录如下: 第1篇 初识Android系统 第1章 准备知识 1.1 Linux内核参考书籍 1.2 Android应用程序参考书籍 1.3 下载、编译和运行Android源代码 1.3.1 下载...

    基于small的Android动态加载实现.zip

    开放源代码:Android系统采用开放源代码模式,允许开发者自由访问、修改和定制操作系统,这促进了技术的创新和发展,使得Android系统具有高度的灵活性和可定制性。 多任务处理:Android允许用户同时运行多个应用程序...

    Android代码-安卓结合HTML5快速开发APP

    2,这是我结合Android与H5技术,利用webview,viewpager与PagerSlidingTab,文章均来自于微信热文精选。 3,webview本地缓存,没有网时也能浏览之前加载过的新闻 4,activity里用viewpager,viewpager的每个条目都是...

    Android代码-ApkProtect

    APK安全加固是面向移动应用程序的深度安全保护服务,可以为您的APP穿上一层“软猬铠甲”,通过加密、加壳、RPC、动态加载等技术为您的应用进行全方位安全保护,有效防止逆向工程、反编译、嵌入病毒、非法扣费等恶意...

    Android代码-外包项目聚合信息

    外包集中营 整合多个软件外包平台项目信息,替你筛选优质项目 关于我们 功能 首页 展示你关注的外包信息,比如: 移动app、网站开发、微信/小程序。...common            公用代码 a

    Android代码-AppInit

    AppInit 用于解决美团收银 B 端 App 在业务演进过程中的实际问题,取得了不错的效果,因此我们决定将其开源,希望更多技术同行一起开发,应用到更广泛的场景里去。 背景 随着业务的快速发展,新项目新业务不断出现,...

    android解决加载图片内存溢出

    android 解析加载图片是一个常用的技术 但是如何优化 这是一个问题 想要用户体验好必须加载速度快 稳定 那么你看了这个代码就明白了

    Adroid动态加载Apk-插件化技术框架(动态代理方案)源码

    Android动态加载Apk-插件化技术(动态代理方案) 一. 什么是插件化 1. 主App(宿主App)加载插件apk的实现 2. 每个业务组件模块形成一个独立的Apk, 然后通过主App动态加载部署业务组件模块Apk的一种方案 二.插件化的...

    Android代码-Componentization

    随着业务的发展 App 开发技术也越来越成熟,对开发者来说 App 代码量也迅速地增长到一个数量级。对于如何架构 App 已经每个开发者面临的实际问题。好的架构可以提高开发者的效率,降低维护成本。 由于业务增长引起...

    Android代码-玩安卓客户端

    添加Fragment懒加载V1.0.1 文章详情页添加收藏功能 修复几个小Bug 优化部分代码V1.0 首页 知识体系 登录、注册 收藏 搜索 分享 功能 登录和注册 登录 注册首页相关 首页文章列表 首页banner体系 知识体系 知识...

    android源代码 Rss阅读器

    原创 自己写的源代码 导入即可用 Android 应用程序开发技术 rss阅读器实例 实现通过Rss地址阅读到新闻 网页等内容 可自己添加Rss地址 并保存至数据库 功能强大

    Android代码-利用Android AccessibilityService 实现自动加好友,拉人进群聊

    版本的按键精灵,其实就是点点点,本项目仅用于技术研究学习之用,请勿用于商业用途,所以项目不会做任何适配! 只保证在笔者手机上是可以正常运行的,代码开源,有问题或者建议欢迎提issues。运行项目后,需要启用...

    Android代码-Android-Material-Sloth

    Sloth 项目介绍: 这是一个用于Android学习的项目,使用了代码家的...有新的技术也会不断往项目里面添加. 希望能通过这个项目技术有一定得提升.当然你也可以安装到手机上,空闲时间看看技术文章和妹纸. 效果:

    Android代码-WebView缓存例子

    做一个webview的页面,功能类似于微信发朋友圈一样,要求能上传本地图片到webview中进行展示,并按用户喜好添加和删除,当用户点击发布的时候,将这些图片上传至阿里云oss,收到oss响应后封装页面信息提交给服务器 ...

    Android代码-SimpleGitHub

    其中会使用一些比较新的流行技术,当做学习 目前使用到的(used Library) 响应式编程:rxJava 数据库:realm,尽管有些坑,但还是在继续使用(线程问题实在麻烦,还是换回SQLite) orm:greenDao 图片加载:glide 网络...

Global site tag (gtag.js) - Google Analytics