前言
Small官网: https://github.com/wequick/Small
世界那么大,组件那么小。Small,做最轻巧的跨平台插件化框架。 ——Galenlin
这是Small作者,林光亮老师,给Small一句概括。
今年6月份,我和同事Simon奔赴北京参加 GMTC全球移动技术大会2016。当时Galenlin给大家介绍了Small插件化框架,插件化加载dex、资源拆分、hook.....
Dynamic-load-apk的作者任玉刚也有演讲,不过没介绍DLA。
回广州后,对Small做了几个实验性demo,不禁赞叹Small真的非常简洁,而且基本能满足 APP组件化需求。
Small完成什么使命?
组件化,既熟悉又陌生的词汇。通俗点说,就是把APP拆分成不同功能模块,形成独立组件,让宿主调用。
组件化不一定是插件化,组件化是一个更大的概念:把模块解耦,组件之间代码不依赖,宿主可以依赖组件;而插件化则具体到了技术点上,宿主通过 动态加载 来调用组件,宿主不依赖组件,达到 完全解耦 的目的。
Small插件化方案适用于将一个APK拆分为多个公共库插件、业务模块插件的场景。
(知乎上一个插件化提问《怎么将 Android 程序做成插件化的形式?》)
框架对比
Android插件化框架有很多,相信Dynamic-load-apk、ACDD、DroidPlugin 如雷贯耳。
Small官方比较:COMPARISION.md
DyLA : Dynamic-load-apk @singwhatiwanna, 百度
DiLA : Direct-Load-apk @FinalLody
APF : Android-Plugin-Framework @limpoxe
ACDD : ACDD @bunnyblue
DyAPK : DynamicAPK @TediWang, 携程
DPG : DroidPlugin @cmzy, 360
- 功能
/ | DyLA | DiLA | ACDD | DyAPK | DPG | APF | Small |
---|---|---|---|---|---|---|---|
加载非独立插件[1] | × | x | √ | √ | × | √ | √ |
加载.so后缀插件 | × | × | ! [2] | × | × | × | √ |
Activity生命周期 | √ | √ | √ | √ | √ | √ | √ |
Service动态注册 | × | × | √ | × | √ | √ | x [3] |
资源分包共享[4] | × | × | ! [5] | ! [5] | × | ! [6] | √ |
公共插件打包共享[7] | × | × | × | × | × | × | √ |
支持AppCompat[8] | × | × | × | × | × | × | √ |
支持本地网页组件 | × | × | × | × | × | × | √ |
支持联调插件[9] | × | x | × | × | × | × | √ |
Small初体验
1.Create Project
假设宿主包名为com.example.mysmall
- 设置Application name为
MySmall
- 修改Company Domain为
mysmall.example.com
2.配置build.gradle
对project/build.gradle
修改如下:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.2'
classpath 'net.wequick.tools.build:gradle-small:1.0.0-beta3'
}
}
apply plugin: 'net.wequick.small'
small {
aarVersion = '1.1.0-beta1'
}
...
(com.android.tools.build:gradle
用回你Android Studio支持的gradle插件版本)
aarVersion
、net.wequick.tools.build:gradle-small
版本号,可以参照Small官方sample的build.gradle
。sample
3.新建Application
new SmallApp
public class SmallApp extends Application {
@Override
public void onCreate() {
super.onCreate();
Small.preSetUp(this);
Small.setBaseUri("http://example.com/");// 浏览器跳转url
Small.setUp(this, null);
// Small.setUp(this, new Small.OnCompleteListener(){...});
}
}
AndroidManifest.xml
:
<application
android:name=".SmallApp"
...
>
4.新建 插件Module
File->New->Module,选择Phone & Tablet Module
:
- Application Name:
App.main
- Module name:
app.main
- package name:
com.example.mysmall.app.main
如果选择Android Library
,app.*
换成lib.*
Small要求插件module满足:
- 模块名形如:
app.*
,lib.*
或者web.*
- 包名包含:
.app.
,.lib.
或者.web.
Add an Activity to Mobile
选择最简单的Empty Activity即可(其他也可以)。
除了默认MainActivity
,顺手创建多个ActivityB
吧。
5.配置UI route
新建assets/bundle.json
:
{
"version": "1.0.0",
"bundles": [
{
"uri": "main",
"pkg": "com.example.mysmall.app.main",
"rules": {
"page2": ".ActivityB"
}
}
]
}
- uri : 跳转Activity需要的uri
- pkg : 插件模块包名
- rules : 指定跳转的Activity
6.跳转到插件Activity
@Override
public void onClick(View view) {
Small.openUri("main", this); // open bundles.main Launch Activity
// Small.openUri("main/page2", context);// 指定跳转到app.main.page2
}
调用openUri
后,就可以跳转到插件的某个Activity了。
7.编译插件
1)Build libraries (准备基础库)
gradlew buildLib
如果插件module是Android Library
,这时会生成app/smallLibs/armeabi/*.so
2)Build bundles (打包所有组件)
gradlew buildBundle
生成app/smallLibs/armeabi/libcom_example_mysmall_app_main.so
运行
由于project有两个Phone & Tablet Module
,运行时要选app
噢
使用效果
你会发现,宿主app
没有依赖app.main
,仅仅把app.main
编译成so文件, 宿主app
就可以跳转到插件app.main
页面了。这就是插件化的魅力——零依赖!
遇到的问题
之前遇到一个很奇葩的问题,如图:
解决方法:
- gradlew cleanLib
- bradlew cleanBundle
- 重新buildLib、buildBundle即可
还试过运行时提示“找不到app/MainActivity
”,解决:File->Invalidate Caches/Restart
清一下缓存再重启AS就好了。
小结
Small算是最简单的插件化框架,如果你的project本来就已经组件化到一定程度,使用Small轻而易举。
由于笔者还未试过在实际项目中使用,可能有些潜在的坑未踩。Small的更新也是蛮积极的,目前大概一个月更新一次,在交流Q群&issue,Galenlin回应也很积极。
强烈建议大家看看Small Issue,了解大家在使用中遇到的问题,以及Galenlin和其他人提出的解决方案。目前就4页,中文的,不会太多哈哈。
笔者相信,未来半年一年,Small会更稳定、更容易在项目中集成,让我们更爽地体验插件化的优势!
推荐阅读:
关于转载
如果你想转载此文,请务必在转载时,加上原文作者&原文链接。谢谢