共计 7635 个字符,预计需要花费 20 分钟才能阅读完成。
为了踊跃拥抱新技术并优化 RN 的性能问题,所以决定在新业务需要中引入 Flutter 技术栈
Flutter 混合栈开发大抵能够分为一下两种模式
native 工程间接依赖开发
具体接入形式为,先在 setting.gradle 中退出如下代码:
setBinding(new Binding([gradle: this]))
evaluate(new File(
settingsDir,
'../../Flutter Module 工程根目录 /.android/include_flutter.groovy'
))
其次在 App 的 build.gradle 中退出如下代码:
implementation project(':flutter')
最初在主工程的 build.gradle 中退出如下代码即可:
repositories {
buildscript {
maven {url 'http://download.flutter.io'}
}
}
allprojects {
repositories {
maven {url 'http://download.flutter.io'}
}
}
native 工程接入 aar
新建 Flutter module 工程
flutter create -t module xx_module
目录构造如下
xx_modlue
- .android // Android 测试工程
- .ios // iOS 测试工程
- lib // Flutter 主工程
- main.dart // Flutter 入口文件
- pubspec.yaml // Flutter 三方包配置文件
Flutter 中提供了将 module 打包成 aar 的命令,生成的 aar 文件门路为 xx_modlue/build/host/outputs/repo
flutter build aar
将生成的 aar 文件引入 Android 开发工程即可实现 aar 的援用
到目前为止整个 aar 的引入根本是能够失常开发的,然而存在问题,那就是在每次开发都须要手动的将生成的 aar 包复制到主工程中进行依赖,不仅操作麻烦而且会出错,所以讲 Flutter 打包及引入流程变成日常开发罕用的模式是最佳实际
flutter 打包上传流程剖析:
为合乎日常开发流程,须要将 Flutter 打成的 aar 文件上传至 maven,因而首要任务就是解决将 aar 上传至 maven 问题
查看生成的 aar 目录上面的 pom 文件会发现主工程依赖的第三方 aar 包也会被下载至 xx_modlue/build/host/outputs/repo 门路下,pom 文件如下:
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xxx.flutter</groupId>
<artifactId>xxx</artifactId>
<version>release-0.0.7</version>
<packaging>aar</packaging>
<dependencies>
<dependency>
<groupId>io.flutter</groupId>
<artifactId>flutter_embedding_release</artifactId>
<version>1.0.0-af51afceb8886cc11e25047523c4e0c7e1f5d408</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.flutter</groupId>
<artifactId>armeabi_v7a_release</artifactId>
<version>1.0.0-af51afceb8886cc11e25047523c4e0c7e1f5d408</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.flutter</groupId>
<artifactId>arm64_v8a_release</artifactId>
<version>1.0.0-af51afceb8886cc11e25047523c4e0c7e1f5d408</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.flutter</groupId>
<artifactId>x86_64_release</artifactId>
<version>1.0.0-af51afceb8886cc11e25047523c4e0c7e1f5d408</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
剖析 pom 文件可知在上传主工程生成的 aar 的时候咱们还须要将下载下来的第三方 aar 上传至 maven 库,因而咱们得悉具体工程化脚本流程如下:
1、获取生成的 aar 门路
2、上传第三方依赖的 aar 文件
3、更新主工程 aar 的 artifactId
4、上传主工程 aar 文件
具体脚本如下:
deploy_aar(){
mvn deploy:deploy-file \
-DpomFile="$FILE_PATH/$NAME.pom" \
-DgeneratePom=false \
-Dfile="$FILE_PATH/$NAME.aar" \
-Durl="http://xxx.xxx.xxx:xxx/repository/public/" \
-DrepositoryId="nexus" \
-Dpackaging=aar \
-s="mvn-settings.xml" \
-Dversion="$VERSION"
}
projectDir=`pwd`
# 革除 Flutter 生成文件
flutter clean
# 获取 pub 包
flutter pub get
# 删除文件夹
rm -rf `pwd`/build/host/outputs/repo/
# 批改版本号
group="com.xxx.flutter"
type="release"
#type="debug"
#type="profile"
version="${type}-0.0.7"
artifactId="xxx"
echo "替换 Flutter/build.gradle 中的 group 为 ${group}"
path=`pwd`/.android/Flutter/build.gradle
sed -i '''29s/^.*$/group"'${group}'"/' ${path}
echo "替换 Flutter/build.gradle 中的 version 为 ${version}"
path=`pwd`/.android/Flutter/build.gradle
sed -i '''30s/^.*$/version"'${version}'"/' ${path}
# 打包 AAR
flutter build aar --no-debug --no-profile
# 找到 AAR 并上传
path=`pwd`
# shellcheck disable=SC2006
p=`find ${path}/build/host/outputs/repo -type f -name "*${type}*.aar"`
echo "${p}"
array=(${p//'\n'/})
currentName=""currentPath=""
currentPom=""currentDir=""
# shellcheck disable=SC2068
for item in ${array[@]}
do
resFile=`basename ${item}`
echo "${item}"
result=$(echo ${resFile} | grep "flutter_release")
if [["$result" == ""]]
then
lenght=${#item}
sub=${item:0:${lenght}-3}
pom="${sub}pom"
resFileLenght=${#resFile}
subDir=${item:0:${lenght}-${resFileLenght}}
curName=`echo ${resFile} | cut -d "-" -f 2`
curNameLenght=${#curName}
subVersion=${curName:0:${curNameLenght}-4}
nameLenght="${#resFile}"
subName=${resFile:0:${nameLenght}-4}
export FILE_PATH="${subDir}"
export NAME="${subName}"
export VERSION=${subVersion}
deploy_aar
else
nameLenght="${#resFile}"
subName=${resFile:0:${nameLenght}-4}
currentName="${subName}"
currentPath=${item}
currentPath=${item}
lenght=${#item}
sub=${item:0:${lenght}-3}
currentPom="${sub}pom"
resFileLenght=${#resFile}
subDir=${item:0:${lenght}-${resFileLenght}}
currentDir=${subDir}
fi
done
cd "${currentDir}"
echo `pwd`
mv "${currentName}.aar" "${artifactId}-${version}.aar"
mv "${currentName}.pom" "${artifactId}-${version}.pom"
cd ${projectDir}
echo `pwd`
currentName="${artifactId}-${version}"
currentPath="${currentDir}${currentName}.aar"
currentPom="${currentDir}${currentName}.pom"
echo "current name is ${currentName}"
echo "current path is ${currentPath}"
echo "currentPom is ${currentPom}"
echo "替换 pom artifactId 为 ${artifactId}"
sed -i '''6s/^.*$/ <artifactId>'${artifactId}'<\/artifactId> /' ${currentPom}
echo "currentDir is ${currentDir}"
echo "currentVersion is ${version}"
export FILE_PATH="${currentDir}"
export NAME="${currentName}"
export VERSION=${version}
deploy_aar
上传 maven 胜利后,主工程依赖 Flutter 代码就和增加第三方 SDK 流程统一了。
选型比照
名称 | 长处 | 毛病 |
---|---|---|
native 工程间接依赖开发 | 接入快 | 工程结构复杂,无奈将 Flutter 开发从 native 开发流程中剥离 |
native 工程接入 aar | Flutter 开发与 native 开发流程解耦 | 初期接入流程简单 |
最终抉择为通过 maven 形式接入 aar 不便后续拓展
Flutter 混合栈选型
在实现 Flutter 混合开发接入流程后,会有混合栈治理问题,在混合计划中解决的次要问题是如何去解决交替呈现的 Flutter 和 Native 页面。综合目前的开源框架,选型为 FlutterBoost
flutterBoost Flutter 端接入:
FlutterBoost.singleton.registerPageBuilders(<String, PageBuilder>{testhome: (String pageName, Map<dynamic, dynamic> params, String _) =>
MyHomePage(title: ''),
shoppingcar: (String pageName, Map<dynamic, dynamic> params, String _) {
String platformItemNo = '';
if (params.containsKey("platformItemNo")) {platformItemNo = params['platformItemNo'];
NativeChat.print(platformItemNo);
}
return ShoppingCar(platformItemNo: platformItemNo);
},
login: (String pageName, Map<dynamic, dynamic> params, String _) =>
LoginPage(),
overlay: (String pageName, Map<dynamic, dynamic> params, String _) =>
OverlayPage(),});
android 端接入:
application 初始化代码:
val router =
INativeRouter { context, url, urlParams, requestCode, exts ->
PageRouter.openPageByUrl(context, url, urlParams)
}
val boostLifecycleListener = object : FlutterBoost.BoostLifecycleListener {override fun onEngineCreated() { }
override fun onPluginsRegistered() {}
override fun beforeCreateEngine() {}
override fun onEngineDestroy() {}
}
val platform = FlutterBoost.ConfigBuilder(application, router)
.isDebug(BuildConfig.DEBUG)
.whenEngineStart(FlutterBoost.ConfigBuilder.ANY_ACTIVITY_CREATED)
.renderMode(FlutterView.RenderMode.texture)
.lifecycleListener(boostLifecycleListener)
.build()
FlutterBoost.instance().init(platform)
路由配置代码
// PageRouter 路由跳转及配置页面
object PageRouter {
/**
* 路由映射
*/
val pageName: HashMap<String?, String?> =
object : HashMap<String?, String?>() {
init {put("xxxx://shoppingCar", "shoppingCar")
put("xxxx://login", "login")
put("xxxx://home", "home")
put("xxxx://overlay", "overlay")
}
}
const val SHOPPING_CAR = "xxxx://shoppingCar"
const val LOGIN_PAGE = "xxxx://login"
const val OVERLAY = "xxxx://overlay"
const val BUYER_PRODUCT_DETAIL = "xxxx://buyer/productdetail"
const val TEST_SECOND = "xxxx://testSecond"
@JvmOverloads
fun openPageByUrl(
context: Context,
url: String,
params: Map<*, *>?,
requestCode: Int = 0
): Boolean {val path = url.split("\\?").toTypedArray()[0]
Log.i("openPageByUrl", path)
return try {
when {pageName.containsKey(path) -> {
val intent =
BoostFlutterActivity.withNewEngine().url(pageName[path]!!)
.params(params!!)
.backgroundMode(BoostFlutterActivity.BackgroundMode.opaque)
.build(context)
if (context is Activity) {context.startActivityForResult(intent, requestCode)
} else {context.startActivity(intent)
}
return true
}
url.startsWith(TEST_SECOND) -> {
context.startActivity(
Intent(
context,
SecondActivity::class.java
)
)
return true
}
else -> false
}
} catch (t: Throwable) {false}
}
}
native 跳转逻辑
// 初始化 channel 告诉
FlutterBoost.instance().channel().addMethodCallHandler { call, result ->
when (call.method) {
"baseUrl" -> {result.success(ApiConstant.getApiUrl())
}
}
}
// 跳转代码
val params = hashMapOf<String, String>()
params["param"] = param
PageRouter.openPageByUrl(this, PageRouter.SHOPPING_CAR, params)
Flutter 测试环境搭建
在混合开发的工程中被吐槽最多的大略就是测试了吧,和 native 打包在一起调试费时费力,对前端开发要求高须要理解 native 的根本流程