一、插件化的概念
在说插件化之前我们先说说组件化
组件化就是将一个app分成多个模块,每个模块都是一个组件(Module),开发的过程中我们可以让这些组件相互依赖或者单独调试部分组件等,但是最终发布的时候是将这些组件合并成一个apk,这就是组件化开发。
再来理解插件化
插件化 和组件化开发略有不用,插件化开发时将整个app拆分成很多模块,这些模块包括一个宿主和多个插件,每个模块都是一个apk(组件化的每个模块是个lib),最终打包的时候将宿主apk和插件apk分开或者联合打包。
二、组件化要解决的问题
1.app的功能模块越来越多,体积越来越大
2.模块之间的耦合度高,协同开发沟通成本越来越大
3.应用之间的相互调用
三、如何实现插件化
接下来我们围绕下面三个问题展开,本篇只解决第一个问题,后续会有两篇继续解决后面两个问题。
1.如何加载插件的类?
2.如何调用插件的四大组件?
3.如何加载插件的资源?
现在我们来解决第一个问题,如何加载插件类。插件类是没有编译到宿主apk里面去的,所以无法用反射调用。
用Android studio新建一个工程,有两个module,app 和plugin,如图所示
在module中添加TestPlugin类,代码如图所示。现在我们看看如何调用TestPlugin的funPlugin方法。
首先我们需要将.java文件转为.class文件,再将.class文件转为.dex文件,模拟系统的打包过程。
.class文件可以用javac命令,也可以直接去下面文件夹找
然后我们用dx命令将.class文件转为.dex文件
D:\workspace\PluginApp\plugin\build\intermediates\javac\debug\classes>dx --dex --output=testPlugin.dex com\example\plugin\TestPlugin.class
注意点:
- dx命令在Android sdk 安装目录的\build-tools目录下,我的目录是D:\Android_software\android_sdk\build-tools\29.0.3 如果是第一次使用需要配环境变量。
- 执行命令的目录最好在TestPlugin.class所在目录的包名的前一个目录,也就是classes目录
命令执行成功后会生成testPlugin.dex文件
当然也可以省事一点,直接取以下路径的classe.dex也可以。
然后将testPlugin.dex文件放入到手机的sd卡目录
然后我们来写宿主apk的代码,宿主apk只有一个MainActivity
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bt = findViewById(R.id.bt_call_plugin);
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
DexClassLoader dexClassLoader = new DexClassLoader("/sdcard/plugin/testPlugin.dex",
MainActivity.this.getCacheDir().getAbsolutePath(),
null,
MainActivity.this.getClassLoader());
try {
Class<?> clazz = dexClassLoader.loadClass("com.example.plugin.TestPlugin");
Method method = clazz.getMethod("funPlugin");
method.invoke(null);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
然后我们需要在AndroidManifest中添加访问外部存储的权限。
最后我们在项目的settings.gradle中屏蔽调include ‘:plugin’,不让宿主将插件打包进去。
接下来我们可以编译启动宿主apk了。记得还需要在手机设置下面对应app的设置下开启权限。
点击button
看输出
2020-12-01 23:14:31.745 3894-3894/com.example.plugin D/TestPlugin: funPlugin: 我是TestPlugin
到这里就已经完成加载并调用插件中的类。