在 Android 中实现插件化框架,需要解决的问题主要如下:
是基于代理的方式实现插件框架; 对 App 的表层做了处理,通过在 Manifest 中注册代理组件,当启动插件组件时,首先启动一个代理组件,然后通过这个代理组件来构建,启动插件组件;需要按照一定的规则来开发插件 APK,插件中的组件需要实现经过改造后的 Activity、FragmentActivity、Service 等的子类
DroidPlugin 是 360 手机助手实现的一种插件化框架; 它可以直接运行第三方的独立 APK 文件,完全不需要对 APK 进行修改或安装;一种新的插件机制,一种免安装的运行机制,是一个沙箱(但是不完全的沙箱;就是对于使用者来说,并不知道他会把 apk 怎么样), 是模块化的基础
共享进程: 为android提供一个进程运行多个 apk 的机制,通过 API 欺骗机制瞒过系统
占坑: 通过预先占坑的方式实现不用在 manifest 注册,通过一带多的方式实现服务管理
Hook 机制:
动态代理实现函数 hook ,Binder 代理绕过部分系统服务限制,IO 重定向(先获取原始 Object –> Read ,然后动态代理 Hook Object 后–> Write 回去,达到瞒天过海的目的)

Small 是一种实现轻巧的跨平台插件化框架,具有“轻量、透明、极小化、跨平台”的理念
动态加载类:
我们知道插件化很多都从 DexClassLoader 类有个 DexPathList 清单,支持 dex/jar/zip/apk 文件格式,却没有支持 .so 文件格式,因此 Small 框架则是把 .so 文件包装成 zip 文件格式,插入到 DexPathList 集合中,改写动态加载的代码
资源分段:
由于 Android 资源的格式是 0xPPTTNNNN ,PP 是包 ID ,00-02 是属于系统,7f 属于应用程序,03-7e 则保留,可以在这个范围内做文章 , TT 则是 Type 比如,attr 、layout 、string 等等,NNNN 则是资源全局 ID;那么这个框架则是对资源包进行重新打包,每个插件重新分配资源 ID ,这样就保证了宿主和插件的资源不冲突
动态代理注册:
在 Android 中要使用四大组件,都是需要在 manifest 清单中注册,这样才可以使用,那如何在不注册情况也能使用呢,这里就是用到动态代理机制进行 Hook ,在发送 AMS 之前用占坑的组件来欺骗系统,通过认证后,再把真正要调用的组件还原回来,达到瞒天过海目的

DyLA : Dynamic-load-apk @singwhatiwanna
DiLA : Direct-Load-apk @FinalLody
APF : Android-Plugin-Framework @limpoxe
ACDD : ACDD @bunnyblue
DyAPK : DynamicAPK @TediWang
DPG : DroidPlugin @cmzy, 360
功能

透明度

VirtualAPK 是滴滴开源的一套插件化框架,支持几乎所有的 Android 特性,四大组件方面

VirtualAPK 对插件没有额外的约束,原生的 apk 即可作为插件。插件工程编译生成 apk后,即可通过宿主 App 加载,每个插件 apk 被加载后,都会在宿主中创建一个单独的 LoadedPlugin 对象
如下图所示,通过这些 LoadedPlugin 对象,VirtualAPK 就可以管理插件并赋予插件新的意义,使其可以像手机中安装过的 App 一样运行
合并宿主和插件的ClassLoader 需要注意的是,插件中的类不可以和宿主重复
合并插件和宿主的资源 重设插件资源的 packageId,将插件资源和宿主资源合并 去除插件包对宿主的引用 构建时通过 Gradle 插件去除插件对宿主的代码以及资源的引用

四大组件均不需要在宿主manifest中预注册,每个组件都有完整的生命周期

speed-tools 是一款基于代理模式的动态部署apk热更新框架、插件化开发框架;
speed-tools这个名字主要指的快速迭×××发工具集的意思
1、支持Android 2.3 以上版本
2、支持R文件资源直接调用
3、开发过程中无发射调用
4、apk无需安装直接调用
5、代理模式对代码侵入性少
6、使用简单,只需要继承简单的类即可
添加依赖:
compile 'com.liyihangjson:speed_tools:1.0.3'
首先看看项目结构:

lib_speed_tools: 插件化核心功能library module_host_main:宿主工程主工程,负责加载部署apk module_client_one:测试业务apk 1 module_client_two:测试业务apk 2 lib_img_utils:测试imageloader图片框架
注意:需要使用speed tools 只需要依赖lib_speed_tools即可,然后开始配置插件化步骤:
首先在module_client_one中创建业务逻辑类:TestClass.java
/*** by liyihang*/
public class TestClass extends SpeedBaseInterfaceImp {private Activity activity;@Overridepublic void onCreate(Bundle savedInstanceState, final Activity activity) {this.activity=activity;activity.setContentView(R.layout.activity_client_main);activity.findViewById(R.id.jump).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {SpeedUtils.goActivity(activity,"first_apk", "two_class");}});ImageView imageView= (ImageView) activity.findViewById(R.id.img_view);imageView.setVisibility(View.VISIBLE);ImgUtils.getInstance(activity).showImg("https://img-my.csdn.net/uploads/201309/01/1378037235_3453.jpg", imageView);}
}
SpeedBaseInterfaceImp业务组件中业务activity代理类,他是实现了主要的生命周期方法,相当于组件的activity类
然后创建hock类每个业务组件中只创建一个:ClientMainActivity.java
public class ClientMainActivity extends SpeedClientBaseActivity {@Overridepublic SpeedBaseInterface getProxyBase() {return new TestClass();}}
这个类在组件中是唯一的,作用就是hock在独立测试时候使用
接下来配置配置组件的AndroidManifest.xml
组件意图写死保持一直,root_class 是调用死后使用对于配置的com.example.clientdome.TestClass业务类,这样业务组件配置完成
接下来配置宿主工程module_host_main;
创建宿主工程唯一hock类:ApkActivity.java
/*** by liyihang* blog http://sijienet.com/*/
public class ApkActivity extends SpeedHostBaseActivity {@Overridepublic String getApkKeyName() {return HostMainActivity.FIRST_APK_KEY;}@Overridepublic String getClassTag() {return null;}
}
整个宿主工程创建一个类即可,用户是hock activity;然后创建一个开屏页apk第一次加载时候需要一些时间,放入开屏等待页面是非常合适的
HostMainActivity.java
/*** by liyihang* blog http://sijienet.com/*/
public class HostMainActivity extends AppCompatActivity implements Runnable,Handler.Callback, View.OnClickListener {public static final String FIRST_APK_KEY="first_apk";public static final String TWO_APK_KEY="other_apk";private Handler handler;private TextView showFont;private ProgressBar progressBar;private Button openOneApk;private Button openTwoApk;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_host_main);showFont= (TextView) findViewById(R.id.show_font);progressBar= (ProgressBar) findViewById(R.id.progressbar);openOneApk= (Button) findViewById(R.id.open_one_apk);openTwoApk= (Button) findViewById(R.id.open_two_apk);handler=new Handler(this);new Thread(this).start();}@Overridepublic void run() {String s = "module_client_one-release.apk";String dexOutPath="dex_output2";File nativeApkPath = SpeedUtils.getNativeApkPath(getApplicationContext(), s);SpeedApkManager.getInstance().loadApk(FIRST_APK_KEY, nativeApkPath.getAbsolutePath(), dexOutPath, this);String s2 = "module_client_two-release.apk";String dexOutPath3="dex_output3";File nativeApkPath2 = SpeedUtils.getNativeApkPath(getApplicationContext(), s2);SpeedApkManager.getInstance().loadApk(TWO_APK_KEY, nativeApkPath2.getAbsolutePath(), dexOutPath3, this);handler.sendEmptyMessage(0x78);}@Overridepublic boolean handleMessage(Message message) {showFont.setText("当前是主宿主apk\n插件apk完毕");progressBar.setVisibility(View.GONE);openOneApk.setVisibility(View.VISIBLE);openTwoApk.setVisibility(View.VISIBLE);openOneApk.setOnClickListener(this);openTwoApk.setOnClickListener(this);return false;}@Overridepublic void onClick(View v) {if (v.getId()==R.id.open_one_apk){SpeedUtils.goActivity(this, FIRST_APK_KEY, null);}if (v.getId()==R.id.open_two_apk){SpeedUtils.goActivity(this, TWO_APK_KEY, null);}}
}
加载apk核心代码是:
String s = "module_client_one-release.apk";String dexOutPath="dex_output2";File nativeApkPath = SpeedUtils.getNativeApkPath(getApplicationContext(), s);SpeedApkManager.getInstance().loadApk(FIRST_APK_KEY, nativeApkPath.getAbsolutePath(), dexOutPath, this);
业务apk都是放在assets目录中
最后配置AndroidManifest.xml文件:
这样所有配置结束,插件化实现
正如开头所说,要实现插件化的框架,无非就是解决那典型的三个问题:插件代码如何加载、插件中的组件生命周期如何管理、插件资源和宿主资源冲突怎么办;
每个框架针对这三个问题,都有不同的解决方案,同时呢,根据时间顺序,后出来的框架往往都会吸收已经出的框架精髓,进而修复那些比较有里程碑意义框架的不足;
但这些框架的核心思想都是用到了代理模式,有的在表面层进行代理,有的则在系统应用层进行代理,通过代理达到替换和瞒天过海,最终让 Android 系统误以为调用插件功能 和调用原生开发的功能是一样的,进而达到插件化和原生兼容编程的目的
我从去年开始接触Android开发,以下结合自己的一点项目经验,同时参考了Google的优化文档和网上的诸多技术大牛给出的意见,整理出这份电子手册 《Android 开发学习笔记》,私信发送 “进阶” 即可 直达获取;这份笔记汇总了我从事 Android 开发行业以来遇到的 技术难点问题,相信可以帮助到大家



整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下~
你的支持,就是我的动力;祝各位前程似锦
上一篇:4-5:关注,取消关注
下一篇:农村电商高质量发展再迎政策支持