当前位置:   article > 正文

你需要掌握的插件化知识_插件化技术

插件化技术

1 什么是插件化?

插件化技术最初源于免安装运行 apk 的想法,这个免安装的 apk 就可以理解为插件,而支持插件的 app 我们一般叫宿主

2 插件化实现思路

1 如何加载插件的类?

2 如何加载插件的资源?

3 如何调用插件类?

Q 1, 回答问题之前我们要先了解什么是双亲委托机制

类在加载的过程中首先回去 判断当前类是否已经被加载过,如果没有加载过并且自己的父加载器不为空,将会让自己的父加载器去处理,父加载同样会去按照这个逻辑处理。如果没有找到父加载器,才会自己去加载。

这样处理的好处:

1、避免重复加载,当父加载器已经加载了该类的时候,就没有必要子ClassLoader再加载一次。

2、安全性考虑,防止核心API库被随意篡改。

在android中classLoader的继承关系如下

 pathclassLoader 和DexClassLoader 

在8.0(API 26)之前,它们二者的唯一区别是第二个参数 optimizedDirectory,这个参数的意思是生成的 odex(优化的dex)存放的路径。

在8.0(API 26)及之后,二者就完全一样了。

DexClassLoader中没有重写findClass 方法。而是使用父类BaseDexClassLoader中的,继续跟踪进去看,最终是通过Element类中的方法返回的,而每一个Element就是对应一个dex文件,因为一个apk中可能会存在多个dex,所以使用Element[]数组表示.

 

 3 实现步骤

1. 创建插件的 DexClassLoader 类加载器,然后通过反射获取插件的 dexElements 值。

 

2. 获取宿主的 PathClassLoader 类加载器,然后通过反射获取宿主的 dexElements 值。

3. 合并宿主的 dexElements 与 插件的 dexElements,生成新的 Element[] 。

4. 最后通过反射将新的 Element[] 赋值给宿主的 dexElements 。

 上面的操作可以让普通的类被加载执行,但是Activity呢?

我们知道activity 是需要在注册文件中添加的,如果没有添加会报错的,所以我们得解决这个问题。

思路:通过hook系统源码,通过验证阶段,然后在真正进行跳转得地方,将插件中得activity进行替换。将需要真正跳转的类藏在intent中,等通过验证再取出进行替换

/**
 * 插件化hook原理:intent.setClassName("插件包名","插件中的全类名");
 * 1、hook AMS的startActivity方法,
 * 将intent改为 intent.setClassName("宿主包名","宿主中的全类名(代理类)");
 * 2、当AMS过程执行结束,再将intent还原
 * 将intent改为 intent.setClassName("插件包名","插件中的全类名");
 *
 */

将真正跳转的类藏入intent

 

 invoke函数内部找到startAcitivity方法,对其进行处理,替换内部的intent数据。

在 ActivityThread中的mH中,此时已经完成了验证,在mh中进行恢复

Q2 资源的文件该如何加载?

资源文件的加载离不开 Resources类,实际上,Resources 类也是通过 AssetManager 类来访问那些被编译过的应用程序资源文件的,不过在访问之前,它会先根据资源 ID 查找得到对应的资源文件名。 而 AssetManager 对象既可以通过文件名访问那些被编译过的,也可以访问没有被编译过的应用程序资源文件

raw文件夹和assets文件夹有什么区别?

raw : Android会自动的为这目录中的所有资源文件生成一个ID,这意味着很容易就可以访问到这个资源,甚至在xml 中都是可以访问的,使用ID访问速度是最快的。

assets : 不会生成ID,只能通过AssetManager访问,xml中不能访问,访问速度会慢些,不过操作更加方便。

解题步骤:

1. 需要创建一个 Resources 对象,用来加载插件的资源

2. Resources 的创建需要 AssetManager 对象

3. AssetManager 创建的时候,需要指定资源路径

Q3 so文件该如何动态加载?

若要运用动态加载技术,编译前不把so文件放入jniLibs目录(原因很多,比如想减小安装包的大小),自然打包生成的安装包也不包含该so。接着在手机上安装这个apk并启动App,如果App的运行不涉及到jni方法的调用,那相安无事就当so不存在;如果App打开了某个页面,而该页面又需要调用jni方法,则App自动到指定地址下载需要的so文件,然后保存到用户目录,并从用户目录加载该so,最后再调用jni方法。

实现步骤:

步骤1、下载so   

步骤2、拷贝so至私有(data)目录  

  

步骤3、通过绝对路径加载so

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/喵喵爱编程/article/detail/861069
推荐阅读
相关标签
  

闽ICP备14008679号