初识插件化

来源:互联网 发布:php在线帮助文档系统 编辑:程序博客网 时间:2024/06/03 15:49

一,什么是插件化

插件化是将一个应用按照宿主,插件的方式改造就叫插件化
(1)宿主:主app可以用来加载插件也成为Host
(2)插件:插件app,被宿主加载的app,可以跟普通的app一样的apk文件
这里写图片描述
如图显示的so文件就是通过插件化生成的各个业务线的so文件

二,插件化的作用

解决 由于app体积越来越,功能模块越来越多导致的以下几个问题
(1)方法数超过65535,占用内存过大
(2)耦合度高
(3)协同开发成本高
优势:
(1).业务模块基本完全解耦
(2).高效的并行开发(编译速度更快)
(3).按需加载,内存占用更低

三,概念对比与分析

组件化与插件化
1.组件化是一种编程思想,而插件化是一种技术
2.组件化是为了代码的高度复用性而出现
3.插件化是为了解决应用越来越庞大而出现的
插件化与动态更新
1.都是动态加载的技术的应用
2.动态更新是为了解决线上bug或小功能的更新出现
3.插件化是为了解决应用越来越庞大而出现的
封装设计模式:组件化
动态加载技术:
1.插件化
2.热修复/热更新/动态更新

四,插件化原理与简单实践

运用到的技术:
android ClassLoader加载class文件原理
java的反射原理
android 的资源加载原理
四大组件加载原理

1.Manifest处理
这里写图片描述
解析:
(1).构建期进行全量的Merge操作
(2).Bundle的依赖单独Merge生成Bundle自己的MergeManifest
(3).解析各个Bundle的MergeManifest,得到整个包的BundleInfoList
关键点:
(1).文件的合并 合并到总的Manifest总文件中
(2).如何修改编译流程完成所有清单文件的合并

2.插件类加载

这里写图片描述
(1)DelegateClassLoader以PathClassLoader为父classloader,找不到的情况下根据BundleList找到对应的BundleClassLoader
(2)BundleClassLoader的父对象为BootClassLoader,包含PathClassLoader对象,先查找当前classloader,再查找当前的PathClassLoader
关键点:
(1)如何自定义ClassLoader加载类文件
(2)如何调用插件apk文件中的类
代码简单原理实现

/***该类位于A.apk,实现调用B.apk中的MyLogUtil类中方法名为show的方法***/public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        String apkPath=getExternalCacheDir().getAbsolutePath()+"/bundlea.apk";        loadApk(apkPath);    }    private void loadApk(String apkPath) {        File optFile=getDir("opt",MODE_PRIVATE);        DexClassLoader classLoader=new DexClassLoader(apkPath,optFile.getAbsolutePath(),null,this.getClassLoader());        try {            Class cls=classLoader.loadClass("com.example.bundlea.MyLogUtil");            if(cls!=null){                Object instance=cls.newInstance();                Method method=cls.getMethod("show");                method.invoke(instance);            }        } catch (Exception e) {            e.printStackTrace();        }    }}

3.资源加载
这里写图片描述

这里写图片描述
(1)所有的Bundle Res资源都是加入到一个DelegateResources
(2)Bundle Install的时候将Res,So等目录通过反射加入(AssetManager
.addAssetPath)
(3)通过不同的package来区分Bundle的资源ID
(4)覆盖getIdentifier方法 兼容5.0以上系统

代码实现

public class PluginManager {    private static PluginManager mInstance;    private static Context mContext;    private static File mFile;    private static HashMap<String, PluginInfo> mPluginInfoMap;    private PluginManager(Context context) {        mContext = context;        mFile = context.getDir("opt", Context.MODE_PRIVATE);        mPluginInfoMap = new HashMap<>();    }    public static PluginManager getInstance(Context context) {        if (mInstance == null) {            synchronized (PluginManager.class) {                if (mInstance == null) {                    mInstance = new PluginManager(context);                }            }        }        return mInstance;    }    public static PluginInfo loadApk(String apkPath) {        if (mPluginInfoMap.get(apkPath) != null) {            return mPluginInfoMap.get(apkPath);        }        PluginInfo pluginInfo = new PluginInfo();        pluginInfo.mDexClassLoader = createPluginManagerClassLoader(apkPath);        pluginInfo.mAssetManager = createPluginAssetManager(apkPath);        pluginInfo.mResources = createPluginResources(apkPath);        mPluginInfoMap.put(apkPath, pluginInfo);        return pluginInfo;    }    //为插件apk创建对应的classLoader    private static DexClassLoader createPluginManagerClassLoader(String apkPath) {        DexClassLoader dexClassLoader = new DexClassLoader(apkPath, mFile.getAbsolutePath(), null, null);        return dexClassLoader;    }    //为对应的插件创建AssetManager    private static AssetManager createPluginAssetManager(String apkPath) {        try {            AssetManager assetManager = AssetManager.class.newInstance();            Method method = assetManager.getClass().getMethod("addAssetPath", String.class);            method.invoke(assetManager, apkPath);            return assetManager;        } catch (Exception e) {            e.printStackTrace();        }        return null;    }    //为对应的插件创建resoures    private static Resources createPluginResources(String apkPath) {        AssetManager assetManager = createPluginAssetManager(apkPath);        Resources supResources = mContext.getResources();        Resources pluginReso = new Resources(assetManager, supResources.getDisplayMetrics(), supResources.getConfiguration());        return pluginReso;    }}

总结核心点
(1)处理所有的插件apk文件中的Manifest文件(修改编译流程,清单文件合并)
(2)管理宿主apk中所有插件apk的信息
(3)为每个插件Apk创建对应的类加载器,资源管理器