为了踊跃拥抱新技术并优化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的根本流程