好久没有写博客了,这次准备写写我这几天的研究成果——Android插件化开发框架CJFrameForAndroid。

好久没有写博客了,这次准备写写我这几天的研究成果——Android插件化开发框架CJFrameForAndroid。

背景交代

首先。你须要知道什么是插件化开发。

就拿最常见的QQ来说,在第三个界面动态那里有个管理,点开后能够选择非常多的增植功能,这里腾讯仅仅放了一些网页应用。那么假设未来想增加一个打飞机游戏,要怎么做?让用户又一次安装吗。这就是插件化开发所解决的问题。

用一句话来概括插件式开发:你基本上能够理解为让一个apk不安装也能够被执行。

仅仅只是这个执行是有非常多限制的执行,所以才叫插件否则就叫病毒了。

事实上在眼下淘宝、百度、腾讯、等都有成熟的动态载入框架,包含apkplug,可是它们都是不开源的。

说一下我觉得这项技术的难点:1、一个未被安装的apk正常情况无法被执行。2、这个apk的资源没办法被引用;3、这个apk的界面就算被载入,也没办法与用户交互。

最初查遍了资料,第一点好解决,在Android中有一个dexClassLoad类载入器,大家应该明确了,就是通过反射载入一个类来执行。第二点,网上有两种方法:能够将插件的资源放到sd卡上通过流的形式读取,只是也有人反对说用流读取会有问题,通配性太差;一种比較好的解决的方法是将apk中的资源复制一份到当前app内。然后就能够载入了。

这样的办法是不错,可是用户每下载一次插件就复制一份。久而久之,对空间要求太高了。还有就是第三点也没办法解决。而第三点,在github上有一个叫AndroidDynamicLoader的项目,是通过用Fragment做为插件的表现形式,因为Fragment特殊性(既能够处理逻辑交互又具备与Activity同样的生命周期)。可是Fragment限制性太大了,太过碎片化使得使用起来复杂性过高。直到我找到了一篇360的官方博客。博客给了一种思路:通过代理/托付模式设计的Application类去动态的改变一个apk所在的环境。实现动态载入的目的。抱着这样的思路,我曾想自己去设计一个application类,可是技术有限,太复杂了,于是结合AndroidDynamicLoader的思路与360的思路。我自己设计了一个Activity去代理插件的Activity。于是就有了CJFrameForAndroid.

原理描写叙述

首先解释几个名词:

APP项目:指要调用插件apk的那个已经安装到用户手机上的应用。

插件项目:指没有被安装且希望借助已经安装到手机上的项目执行的apk。

插件化:Activity继承自CJActivity,且与APP项目jar包冲突已经解决的插件项目称为已经被插件化。

Activity事务:在CJFrameForAndroid中,一个Activity的生命周期以及交互事件统称为Activity的事务。

托管所:指插件中的一个委派/代理Activity,通过这个Activity去处理插件中Activity的所有事务,从而表现为就像插件中的Activity在执行一样。

CJFrameForAndroid的实现原理是通过类载入器,动态载入存在于SD卡上的apk包中的Activity。通过使用一个托管所。插件Activity所有事务(包含声明周期与交互事件)将交由托管所来处理,间接实现插件的执行。

一句话描写叙述:CJFrameForAndroid中的托管所。复制了插件中的Activity。来替代插件中的Activity与用户交互。

看到这里你应该就明确了,整个框架最核心的部分就是这个托管所。这里给出CJFrameForAndroid中这个托管所的细节代码:

  1. /**
  2. * 通过反射。获取到插件的资源訪问器
  3. */
  4. protected void initResources() {
  5. try {
  6. AssetManager assetManager = AssetManager.class.newInstance();
  7. Method addAssetPath = assetManager.getClass().getMethod(
  8. "addAssetPath", String.class);
  9. addAssetPath.invoke(assetManager, mDexPath);
  10. mAssetManager = assetManager;
  11. } catch (Exception e) {
  12. e.printStackTrace();
  13. }
  14. Resources superRes = super.getResources();
  15. mResources = new Resources(mAssetManager, superRes.getDisplayMetrics(),
  16. superRes.getConfiguration());
  17. mTheme = mResources.newTheme();
  18. mTheme.setTo(super.getTheme());
  19. }
  20.  
  21. /**
  22. * 启动插件的Activity
  23. */
  24. protected void launchPluginActivity() {
  25. PackageInfo packageInfo = CJTool.getAppInfo(this, mDexPath);
  26. if ((packageInfo.activities != null)
  27. && (packageInfo.activities.length > 0)) {
  28. String activityName = packageInfo.activities[mAtyIndex].name;
  29. mClass = activityName;
  30. launchPluginActivity(mClass);
  31. }
  32. }
  33.  
  34. /**
  35. * 启动指定的Activity
  36. *
  37. * @param className
  38. * 要启动的Activity完整类名
  39. */
  40. protected void launchPluginActivity(final String className) {
  41. try {
  42. Class<?
  43.  
  44. > atyClass = getClassLoader().loadClass(className);
  45. Constructor<?> atyConstructor = atyClass
  46. .getConstructor(new Class[] {});
  47. Object instance = atyConstructor.newInstance(new Object[] {});
  48. setRemoteActivity(instance);
  49. mPluginAty.setProxy(this, mDexPath);
  50. Bundle bundle = new Bundle();
  51. bundle.putInt(CJConfig.FROM, CJConfig.FROM_PROXY_APP);
  52. mPluginAty.onCreate(bundle);
  53. } catch (Exception e) {
  54. e.printStackTrace();
  55. }
  56. }
  57.  
  58. /**
  59. * 保留一份插件Activity对象
  60. */
  61. protected void setRemoteActivity(Object activity) {
  62. if (activity instanceof I_CJActivity) {
  63. mPluginAty = (I_CJActivity) activity;
  64. } else {
  65. throw new ClassCastException(
  66. "plugin activity must implements I_CJActivity");
  67. }
  68. }

本框架眼下不过一个开发阶段,不过实现了插件Activity的执行(原理上来说,动态注冊的广播也能够执行),而Service、contentProvider都没办法使用,这些都仍在研究中。

在未来的某一天,或许会将这个CJFrameForAndroid插件框架与KJFrameForAndroid快捷开发框架合并。组成一个更完好应用开发框架,对自己说:加油!

●眼下仅支持Activity和Fragment,Service,动态注冊的广播,Activity LaunchMode,注解式开发。

●APP项目和插件项目中。都须要使用到CJFrameForAndroid的jar包。

●在项目中必须增加托管所声明。

●在开发插件的时候。必须继承CJActivity;

●在插件的Activity中,一切使用this的部分必须使用that来替代;

●在插件Activity跳转时,推荐使用CJActivityUtils类来辅助跳转。

●在插件和APP两个project中不能引用同样的jar包。

Android插件化开发,初入殿堂的更多相关文章

  1. Android插件化开发

    客户端开发给人的印象往往是小巧,快速奔跑.但随着产品的发展,目前产生了大量的门户型客户端.功能模块持续集成,开发人员迅速增长.不同的开发小组开发不同的功能模块,甚至还有其他客户端集成进入.能做到功能模 ...

  2. Android插件化开发---执行未安装apk中的Service

    欢迎各位增加我的Android开发群[257053751​] 假设你还不知道什么叫插件化开发.那么你应该先读一读之前写的这篇博客:Android插件化开发,初入殿堂 上一篇博客主要从总体角度分析了一下 ...

  3. Android 插件化开发(四):插件化实现方案

    在经过上面铺垫后,我们可以尝试整体实现一下插件化了.这里我们先介绍一下最简单的实现插件化的方案. 一.最简单的插件化实现方案 最简单的插件化实现方案,对四大组件都是适用的,技术面涉及如下: 1). 合 ...

  4. Android 插件化开发(一):Java 反射技术介绍

    写在前面:学习插件化开发推荐书籍<Android 插件化开发指南>,本系列博客所整理知识部分内容出自此书. 在之前的项目架构的博文中,我们提到了项目插件化架构,提到插件化架构不得不提的到J ...

  5. 《Android插件化开发指南》面世

    本书在京东购买地址:https://item.jd.com/31178047689.html 本书Q群:389329264 (一)这是一本什么书 如果只把本书当作纯粹介绍Android插件化技术的书籍 ...

  6. 《Android插件化开发指南》勘误

    一些常识: 1)全书70个代码例子中,涉及到插件的例子,请先assemble插件的项目,这会在HostApp项目中生成assets目录,并在该目录下plugin1.apk.这样,HostApp才能正常 ...

  7. Android插件化开发之解决OpenAtlas组件在宿主的注冊问题

    OpenAtlas有一个问题,就是四大组件必须在Manifest文件里进行注冊,那么就必定带来一个问题,插件中的组件都要反复在宿主中注冊.像Service,ContentProvider等组件眼下没有 ...

  8. 【我的Android进阶之旅】Android插件化开发学习资料

    1.目前开源的插件开发框架大致有哪些? 1. 任玉刚 的 dynamic-load-apk Github 地址:https://github.com/singwhatiwanna/dynamic-lo ...

  9. 详解Android插件化开发-资源访问

    动态加载技术(也叫插件化技术),当项目越来越庞大的时候,我们通过插件化开发不仅可以减轻应用的内存和CPU占用,还可以实现热插拔,即在不发布新版本的情况下更新某些模块.     通常我们把安卓资源文件制 ...

随机推荐

  1. 让vim的在输入模式下现实光标不同

    前几天用过苹果之后,发现vim中在插入模式下与命令模式下光标形状不同,根据光标形状就可以快速确认所在的模式,很方便,后来查了很多资料,一直查到官方的wiki也没有搞定,后来,终于搞定,现记录如下:我的 ...

  2. XAudio2播放PCM

    XAudio2 是一个跨平台的API,在Xbox 360及Windows中得到支持.在Xbox 360上, XAudio2作为一个静态库编译到游戏可执行文件中.在Windows上,XAudio2提供一 ...

  3. Python学习杂记_12_函数(三)

    内置函数 Python有很多内置函数,以下这些是常用且必须要掌握的: 强制类型转换: bool() # 把一个对象转换成布尔类型 int() # 整形 float() # 小数 str() # 字符 ...

  4. python 实现经典算法

    import time start_time = time.clock() list_ = [9, 2, 7, 4, 5, 6, 3, 8, 1] """ # 堆排序(通 ...

  5. Hibernate 快速上手操作入门

    本文主要是从技术操作角度去介绍hibernate,并且简单描述如何快速的上手操作hibernate,用于作为与数据库的连接的持久层. 简单讲述一下hibernate究竟是什么,它有什么作用,在理解它的 ...

  6. (10)ERStudio

     1.外键 https://jingyan.baidu.com/article/f79b7cb37e9d219144023ea6.html 第一个图标:Identifying Relationship ...

  7. (1)oracle安装、卸载、启动、关闭、登陆以及同时遇到的问题

    数据库概念 在oracle里数据库是一个静态的概念,数据库的资料保存在硬盘上,一个数据库可以有多个实例 数据库实例 数据库实例是一个动态的概念,它是进程+这个进程的内存块.就把它当成个指针吧,这个指针 ...

  8. spoj - Distinct Substrings(后缀数组)

    Distinct Substrings 题意 求一个字符串有多少个不同的子串. 分析 又一次体现了后缀数组的强大. 因为对于任意子串,一定是这个字符串的某个后缀的前缀. 我们直接去遍历排好序后的后缀字 ...

  9. jdbc多种实现方式

    1,驱动加载 //注册驱动 //DriverManager.registerDriver(new Driver());此方法被淘汰 Class.forName("com.mysql.jdbc ...

  10. TranslateAnimation详解 Android动画。

    TranslateAnimation详解 Android JDK为我们提供了4种动画效果,分别是: AlphaAnimation,RotateAnimation, ScaleAnimation, Tr ...