初识插件化
来源:互联网 发布: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创建对应的类加载器,资源管理器
- 初识插件化
- 初识Eclipse插件Mylyn
- 初识----浏览器插件开发
- bacula插件编写初识
- 初识cordova插件开发
- construct 2 插件初识
- 初识OSGI.NET插件框架
- vim中ctags插件初识
- 初识OSGI.NET插件框架
- jQuery模板插件--jQuery tmpl初识
- Maven 插件编写 之 初识 Mojo
- 最好用的剧情插件:USequencer初识
- construct 2 插件初识(2)
- 插件开发之360 DroidPlugin源码分析(一)初识
- 插件开发之360 DroidPlugin源码分析(一)初识
- FusionCharts绘图插件(一)——初识fusioncharts
- Validate笔记一:初识表单验证插件Validate
- 初识vscode,留下点设置及初步插件
- 给一个数组,使奇数在前偶数在后,不能改变相对位置
- Vue—— 组件进阶
- static关键字
- TCP/IP协议分层详解
- git使用时遇到 '/path/my_project/.git/index.lock: File exists'
- 初识插件化
- OpenGL超级宝典Windows + VS2013开发环境配置
- Google分析统计
- 2.RPC框架的简单实现(定义自己的ldubbo命名空间)
- 我的博客发表练习
- subic项目总结(二)-quartz中的三种JobStore
- openssl req和x509命令及配置文件
- 1007. 素数对猜想 (20)
- 反汇编定位代码崩溃位置_4