导航:首页 > 操作系统 > android组件化插件化

android组件化插件化

发布时间:2023-08-08 06:20:06

❶ 插件化原理

总的来说,组件化框架功能单一,专心于模块化开发,但没有黑科技,不存在android版本的兼容问题。而插件化框架功能强大,最关键的是具备热修复、模块动态加载、删除的能力,但因为需要hook系统组件,所以存在可能的兼容性问题。
Atlas的热修复使用的是自家的Andfix,基于Native hook。

插件化是体现在功能拆分方面的,它将某个功能独立提取出来,独立开发,独立测试,再插入到主应用中动态加载。以此来规避主应用规模超限。通过代理或Hook来实现。

要正常打开插件中的Activity,需要以下资源:
1,通过DexClassLoader加载插件apk
2,通过包管理器,获取当前已加载的类信息
3,通过AssetManager获取插件apk中的资源
4,通过壳app中的代理Activity,提供上下文Context和生命周期管理(插件中的四大组件因为并没有注册到壳app的AndroidManifest.xml,所以并不具备生命周期)

通过代理Activity启动和同步插件Activity的生命周期

Hook其中的第一步或第十步实现插件Activity启动。

通过hook的方式启动插件Activity需要解决如下问题:
a、插件Activity如何绕开Manifest中注册的检测
b、如何创建Activity实例,并同步生命周期
我们通过VirtualApk插件化框架来看其实现方案:
a、预先在Manifest中注册各种启动模式的Activity占坑,启动时hook第1步,将Intent根据启动模式替换成预先在Manifest占坑的Activity,这样就解决了Manifest中注册的检测
b、hook第10步,使用插件的ClassLoader反射创建插件Activity,之后Activity的生命周期回调都通知给插件Activity,这样就解决了创建Activity并同步生命周期的问题

1,关于dex的生成
我们可以用dx工具,将jar包转成dex文件
2,dex的加载过程
通过DexClassLoader加载dex文件,然后解析其中的class、method等

参考:
https://www.jianshu.com/p/7e4958d02094

❷ android 插件化怎么把几个模块一起打包

1、java 里面直接把 .class 文件打包到 .jar 文件里面就可以了,但是 Android 的 Dalvik VM 是不认 Java 的 byte code 的,所以不能直接这么打包,而要用 dx 工具转成 Dalvik byte code 才可以。当然,dx 工具转了之后,jar 包里面就不是 .class 文件了,而是 .dex 文件。 2、可以做成server 利用broadcast,pendingIntent,Intent去通信,再provider数据共享过滤器设置下就能实现这样的效果 3、国内的各大应用市场的安卓客户端就是这么做的,由市场客户端可以下载各个功能客户端,在市场里可以对这些功能客户端进行更新、删除、打开操作。其实如果需求是定制化的应用市场,比如“办公应用市场”,在功能性的规则接口定义好之后,可以增加更多的业务逻辑,比如说“从市场客户端开启功能客户端的具体某个页面”,或者“从市场客户端调用功能客户端的某个功能”。

❸ Android 插件化

原理:实现原理上都选择尽量少的hook,通过在manifest上预埋一些组件实现四大组件的插件化。其中Small更形成了一个跨平台、组件化的框架。

VirtulApp:
能够完全模拟app的运行环境,能够实现免安装应用和双开技术。
Atlas:
阿里出品,号称是一个容器化框架,结合了组件化和热更新技术。

Android中有两种类加载器,DexClassLoader和PathClassLoader,它们都继承于BaseDexClassLoader。

两者的区别:DexClassLoader多了一个optimizedDirectory的路径参数,这个目录必须是内部存储路径,用于缓存系统创建的Dex文件。

所以我们可以使用DexClassLoader去加载外部Apk中的类。

ClassLoader调用loadClass方法加载类采用了双亲委托机制来避免重复加载类。
首先,ClassLoader会查看自身已经加载的类中是否已经存在此类,如不存在,然后,则会使用父类来加载此类,如不能成功加载,则会使用自身重载于BaseDexClassLoader的findClass()方法来加载此类。

DexClass的DexPathList在DexClass的构造器中生成,findClass()方法则是从DexPathList下面找出对应的DexFile,循环DexElements,通过dexElement.dexFile取出对应的DexFile,再通过DexFile.loadClassBinaryName()加载对应的类。

作用:使用插件DexClassLoader加载出需要的类。

通过每一个插件的DexClassLoader加载出自身所需要的类,当每一个插件需要加载相同的类库时,可采用该类库的不同版本来使用。

通过把每一个插件的pathList(DexFile)合并到主app的DexClassLoader上,来使各个插件和主app直接能够相互调用类和方法,并且各个插件中相同的功能可以抽取出来作为一个Common插件供其它插件使用。

插件调用主工程
在ClassLoader构造时指定主工程的DexClassLoader为父加载器即可直接调用主工程中的类和方法。
主工程调用插件
如果是多DexClassLoader的情况,则需要通过插件的DexClassLoader加载对应的类并反射调用其方法。此种情况,主工程一般会在一个统一的地方对访问插件中的类和方法做一些访问权限的管理及配置。

如果是单DexClassLoader的情况,则可以直接调用插件中的类和方法。但是当多个插件引用的库的版本不同时,会出现错误,因此,建议采用Gradle版本依赖管理统一处理主工程及各个插件的库依赖。

Android通过Resource来加载资源,只要有插件apk,就可以使用assertManager.addAssertPath(apkPath)的方式来生成assertManager,再使用其new出对应的Resource对象即可。

注意:由于AssertManager并不是Public,所以需要通过反射的方式去调用它。并且由于一些Rom对Resource的处理,所以,需要兼容处理。

有2种处理方式:

产生的原因:由于主工程和各个插件引用的Resource id重复产生的冲突。

解决思路:Android中的资源在系统中是以8位16进制0XPPTTRRRR的方式存在,其中PP即是资源区分的区域(Android系统只用它来区分系统资源和应用资源),只要让每一个插件的PP段取不同的值即可解决资源id冲突的问题。
具体解决方式:

1.修改aapt源码编译期修改PP段。
2.修改Resource的arsc文件,其中的每一条都包含了资源id和映射路径。

Activity的处理最为复杂,有两种处理方式:
1.ProxyActivity的方式。
2.预埋StubActivity,hook系统启动Activity的过程。

原理:VirtualAPK通过替换了系统的Instrumentation,hook了Activity的启动和创建,省去了手动管理插件Activity生命周期的繁琐,让插件Activity像正常的Activity一样被系统管理,并且插件Activity在开发时和常规一样,即能独立运行又能作为插件被主工程调用。

Android插件化方向主要有2个方向:

Android 插件化

❹ android插件化(四)Hook加载插件APK(ClassLoader方式)

前面插件化一和二说了下插桩式加载未安装的APK,主要是重写了getResource和getClassloader两个方法来实现的。以及每个组件要实现一个接口,通过接口注入上下文来达到它的生命周期。

那么插桩式和hook式的实现方式有什么不同呢?

插桩式是怎么加载到插件中的class文件呢,是通过将将APK转化成插件的Classloader,然后想要加载插件的class文件,我们的去拿这个插件的classloader去loadClass。所以是有一个中间者的。

hook式呢是将插件apk融入到了我们的宿主apk,那直接在里面就可以直接loadClass了,在不用这个插件的ClassLoader了,这样的话对于插件和宿主就没什么区别了,不像插桩式有一个中间者。

那么要实现hook式 就要知道android中一个class文件式怎样被加载到内存中去的。其实就是通过PathClassLoader来加载的。

那么我们先看下ClassLoader

任何一个java程序都是由一个或者多个class组成的,在程序运行时,需要将class文件加载到JVM中才可以使用,负责加载这些class文件的就是java的类加载机制。CLassLoader的作用就是加载class文件提供给程序运行时使用,每个Class对象内部都有一个ClassLoader来标示自己是有那个classLoade加载的。

Android app的所有的java文件都是通过PathClassLoader来加载的,那么它的父类是BaseDexClassLoader,还有一个兄弟类是DexClassLoader,那么他们有什么区别呢。

从上面可以看出这两个类的构造函数不同。(在26的源码中DexClassLoader中的optimizedDirectory也废弃了)

PathClassLoader:用于Android应用程序类加载器。可以加载指定的dex,以及jar、zip、apk中的classes.dex

DexClassLoader:加载指定的dex以及jar、zip、apk中的classes.dex。

可以看到创建ClassLoader的时候需要接收一个CLassLoader parent的参数,这个parent的目的就在于实现类加载的委托。

某个类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,一次递归,如果父加载器可以完成加载任务,那么就返回,只有当父加载器无法完成加载任务时,才自己去加载。

因此我们自己创建的ClassLoader:newPathClassLoader("/sdcard/xx.dex",getClassLoader()),并不仅仅只能加载我们的xx.dex中的class。

需要注意的是,findBootstrapClassOrNull 这个方法,当parent为null的时候,去这个BootCLassLoader进行加载,

但是在Android当中的实现:

所以new PathClassLoader("/sdcard/xx.dex",null),是不能加载Activity.class的。

上面分析了加载了一个class,是利用了双亲委托机制,那么要是都找不到那就开始调用自己的findCLass方法

在ClassLoader类中findClass:

任何ClassLoader的子类,都可以重写loadClass和findClass。如果你不想使用双亲委托,就重写loadClas修改实现,重写findClass则表示在双亲委托机制下,父ClassLoader都找不到class的情况下,定义自己去查找一个class。

而我们的PathClassLoader会自己负责加载Activity这样的类,利用双亲委托父类去加载activity,而我们的PathClassLoader没有重写findClass,是在它的父类里面。因此我们可以看看父类的findClass是如何实现的。

可以看到加载PathClassLoader加载class,转化为从DexPathList中加载class了,那么我们看看DexPathList中的findClass

那么从上面分析得到

到这里我们想要加载一个插件的apk ,其实最终加载的是一个dex文件(先说class文件,加载资源后面说),有没有办法吧这个dex文件给转化成一个 Element 对象,给放到 Elemeng数组 当中,这样直接就可以加载我们插件中的类了。

1、首先我们肯定是要得到插件APK的的中DexPathList对象中的dexElement数组

2、插件的dexElements数组我们拿到了,那么是不是要开始拿我们系统里面的 ,我们反射获取,和上面的一样。

3、上面我们获取到了系统和我们插件的dexElement数组,然后我们将这个数组合并到一个新的数组里面去,并且给注入到系统里面

至此,加载插件的一个流程基本就完成了。但是上面只是处理了class文件,没有处理资源。资源的话我们也是采用hook的方式去实现

在宿主的Application中hook这个方法,然后去重写getAsserts和getResources两个方法:

然后在插件的BaseActivity中继续重写getAssets和getResources两个方法

这样就可以完成hook式加载一个未安装的APK了。至此基本就完成了插桩式和Hook式插件化的基本实现。(后面几篇是优化)。

阅读全文

与android组件化插件化相关的资料

热点内容
如何用html5开发app 浏览:135
怎么隐藏苹果的app 浏览:320
上海積架空气压缩机 浏览:451
51单片机换行 浏览:733
哪里可以快速学看建筑图纸app 浏览:496
内部排序的算法比较 浏览:177
服务器如何定期执行指令 浏览:931
python下载python脚本 浏览:297
台达plc远程编程 浏览:263
云计算的后台服务器 浏览:589
windows7的我的电脑咋创建文件夹 浏览:492
去视频水印的app哪个好用 浏览:384
doc转为pdf 浏览:48
华为加密壁纸怎么提取 浏览:52
曲线命令的描述 浏览:454
php模板怎么修改 浏览:999
单片机和微机编程的区别 浏览:642
金牛期货哪个app好 浏览:803
程序员越老越贬值吗 浏览:211
安卓手机用计算机如何隐藏应用 浏览:459