Android技术知识

Android开发之组件化和插件化

2020-12-30  本文已影响0人  冬日毛毛雨

组件化

组件化是一个老生常谈的问题,其实并不新鲜

说下我的个人观点

这里比较下前端开发

插件化

App 的部分功能模块在打包时并不以传统方式打包进 apk 文件中,而是以另一种形 式二次封装进 apk内部,或者放在网络上适时下载,在需要的时候动态对这些功能 模块进行加载,称之为插件化。
这些单独二次封装的功能模块 apk ,就称作「插件」,初始安装的 apk 称作「宿 主」。
插件化是组件化的更进一步推进。

插件化基础:反射

反射基本使用

    public class PluginActivity extends AppCompatActivity {

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_plugin);

            //使用反射
            try {
                //1.拿到类
                Class utilsClass = Class.forName("com.dsh.txlessons.plugin.utils.Utils");
                //2.拿到第一个构造方法
                Constructor utilsConstructor = utilsClass.getDeclaredConstructors()[0];
                //3\. 扩大访问性 默认default包权限 -> public
                utilsConstructor.setAccessible(true);
                //4\. 创建类实例(通过构造方法实例)
                Object utils=utilsConstructor.newInstance();
                //5\. 获取方法
                Method shoutMethod = utilsClass.getDeclaredMethod("shout");
                //6\. 扩大方法访问权限
                shoutMethod.setAccessible(true);
                //7\. 方法执行
                shoutMethod.invoke(utils);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

反射的目的

Java 既然提供了可⻅性关键字 public private 等等,用来限制代码之间的可 ⻅性,为什么又要提供反射功能?

插件化原理:动态加载

通过自定义 ClassLoader 来加载新的 dex 文件,从而让程序员原本没有的类可以被 使用,这就是插件化的原理。

  1. 下面我们改造下代码

Caused by: java.lang.ClassNotFoundException: Didn't find class "com.dsh.pluginapp.utils.Utils" on path: DexPathList[[zip file "/data/app/com.dsh.mydemos-q8nYNkNjIWB0F6mdYX_Gvg==/base.apk"] - 这个错误表示没有找到Utils这个类

2. 重点来了
上面的代码之所以会报错,是因为pluginapp同样是一个App工程,其本身经过打包也是一个apk的存在,所以我们app工程的类加载器是无法加载到pluginapp里面的类(.dex)文件的,所以才会报这样的错误
那么下面要解决的问题就是如何让app程序能够拿到pluginapp程序中的Utils
插件化的解决方案很粗暴,就是把插件工程的文件扔给宿主工程

下面我们实践一下

onCreate{
    ...
    //------------------  插件化使用  ------------------
    //1\. 将插件apk复制到缓存目录
    File apk = new File(getCacheDir()+"plugin.apk");
    try (Source source = Okio.source(getAssets().open("apk/pluginapp-debug.apk"));
         BufferedSink sink = Okio.buffer(Okio.sink(apk));){
        sink.writeAll(source);
    } catch (IOException e) {
        e.printStackTrace();
    }
    //2\. 创建类加载器实例
    DexClassLoader classLoader = new DexClassLoader(apk.getPath(),getCacheDir().getPath(),null,null);

    //3\. 反射调用
    //1.拿到类
    Class utilsClass = classLoader.loadClass("com.dsh.pluginapp.utils.Utils");
    //2.拿到第一个构造方法
    Constructor utilsConstructor = utilsClass.getDeclaredConstructors()[0];
    //3\. 扩大访问性 默认default包权限 -> public
    utilsConstructor.setAccessible(true);
    //4\. 创建类实例(通过构造方法实例)
    Object utils=utilsConstructor.newInstance();
    //5\. 获取方法
    Method shoutMethod = utilsClass.getDeclaredMethod("shout");
    //6\. 扩大方法访问权限
    shoutMethod.setAccessible(true);
    //7\. 方法执行
    shoutMethod.invoke(utils);
    ...
}

3. 现在普通的类能够加载了,那么Activity能够加载么?

看了一些其他博客,可以实现

插件的灵活配置

如果我们想要让插件工程既可以作为library又可以作为application,那么我们可以这样做

插件化有什么用?

关于 DEX:

相关学习书籍

Android 组件化架构 Android 插件化指南

大家如果还想了解更多Android 相关的更多知识点,可以点进我的GitHub项目中自行查看,里面记录了许多的Android 知识点。

上一篇 下一篇

猜你喜欢

热点阅读