从零开始实现一个插件化框架(一)

从零开始实现一个插件化框架(一),前端h5开发面试题 在Android8.0以后的API中,和 PathClassLoader是没有任何区别的,而在以前的API中,两者只有一个设置加载路径的区别(有的文章说,PathClassLoader只支持直接操作dex格式文件,而DexClassLoader可以支持.apk、.jar和.dex文件,并且会在指定的outpath路径释放出dex文件。插件化开发和组件化略有不同,插件化开发是将整个app拆分成多个模块,这些模块包括一个宿主和多个插件,每个模块都是一个apk,最终打包的时候宿主apk和插件apk分开打包。 阅读详情

什么是插件化

概念

插件化技术最初源于免安装运行 apk 的想法,这个免安装的 apk 就可以理解为插件,而支持插件的 app 我们一般叫宿主。宿主可以在运行时加载和运行插件,这样便可以将 app 中一些不常用的功能模块做成插件,一方面减小了安装包的大小,另一方面可以实现 app 功能的动态扩展。


我们知道计算机主板就是由一系列的插槽组成的,我们需要什么功能,给它插上对应的芯片或显卡就可以了,从而实现热拔插。基于这个原理,软件方面的热拔插就是插件化

插件化解决的问题

APP的功能模块越来越多,体积越来越大,这样可以将一些业务模块做成插件化,按需加载,从而减小安装包的体积
模块之间的耦合度高,协同开发沟通成本越来越大
方法数目可能超过65535,APP占用的内存过大
应用之间的互相调用
组件化与插件化的区别
组件化开发就是将一个app分成多个模块,每个模块都是一个组件,开发的过程中我们可以让这些组件相互依赖或者单独调试部分组件等,但是最终发布的时候是将这些组件合并统一成一个apk,这就是组件化开发。

插件化开发和组件化略有不同,插件化开发是将整个app拆分成多个模块,这些模块包括一个宿主和多个插件,每个模块都是一个apk,最终打包的时候宿主apk和插件apk分开打包。

各插件化框架对比

市面上比较流行的插件化框架也有很多,他们之间都有哪些区别呢?

插件化实现

插件apk是没有安装的,那么怎么让宿主去加载它呢?我们知道,一个apk是有代码和资源组成的,所以只需要考虑两个问题即可:

如何加载插件中的类?

如何加载插件中的资源?

当然还有最重要的一个问题,四大组件如何调用呢?四大组件是需要注册的,而插件apk中的组件显然不会在宿主提前注册,那么如何去调用它呢?

下面我们就来一步一步解决这些问题

ClassLoader类加载器
以前在讲热修复的时候,我简单地介绍了一下ClassLoader的加载机制。java源码文件在编译后会生成一个class文件,而在Android中,将代码编译后会生成一个 apk 文件,将 apk 文件解压后就可以看到其中有一个或多个 classes.dex 文件,它就是安卓把所有 class 文件进行合并,优化后生成的。

java 中 JVM 加载的是 class 文件,而安卓中 DVM 和 ART 加载的是 dex 文件,虽然二者都是用的 ClassLoader 加
载的,但因为加载的文件类型不同,还是有些区别的,所以接下来我们主要介绍安卓的 ClassLoader 是如何加载
dex 文件的。

ClassLoader实现类

在Android中,ClassLoader是一个抽象类,它的实现类主要分为两种类型:系统类加载器(BootClassLoader),和自定义类加载器(PathClassLoader | DexClassLoader)

先看一下ClassLoader加载流程图:


BootClassLoader

用于加载Android Framework层的class文件,比如 Activity、Fragment,不过需要注意的是AppCompatActivity虽然也是google工程师提供的类,但是一个第三方包中的类,并不输入Framwork层,所以AppCompatActivity并不是使用BootClassLoader加载的

PathClassLoader

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

DexClassLoader

在Android8.0以后的API中,和 PathClassLoader是没有任何区别的,而在以前的API中,两者只有一个设置加载路径的区别(有的文章说,PathClassLoader只支持直接操作dex格式文件,而DexClassLoader可以支持.apk、.jar和.dex文件,并且会在指定的outpath路径释放出dex文件。其实不然,甚至可以说两者没有任何区别)


先放一张ClassLoader类继承关系图,相信都能看懂,就不多讲了,下面来看一下PathClassLoader 和 DexClassLoader的源码:

// /libcore/dalvik/src/main/java/dalvik/system/PathClassLoader.java
public class PathClassLoader extends BaseDexClassLoader {
    // optimizedDirectory 直接为 null
    public PathClassLoader(String dexPath, ClassLoader parent) {
        super(dexPath, null, null, parent);
    }
    // optimizedDirectory 直接为 null
    public PathClassLoader(String dexPath, String librarySearchPath, ClassLoader parent)    {
        super(dexPath, null, librarySearchPath, parent);
    }
}
// API 小于等于 26/libcore/dalvik/src/main/java/dalvik/system/DexClassLoader.java
public class DexClassLoader extends BaseDexClassLoader {
    public DexClassLoader(String dexPath, String optimizedDirectory,
        String librarySearchPath, ClassLoader parent) {
        // 26开始,super里面改变了,看下面两个构造方法
        super(dexPath, new File(optimizedDirectory), librarySearchPath, parent);
    }
}
// API 26/libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
public BaseDexClassLoader(String dexPath, File optimizedDirectory,
    String librarySearchPath, ClassLoader parent) {
        super(parent);
        // DexPathList 的第四个参数是 optimizedDirectory,可以看到这儿为 null
        this.pathList = new DexPathList(this, dexPath, librarySearchPath, null);
}
// API 25/libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
public BaseDexClassLoader(String dexPath, File optimizedDirectory,
            String librarySearchPath, ClassLoader parent) {
        super(parent);
        this.pathList = new DexPathList(this, dexPath, librarySearchPath,       optimizedDirectory);
}

根据源码就可以了解到,PathClassLoader 和 DexClassLoader 都是继承自 BaseDexClassLoader,且类中只有构造方法,它们的类加载逻辑完全写在 BaseDexClassLoader 中。

其中我们值的注意的是,在8.0之前,它们二者的唯一区别是第二个参数 optimizedDirectory,这个参数的意思是
生成的 odex(优化的dex)存放的路径,PathClassLoader 直接为null,而 DexClassLoader 是使用用户传进来的
路径,而在8.0之后,二者就完全一样了。
下面我们再来了解下 BootClassLoader 和 PathClassLoader 之间的关系:// 在 onCreate 中执行下面代码

ClassLoader classLoader = getClassLoader();
while (classLoader != null) {
    Log.e("leo", "classLoader:" + classLoader);
    classLoader = classLoader.getParent();
}
Log.e("leo", "classLoader:" + Activity.class.getClassLoader());

打印结果:

classLoader:dalvik.system.PathClassLoader[DexPathList[[zip file
"/data/user/0/com.enjoy.pluginactivity/cache/plugin-debug.apk", zip file
"/data/app/com.enjoy.pluginactivity-T4YwTh-
8gHWWDDS19IkHRg==/base.apk"],nativeLibraryDirectories=[/data/app/com.enjoy.pluginactivity-
T4YwTh-8gHWWDDS19IkHRg==/lib/x86_64, /system/lib64, /vendor/lib64]]]
classLoader:java.lang.BootClassLoader@a26e88d
classLoader:java.lang.BootClassLoader@a26e88d

通过打印结果可知,应用程序类是由 PathClassLoader 加载的,Activity 类是 BootClassLoader 加载的,并且
BootClassLoader 是 PathClassLoader 的 parent,这里要注意 parent 与父类的区别。这个打印结果我们下面还
会提到。

加载原理
那么如何使用类加载器去从dex中加载一个插件类呢?很简单

比如,有一个apk文件,路径是apkPath,里面有个类com.plugin.Test,就可以通过反射加载一个类:

// 初始化一个类加载器
DexClassLoader classLoader = new DexClassLoader(dexPath, context.getCacheDir().getAbsolutePath, null, context.getClassLoader);
// 获取插件中的类
Class<?> clazz = classLoader.loadClass("com.plugin.Test");
// 调用类中的方法
Method method = clazz.getMethod("test", Context.class)
method.invoke(clazz.newInstance(), this)

dex中加载类很简单,但是我们需要的是将插件中的dex加载到宿主里面,又该怎么做呢?其实原理还是跟热修复一样,下面就以API 26 Android 8.0举例,通过源码,看一下DexClassLoader类加载器是怎么加载一个apk中的dex文件的。

通过查找发现,DexClassLoader并没有加载类的方法,继续看它的父类,最后在ClassLoader类中找到了一个loadClass方法,看来就是通过这个方法来加载类了:

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
            // 1. 检测这个类是否已经被加载,如果已经被加载了就可以直接返回了
            Class<?> c = findLoadedClass(name);
            // 如果类未被加载
            if (c == null) {
                try {
                    // 2. 判断是否有上级加载器,使用上级加载器的loadClass方法去加载
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        // 正常情况下是不会走到这里的,因为最终ClassLoader都会走到BootClassLoader,重写了loadClass方法结束掉了递归
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                }
                // 3. 如果所有的上级都没找到,就调用findClass方法去查找
                if (c == null) {
                    c = findClass(name);
                }
            }
            return c;
    }

上面类加载分为了3个步骤

1、 检测这个类是否已经被加载,最终会调用到native方法实现查找,这里就不深入了:

protected final Class<?> findLoadedClass(String name) {
        ClassLoader loader;
        if (this == BootClassLoader.getInstance())
            loader = null;
        else
            loader = this;
        //native方法
        return VMClassLoader.findLoadedClass(loader, name);
}

2、如果没被找到,就会从parent中调用loadClass方法去查找,依次递归,如果找到了就返回,如果所有的上级都没有找到,又会调用到findClass一级一级的去查找。这个过程就是双亲委托机制

3、 findClass

// -->2 加载器一般都会重写这个方法,定义自己的加载规则
protected Class<?> findClass(String name) throws ClassNotFoundException {
    throw new ClassNotFoundException(name);
}

根据前面的打印结果我们可以看懂,ClassLoader的最上级是BootClassLoader,来 看下它是如何重写的loadClass方法,结束递归的:

class BootClassLoader extends ClassLoader {
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        return Class.classForName(name, false, null);
    }
    @Override
    protected Class<?> loadClass(String className, boolean resolve)
        throws ClassNotFoundException {
        Class<?> clazz = findLoadedClass(className);
        if (clazz == null) {
            clazz = findClass(className);
        }
        return clazz;
    }
}

从上面可以看到 BootClassLoader 重写了 findClass 和 loadClass 方法,并且在 loadClass 方法中,不再获取 parent,从而结束了递归。

接着往下走,如果所有的parent都没找到,DexClassLoader是如何加载的,通过查找,其实现方法在它的父类BaseDexClassLoader中:

// /libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
    // 在 pathList 中查找指定的 Class
    Class c = pathList.findClass(name, suppressedExceptions);
    return c;
}
public BaseDexClassLoader(String dexPath, File optimizedDirectory,
                          String librarySearchPath, ClassLoader parent) {
    super(parent);
    // 初始化 pathList
    this.pathList = new DexPathList(this, dexPath, librarySearchPath, null);
}

findClass中有调用了DexPathList中的findClass方法,继续:

private Element[] dexElements;
public Class<?> findClass(String name, List<Throwable> suppressed) {
    //通过 Element 获取 Class 对象
    for (Element element : dexElements) {
        Class<?> clazz = element.findClass(name, definingContext, suppressed);
        if (clazz != null) {
            return clazz;
        }
    }
    return null;
}

到这里一目了然,class对象就是从Element中获得的,而每一个Element就对应了一个dex文件,因为一个apk中dex文件可能有多个,所以就使用了数组来盛放Element。到这里加载apk中的类大家是不是就有思路了?

创建插件的ClassLoader加载器(PathClassLoader或DexClassLoader),然后通过反射,获取插件的dexElements数组的值
获取宿主的ClassLoader加载器,通过反射获取宿主的dexElements数组的值。
合并宿主和插件的dexElements数组,生成一个新的数组
通过反射将新的数组重新赋值给宿主的dexElements
实现方法
废话不多说,直接上代码:(我这里使用了kotlin,写起来感觉方便一些)

fun load(context: Context) {
        // 获取 pathList
        val systemClassLoader = Class.forName("dalvik.system.BaseDexClassLoader")
        val pathListField = systemClassLoader.getDeclaredField("pathList")
        pathListField.isAccessible = true

        // 获取 dexElements
        val dexPathListClass = Class.forName("dalvik.system.DexPathList")
        val dexElementsField = dexPathListClass.getDeclaredField("dexElements")
        dexElementsField.isAccessible = true


        // 获取宿主的Elements
        val hostClassLoader = context.classLoader
        val hostPathList = pathListField.get(hostClassLoader)
        val hostElements = dexElementsField.get(hostPathList) as kotlin.Array<Any>

        // 获取插件的Elements
        val pluginClassLoader = PathClassLoader("sdcard/plugin-debug.apk", context.classLoader)
        val pluginPathList = pathListField.get(pluginClassLoader)
        val pluginElements = dexElementsField.get(pluginPathList) as kotlin.Array<Any>

        // 创建数组
        val newElements =
        Array.newInstance(
            pluginElements.javaClass.componentType!!,
            hostElements.size + pluginElements.size
        ) as kotlin.Array<Any>

        // 给新数组赋值
        // 先用宿主的,再用插件的
        System.arraycopy(hostElements, 0, newElements, 0, hostElements.size)
        System.arraycopy(pluginElements, 0, newElements, hostElements.size, pluginElements.size)
        // 将生成的新值赋给 "dexElements" 属性
        dexElementsField.set(hostPathList, newElements)

    }

这样就合并了两个dex文件的类,宿主中就可以直接加载插件中的类了

private fun loadApk() {
        try {
            val clazz = Class.forName("com.kangf.plugin.Test")
            val method = clazz.getMethod("test", Context::class.java)
            method.invoke(clazz.newInstance(), this)
        } catch (e: Exception) {
            e.printStackTrace()
            // 调用上面的load方法
            Toast.makeText(this, "请先点击加载apk", Toast.LENGTH_LONG).show()
        }
}

时间关系,今天就讲到这里,还有两个问题(加载资源图片和四大组件),留到下一篇文章再讲

源码已经上传到github,有需要的可以看一下:

DynamicTest

好了,下面来看一下运行效果吧!


原文作者:Pan Geng
原文链接:https://blog.youkuaiyun.com/qq_22090073/java/article/details/103946596

一个强大的插件化框架 源码Direct-load-apk,Direct - load - apk 是一个强大的插件化框架, 通过使用它, 你可以实现看似不可能实现的功能 ----- 直接加载一个普通apk! 优势: Direct - load - apk 能够加载插件的全部 资源. 支持 插件间 Activity跳转. 不像 "dynamic load - apk" 这个项目, "Direct - load - apk" 不需要对插件有任何约束,也不需要在插件中引入jar和继承自定义Activity,可以直接使用this指针。 立即下载

相关推荐

Windows安全中心空白问题修复:服务重置与系统组件修复实战指南

Windows系统服务是操作系统后台运行的核心组件,负责管理硬件资源、应用程序执行和系统功能。其稳定运行依赖于服务控制管理器、注册表配置和系统文件完整性。当关键服务(如Windows Update、安全中心服务)因更新失败、权限错误或组件损坏而无法正常启动时,依赖其功能的应用程序界面便会出现加载异常。在系统维护与故障排除领域,通过命令行工具重置服务状态、修复系统映像已成为工程师的必备技能。本文聚焦Windows安全中心界面空白这一典型故障,深入剖析其与Windows Update服务、组件存储损坏的关联,并

weixin_30859423的博客 425

从零开始实现一个插件化框架(三) - 完结篇

其实客户端开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。然而Android架构学习进阶是一条漫长而艰苦的道路,不能靠一时激情,更不是熬几天几夜就能学好的,必须养成平时努力学习的习惯。贵在坚持!一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

2401_83977554的博客 1044

信奥编程启蒙 3068:【例13.3】时间差

现在给出一个时间,单位是秒,要求按照电子表格式输出,输出保证不会超过 2424 小时。3067:【例13.2】 电子表。把时间转化成电子表格式输出。电子表上的时间显示方法形如。

900

插件式前端应用开发框架

插件式开发框架并不是一个什么新鲜玩意,这个项目是它在前端应用开发中的一个试验。   先占位。

Web GIS前端研究 988

Matlab实战:3种雷达间歇采样干扰的仿真与识别(附完整代码)

本文通过Matlab实战,详细仿真了雷达有源间歇采样干扰的三种核心样式:直接转发、重复转发和循环转发干扰。文章提供了完整的代码实现,并深入探讨了基于时频分析和循环平稳分析的特征提取与识别方法,为雷达抗干扰技术的学习与实践提供了清晰的工程实现路径。

weixin_29053695的博客 364

SAP财务凭证实战:如何用Coding Block快速添加客户化字段(附ABAP代码)

本文详细介绍了在SAP财务凭证中利用Coding Block技术快速添加客户化字段的完整流程,包括技术架构解析、实战配置步骤(OBC4/OB41)及ABAP增强开发。通过案例演示如何高效扩展字段(如增长曲线类型),实现全流程集成且无需修改数据表,显著提升财务凭证的灵活性和可追溯性。

weixin_29271263的博客 227

基于插件开发的架构研究

最近关注架构问题,从很多方面了解到基于插件开发的优点和方便性。其中一个典型的例子就是Eclipse,允许广大程序员在Eclipse的核心框架基础上进行无限扩展。 那么基于插件开发具有哪些好处呢? 1)可以将各个功能交给插件完成,那么对于核心框架来说,其实只需要实现基本事件调度,数据缓存,插件管理等即可,而相应的业务逻辑可以交给插件完成.如此一来,可以非常方便的对业务逻辑进行更新,而不会影响到主...

weixin_30507481的博客 154

十、强势股的起爆点:第三类买点的实战精解

本文深入解析强势股交易中的第三类买点(三买)实战技巧,涵盖两种经典模式:突破首个中枢后的回踩和底部反转后的直接脱离下跌中枢。通过详细案例和数据分析,揭示三买在捕捉主升浪起爆点时的黄金信号作用,帮助投资者优化风险收益比,提升短线交易成功率。

weixin_30260191的博客 311

【开源】基于Qt的跨平台插件式开发框架QCPFrame(一)

一. 前言 一直以来,笔者都在从事工控相关的行业,时至今日已有15年的职业历程。为了更好的将自己的经验应用于实践,同时汲取各方力量助力这一开放式的开发框架,遂将其进行开源。 框架最初的版本是基于C#开发,应用于航空自动测试系统,即View+TPS的结构,View即一个统一的UI界面,用于选择不同的TPS测试序列包,如此以来,开发人员只需要关注测试序列逻辑及硬件设备的使用,而无需关注UI设计,因为在航空自动测试系统中,被测件是成熟机载电子设备,只需要按照手册中的测试步骤,用程序............

jam12315的专栏 2万+

Linux环境下离线升级GCC-9.4.0的完整实践指南

本文详细介绍了在Linux环境下离线升级GCC-9.4.0的完整实践指南,包括准备工作、依赖库安装、编译配置及常见问题解决。特别适用于企业内网或安全要求严格的服务器环境,帮助开发者高效完成GCC离线升级,提升编译性能并支持现代编程语言特性。

weixin_29288313的博客 671

无人机精准降落辅助系统核心技术解析

接近地面时(<10米)切换至基于图像的视觉伺服(IBVS),依据图像特征点偏移(如靶标图案、LED标记)微调姿态,消除位置累积误差。通过SRUKF(平方根无迹卡尔曼滤波) 算法融合三类数据,输出6自由度位姿估计(精度达厘米级),抑制单一传感器噪声。权值根据信噪比动态调整。模型预测控制(MPC):针对斜坡降落,构建包含平台倾角、风扰的动力学方程,滚动求解最优油门序列。动态照明适配:针对夜间或低光照场景,系统向降落平台发送亮度调节指令,如增强红外信标强度或调整可见光LED阵列,确保特征识别鲁棒性。

YUNZHUO666的博客 1696

java插件化_从零开始实现一个插件化框架(一)

欢迎关注专栏:里面定期分享Android和Flutter架构技术知识点及解析,还会不断更新的BATJ面试专题,欢迎大家前来探讨交流,如有好的文章也欢迎投稿。Flutter跨平台开发终极之选​zhuanlan.zhihu.com本文对应视频教程解析:https://www.bilibili.com/video/BV1SJ411J7ke?from=search&seid=93191035973...

weixin_34624426的博客 1676

Python爬虫实战:利用Selenium与Playwright抓取美团外卖数据

在当今大数据时代,网络数据采集已成为商业分析和市场研究的重要手段。本文以美团外卖平台为例,详细介绍如何使用Python最新爬虫技术(Selenium、Playwright)进行数据采集,并探讨相关技术原理、反爬应对策略及数据存储方案。通过5000+字的详细讲解和完整代码示例,帮助读者掌握现代网络爬虫开发的核心技能。本文详细介绍了使用Python最新爬虫技术采集美团外卖数据的完整流程,涵盖了从环境配置、页面分析到数据存储的全链路解决方案。

2201_76125261的博客 2550

从零开始实现一个插件化框架(一),android驱动工程师

各插件化框架对比 市面上比较流行的插件化框架也有很多,他们之间都有哪些区别呢? 插件化实现 插件apk是没有安装的,那么怎么让宿主去加载它呢?我们知道,一个apk是有代码和资源组成的,所以只需要考虑两个问题即可: 如何加载插件中的类? 如何加载插件中的资源? 当然还有最重要的一个问题,四大组件如何调用呢?四大组件是需要注册的,而插件apk中的组件显然不会在宿主提前注册,那么如何去调用它呢? 下面我们就来一步一步解决这些问题 ClassLoader类加载器 以前在讲热修复的时候,我简单地介绍了一下Cla

m0_66265052的博客 175

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

golang 热插拨 插件_从零开始实现一个插件化框架(一)

欢迎关注专栏:里面定期分享Android和Flutter架构技术知识点及解析,还会不断更新的BATJ面试专题,欢迎大家前来探讨交流,如有好的文章也欢迎投稿。Flutter跨平台开发终极之选​zhuanlan.zhihu.com本文对应视频教程解析:https://www.bilibili.com/video/BV1SJ411J7ke?from=search&seid=93191035973...

weixin_26805597的博客 2081

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

从零开始实现一个插件化框架(一),头条android面试

super(dexPath, null, librarySearchPath, parent); } } // API 小于等于 26/libcore/dalvik/src/main/java/dalvik/system/DexClassLoader.java public class DexClassLoader extends BaseDexClassLoader { public DexClassLoader(String dexPath, String optimizedDirectory, Str

m0_65146275的博客 171

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

从零开始实现一个插件化框架(一)(1),【Android面试题】

下面是辛苦给大家整理的学习路线一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)

碧海朝天素 786

从零开始实现一个插件化框架(二)

上一篇讲了插件化的概念和类加载机制,并实现了从插件apk中合并,并加载一个类。不知道大家还记不记得,实现插件化,只需解决三个问题即可: 如何加载插件中的类? 如何加载插件中的资源? 当然还有最重要的一个问题,四大组件如何调用呢?四大组件是需要注册的,而插件apk中的组件显然不会在宿主提前注册,那么如何去调用它呢? 第一个问题在上一篇文章中已经实现,今天我们就来讲一下插件中的四大组件 - Acti...

AndroidAlvin的博客 240

手把手带你实现最简单的插件化框架

/ 今日科技快讯 /港股中国恒大集团汽车公告称,与六名投资者分别签订认购协议,以每股27.30港元定向增发共9.5亿股新股,占公司扩大后总股数的9.75%,共筹集260亿港元,该...

郭霖 695

golang 热插拨 插件_从零开始实现一个插件化框架

作者:Pan Geng什么是插件化概念插件化技术最初源于免安装运行 apk 的想法,这个免安装的 apk 就可以理解为插件,而支持插件的 app 我们一般叫宿主。宿主可以在运行时加载和运行插件,这样便可以将 app 中一些不常用的功能模块做成插件,一方面减小了安装包的大小,另一方面可以实现 app 功能的动态扩展。我们知道计算机主板就是由一系列的插槽组成的,我们需要什么功能,给它插上对应的芯片或显...

weixin_42510140的博客 2117

从零开始实现一个插件化框架

/ 今日科技快讯 /网易科技讯 7月15日消息,据外媒报道,最新泄露的内部文件显示,电动汽车制造商特斯拉位于美国加州弗里蒙特汽车组装工厂的员工感染新冠病毒的危险激增。到目前为止,...

郭霖 440

从零开始实现一个插件化框架(三) - 完结篇

系列文章 从零开始实现一个插件化框架(一) 从零开始实现一个插件化框架(二) 往期回顾 Activity的启动流程 上两篇文章讲了插件apk中的类加载和Activity跳转,那么面试中经常问到的Activity的启动流程是不是就有了答案? Activity的启动过程,我们可以从Context的startActivity说起,其实现是ContextImpl的startActivity,然后内部会通过...

看了就忘,学了就废系列 1517

从零开始实现一个插件化框架(四)-补充篇

系列文章 从零开始实现一个插件化框架(一) 从零开始实现一个插件化框架(二) 从零开始实现一个插件化框架(三) 好久没写过文章啦,始终有一股深深的罪恶感。插件化系列的文章我前三篇已经介绍完了原理. 从加载插件类---->加载四大组件并跳转 ----> 资源加载 ----> android10以下版本适配四个大步骤,我相信大家都已经有所了解。 不过还是有不少小伙伴在问我android10如何适配,如果同学们看了第三篇文章,我相信适配android10也是易如反掌的,毕竟只是 api的变动嘛!

看了就忘,学了就废系列 699
上一篇: Android自定义View:MeasureSpec的真正意义与View大小控制
下一篇: 从零开始实现一个插件化框架(二)
Python_林一
博客等级 码龄7年 884粉丝 510原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值