技术:Android + java +动态加载+插件化
 

概述

为什么要使用插件化?在开发中,一个项目只会越做越大。初始版本可能是单一功能,后续可能加上各种风马牛不相及的功能。所以我认为插件化可以使得业务分离的更彻底,一人负责哪几个模块,问题也能快速定位。但是也会带来问题:插件和插件之间的交互的复杂性更高、底层支持库因为多个插件需要使用相同的代码可能会变得很大。所以插件化看似解耦了程序员的职责,实际上对于代码质量的要求更高。   实现插件化,最快的方法就是找一个第三方框架。但是要想真正理解,需要真正自己写一个.下面本文就带大家写一个动态加载插件化的框架

详细

Android动态加载Apk-插件化技术(动态代理方案)

一.概述

为什么要使用插件化?在开发中,一个项目只会越做越大。初始版本可能是单一功能,后续可能加上各种风马牛不相及的功能。所以我认为插件化可以使得业务分离的更彻底,一人负责哪几个模块,问题也能快速定位。但是也会带来问题:插件和插件之间的交互的复杂性更高、底层支持库因为多个插件需要使用相同的代码可能会变得很大。所以插件化看似解耦了程序员的职责,实际上对于代码质量的要求更高。

  要想实现插件化,最快的方法就是找一个第三方框架接入。但是要想真正理解,需要真正自己写一个.下面本文就带大家写一个动态加载插件化的框架

二. 什么是插件化

1. 主App(宿主App)加载插件apk的实现

2. 每个业务组件模块形成一个独立的Apk, 然后通过主App动态加载部署业务组件模块Apk的一种方案

三.效果演示图&应用场景

1.效果演示图:

 

2.实际开发中,比如微信和支付宝的如下页面就是典型的插件化应用场景

 

三.插件化的优点好处

1. 业务组件解耦,能够实现业务组件模块的热插拔

2. 更改产品迭代模式,可分为主App和次Apk(动态加载业务组件模块)

3. 改善产品更新过程,可以在不影响用户的情况下实现业务组件模块更新以及重要Bug修复

4. 减轻主App的内存和CPU占用,提高应用的性能.

四.插件化的思想

动态加载Apk的主要思想是:主App是被系统(PMS)安装,被系统(AMS)调用,整个过程都是由系统提供的,而插件Apk并非一个真正的Apk,只是一个打包成Apk的一个组件模块,因为它并非被系统安装调用.简言之,需要讲插件Apk看成一个”非Apk”文件,只是一个结构比较复杂的压缩打包成Apk格式的文件.调用插件即用某种特殊技术手段打开文件并执行其相关代码.

五.插件化的步骤-分析主App

1.主APp打包完成解压后,会有dex,images,xml,asset等类型文件

2.Dex靠PathClassLoader加载运行

3.图片以及xml等资源依靠Resources&AssetManager加载管理

六.插件化的实现流程

六. 插件化的代码实现步骤

1.创建DexClassLoader加载插件化Apk相关代码,核心代码如下:

/**'
* 创建DexClassLoader
*/
private DexClassLoader createDexClassLoader(String apkPath) {
File file = mContext.getDir("dex",Context.MODE_PRIVATE);
return new DexClassLoader(apkPath,file.getAbsolutePath(),null,mContext.getClassLoader());
}

2.创建Resources&AssetManager来加载插件化Apk的资源

/**
* 获取到插件中的Resource
*/
private Resources createResources(AssetManager am) {
Resources resources = mContext.getResources();
return new Resources(am,resources.getDisplayMetrics(),resources.getConfiguration());
} /**
* 获取插件的AssetManager
*/
private AssetManager createAssetManager(String apkPath) {
try {
AssetManager am = AssetManager.class.newInstance();
Method method = AssetManager.class.getDeclaredMethod("addAssetPath",String.class);
method.invoke(am,apkPath);
return am;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}

3.管理插件Apk里的组件(如Activity)的生命周期

package com.czm.pluginlib;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle; /**
* Created by caizhiming on 2018/3/3.
*/ public interface IPlugin { int FROM_INTERNAL = 0;//内部跳转
int FROM_EXTERNAL = 1;//外部跳转 void attach(Activity activity); void onCreate(Bundle bundle);
void onStart();
void onRestart();
void onActivityResult(int requestCode, int resultCode, Intent data);
void onResume();
void onPause();
void onStop();
void onDestroy();
}

4.通过代理模式实现对插件Apk里面组件的管理

@Override
protected void onCreate( Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mClassName = getIntent().getStringExtra("className");
mPluginApk = XCPluginManager.getInstance().getPluginApk(); launchPluginActivity();
} private void launchPluginActivity() {
if(mPluginApk == null){
throw new RuntimeException("请先加载插件Apk");
}
try {
//clazz 就是Activity的实例对象,但是该对象没有生命周期,没有上下文环境
Class<?> clazz = mPluginApk.mDexClassLoader.loadClass(mClassName);
Object object = clazz.newInstance();
if(object instanceof IPlugin) {
mIPlugin = (IPlugin) object;
mIPlugin.attach(this);
Bundle bundle = new Bundle();
bundle.putInt("FROM",IPlugin.FROM_EXTERNAL);
mIPlugin.onCreate(bundle);
}
} catch (Exception e) {
e.printStackTrace();
}
} @Override
public Resources getResources() {
if(mPluginApk != null) {
return mPluginApk.mResources;
} else {
return super.getResources();
}
} @Override
public AssetManager getAssets() {
if(mPluginApk != null) {
return mPluginApk.mAssetManager;
}else {
return super.getAssets();
}
} @Override
public ClassLoader getClassLoader() {
if(mPluginApk != null) {
return mPluginApk.mDexClassLoader;
}else {
return super.getClassLoader();
}
}

以上就是实现插件化的主要过程步骤,具体细节优化读者可以自己扩展优化补充.

七.项目代码目录结构图

注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权

Adroid动态加载Apk-插件化技术框架(动态代理方案)的更多相关文章

  1. 动态加载与插件系统的初步实现(3):WinForm示例

    动态加载与插件系统的初步实现(三):WinForm示例 代码文件在此Download,本文章围绕前文所述默认AppDomain.插件容器AppDomain两个域及IPlugin.PluginProvi ...

  2. android--动态加载、插件化

    需求驱动 随着业务发展需要和无线部门的拆分,各业务产品模块归属到各业务BU,原有无线App开发团队被分为基础框架.业务A.业务B.业务C等多个开发团队,从此App的开发和发布进入了一个全新模式.在这种 ...

  3. C# 实现动态加载DLL插件 及HRESULT:0x80131047处理

    本代码实现DLL的动态加载, 类似PS里的滤镜插件! 1. 建立一个接口项目类库,此处名称为:Test.IPlugin using System; namespace Test.IPlugin { p ...

  4. .NET Web后台动态加载Css、JS 文件,换肤方案

    后台动态加载文件代码: //假设css文件:TestCss.css #region 动态加载css文件 public void AddCss() { HtmlGenericControl _CssFi ...

  5. 动态加载与插件系统的初步实现(三):WinForm示例

    代码文件在此Download,本文章围绕前文所述默认AppDomain.插件容器AppDomain两个域及IPlugin.PluginProvider.PluginProxy3个类的使用与变化进行. ...

  6. vue动态加载jQuery插件

    要先npm安装jQuery插件哦 window.$=$; window.jQuery=$; function loadJs(Url,callback){ var Nscript=document.cr ...

  7. 动态加载与插件系统的初步实现(二):AppDomain卸载与代理

    前一篇文章简单展示了类型发现和MEF使用,本文初步进入AppDomain相关内容. CLR程序运行时会创建默认程序集容器即AppDomain,默认AppDomain不支持卸载其程序集,但CLR支持创建 ...

  8. 动态加载与插件系统的初步实现(四):解析JSON、扩展Fiddler

    按文章结构,这部分应该给出WCFRest项目示例,我想WinForm示例足够详尽了,况且WCFRest还不需要使用插件AppDomain那一套,于是把最近写的Fiddler扩展搬上来吧. Fiddle ...

  9. 动态加载与插件系统的初步实现(一):反射与MEF解决方案

    涉及内容: 反射与MEF解决方案 AppDomain卸载与代理 WinForm.WcfRestService示 PRRT1: 反射实现 插件系统的基本目的是实现宿主与组件的隔离,核心是作为接驳约定的接 ...

随机推荐

  1. appium环境搭建及项目实战

    手机端自动化环境搭建比其他自动化环境搭建较为复杂,安装工具有点多,也会有很多坑,安装工具一定注意版本号对应问题. 一.我的电脑环境:win7  64位,安卓测试机4.4.2版本,Python3.6,a ...

  2. 牛客练习赛 26 C题 城市规划【贪心】

    <题目链接> 题目描述 小a的国家里有n个城市,其中第i和第i - 1个城市之间有无向道路连接,特殊的,第1个城市仅与第2个城市相连为了减轻道路维护负担,城市规划局局长MXT给出了m个要求 ...

  3. 从函数式编程到Ramda函数库(一)

    函数式编程是种编程方式,它将电脑运算视为函数的计算.函数编程语言最重要的基础是λ演算(lambda calculus),而且λ演算的函数可以接受函数当作输入(参数)和输出(返回值).和指令式编程相比, ...

  4. 366. Fibonacci

    描述 查找斐波纳契数列中第 N 个数. 所谓的斐波纳契数列是指: 前2个数是 0 和 1 . 第 i 个数是第 i-1 个数和第i-2 个数的和. 斐波纳契数列的前10个数字是: 0, 1, 1, 2 ...

  5. Centos6.5部署Rsyslog+LogAnalyzer收集网络及系统日志

    1. 介绍 Rsyslog是比syslog功能更强大的日志记录系统,可以将日志输出到文件,数据库和其它程序.可以使用rsyslog替换系统自带的syslog. LogAnalyzer 是一个 sysl ...

  6. 2018-6-8随笔-combox绑定-语音-删空格

    1.下面介绍三种对comboBox绑定的方式,分别是泛型中IList和Dictionary,还有数据集DataTable ----->>>>>飞机票 2. 简单的语音播报 ...

  7. Python3之弹性力学——应力张量1

    题目 已知某点的应力张量为: \[ \left[ \begin{array}{ccc} \sigma_{x} &\tau_{xy} &\tau_{xz}\\ \tau_{yx} &am ...

  8. 机器学习系列-tensorflow-02-基本操作运算

    tensorflow常数操作 import tensorflow as tf # 定义两个常数,a和b a = tf.constant(2) b = tf.constant(3) # 执行默认图运算 ...

  9. 【整理】Java 10新特性总结

    Java 9才发布几个月,很多玩意都没整明白,Java 10就来了..这时候我真尼玛想说:线上用的JDK 7 ,JDK 8 还没用熟,JDK 9 才发布不久不知道啥玩意,JDK 10……刚学Java的 ...

  10. Java笔记(十)堆与优先级队列

    优先级队列 一.PriorityQueue PriorityQueue是优先级队列,它实现了Queue接口,它的队列长度 没有限制,与一般队列的区别是,它有优先级概念,每个元素都有优先 级,队头的元素 ...