最近公司開(kāi)始推行使用Flutter用于移動(dòng)端開(kāi)發(fā)躲胳,忙活了一個(gè)多月的Flutter混合開(kāi)發(fā)迭代端午節(jié)后準(zhǔn)備上線茬暇,寫(xiě)下此過(guò)程的坑以及一些接入流程灵疮,以及Flutter技術(shù)。
由于我主業(yè)是搞Android開(kāi)發(fā)的追他,iOS還是個(gè)菜鳥(niǎo)坟募,先介紹一下Android混合接入流程
1.創(chuàng)建Flutter module
很多情況下,F(xiàn)lutter的接入都是在原有的移動(dòng)端項(xiàng)目的基礎(chǔ)上接入邑狸,這樣相對(duì)于侵入原有項(xiàng)目弱懈糯,并且接入的成本低,風(fēng)險(xiǎn)也低单雾。
flutter create -t module flutter_module
在命令行界面錄入即可赚哗,最好是和原本的項(xiàng)目在相同的目錄下,同級(jí)文件夾硅堆。我的項(xiàng)目基本是原有項(xiàng)目是一個(gè)git倉(cāng)庫(kù)屿储,對(duì)應(yīng)的Flutter代碼是在另一個(gè)git倉(cāng)庫(kù),這樣版本管理也是比較好的
2.Android 開(kāi)始接入
在原有setting.gradle文件末尾的添加一下代碼
setBinding(new Binding([gradle: this]))
evaluate(new File(
settingsDir.parentFile,
'/flutter_module/.android/include_flutter.groovy'
))
這樣就會(huì)引入到對(duì)應(yīng)的Flutter的module資源硬萍,對(duì)應(yīng)的編譯腳本扩所,F(xiàn)lutter框架已經(jīng)寫(xiě)好,后續(xù)有時(shí)間可以讀讀
在app目錄下的build.gradle文件中添加Flutter依賴
implementation project(':flutter')
主要的依賴鏈如下
flutter_module/.android/include_flutter.groovy ->
flutter_module/.android/Flutter/build.gradle ->
$flutterRoot/packages/flutter_tools/gradle/flutter.gradle
很方便的完成混合開(kāi)發(fā)的打包操作朴乖,接入完之后最好在flutter項(xiàng)目下面的.android文件下祖屏,用命令行工具執(zhí)行以下
gradlew assembleDebug
命令完成對(duì)應(yīng)的Android依賴加載
3.原生顯示Flutter的視圖
Button open = findViewById(R.id.openBtn);
open.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setClass(MainActivity.this, MyFlutterActivity.class);
startActivity(intent);
}
});
public class MyFlutterActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_flutter);
final FlutterView flutterView = Flutter.createView(
this,
getLifecycle(),
"route1"
);
final FrameLayout layout = findViewById(R.id.flutter_container);
layout.addView(flutterView);
}
}
只需要在Activity中的addView即可,看起來(lái)很簡(jiǎn)單买羞,不過(guò)存在很多問(wèn)題袁勺,跳轉(zhuǎn)過(guò)程可能會(huì)有黑屏情況,以及Flutter視圖的復(fù)用也是個(gè)問(wèn)題畜普,以及對(duì)應(yīng)的Flutter 跳轉(zhuǎn)Native界面也是個(gè)問(wèn)題期丰。于是乎谷歌發(fā)現(xiàn)FlutterBoost框架解決了大部分以上的問(wèn)題。
4.FlutterBoost框架的接入
依照https://github.com/alibaba/flutter_boost官方的文檔吃挑,接入發(fā)現(xiàn)有很多的坑钝荡,不知道是不是開(kāi)發(fā)人員都反感寫(xiě)文檔一樣的。
接入的流程如下:
4.1 Flutter項(xiàng)目接入FlutterBoost
在對(duì)應(yīng)的pubspec.yaml文件中加入依賴舶衬,pubspec.yaml就是一個(gè)配置文件埠通。
flutter_boost:
git:
url: 'https://github.com/alibaba/flutter_boost.git'
ref: '0.0.411'
之后調(diào)用Package get,右上角即可查看逛犹,之后還是在.android 文件下執(zhí)行
gradlew assembleDebug端辱,完成依賴下載。
4.2 Flutter中main.dart文件中配置
@override
void initState() {
super.initState();
FlutterBoost.singleton.registerPageBuilders({
//對(duì)應(yīng)的Page的名字虽画,最好是類Http格式
'demoPage': (pageName, params, _) {
return DemoPage();
},
});
FlutterBoost.handleOnStartPage();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Boost example',
builder: FlutterBoost.init(postPush: _onRoutePushed),
home: Container());
}
void _onRoutePushed(
String pageName, String uniqueId, Map params, Route route, Future _) {}
4.3 Android 中的Application的設(shè)置
@Override
public void onCreate() {
super.onCreate();
initFlutterBoot();
}
private void initFlutterBoot() {
FlutterBoostPlugin.init(new IPlatform() {
@Override
public Application getApplication() {
return mApplication;
}
@Override
public Activity getMainActivity () {
//這里返回null舞蔽,可以避免跳轉(zhuǎn)界面的(MainActivity)的頁(yè)面整體上移
return null;
}
@Override
public boolean isDebug() {
return AppConfig.IS_DEVELOPING;
}
@Override
public boolean startActivity(Context context, String url, int requestCode) {
//Flutter 跳轉(zhuǎn)的回調(diào)
return PageRouter.openPageByUrl(context,url,requestCode);
}
@Override
public Map getSettings() {
return null;
}
});
}
坑1:getMainActivity 如果返回MainActivity,會(huì)導(dǎo)致對(duì)應(yīng)的主頁(yè)面的布局整體上移码撰,發(fā)現(xiàn)給null也沒(méi)啥問(wèn)題渗柿。
4.4 Native和Flutter界面的跳轉(zhuǎn)
Native-->Fluuter
可以使用官方Demo中的PageRouter
public class PageRouter {
public static final String COMMISSION_TASK_PAGE = "gamma://flutter/commissionTaskPage";
public static final String NATIVE_CUST_INFO_PAGE_URL = "gamma://native/custInfo";
public static boolean openPageByUrl(Context context, String url) {
return openPageByUrl(context, url, 0, "{}");
}
public static boolean openPageByUrl(Context context, String url, String json) {
return openPageByUrl(context, url, 0, json);
}
public static boolean openPageByUrl(Context context, String url, int requestCode) {
return openPageByUrl(context, url, requestCode, "{}");
}
public static boolean openPageByUrl(Context context, String url, int requestCode, String json) {
try {
if (url.startsWith(COMMISSION_TASK_PAGE)) {
//貸后任務(wù)
Intent intent = new Intent(context, FlutterPageActivity.class);
intent.putExtra("pageName", "gamma://flutter/commissionTaskPage");
intent.putExtra("json", json);
context.startActivity(intent);
return true;
} else if (url.contains(NATIVE_CUST_INFO_PAGE_URL)) {
//打開(kāi)客戶界面
Map<String, String> params = getUrlParams(url);
AppUIHelper
.showCustomerInfoActivity(context, params.get("custId"));
return true;
}
} catch (Throwable t) {
return false;
}
}
//獲取對(duì)應(yīng)url中的參數(shù)
private static Map getUrlParams(String url) {
Map<String, Object> map = new HashMap<>();
url = url.replace("?", ";");
if (!url.contains(";")) {
return map;
}
if (url.split(";").length > 0) {
String[] arr = url.split(";")[1].split("&");
for (String s : arr) {
String key = s.split("=")[0];
String value = s.split("=")[1];
map.put(key, value);
}
return map;
} else {
return map;
}
}
}
這樣相對(duì)于好管理,Native頁(yè)面可以設(shè)置以Native開(kāi)頭脖岛,F(xiàn)lutter以flutter開(kāi)頭做祝,這樣好區(qū)分砾省。
對(duì)應(yīng)的FlutterPageActivity可以根據(jù)官方Demo自行修改。
坑2:FlutterPageActivity中最好加上以下代碼
@Override
protected void onCreate(Bundle savedInstanceState) {
FlutterMain.startInitialization(this);
super.onCreate(savedInstanceState);
}
不然會(huì)運(yùn)行報(bào)錯(cuò)
Flutter -- >Native
這種類型跳轉(zhuǎn)和Activity之間互相跳轉(zhuǎn)有點(diǎn)類似
FlutterBoost.singleton.openPage(
"${NativeUrl.NATIVE_CUST_INFO}?custId=${custId};",
{});
這中類型的跳轉(zhuǎn)會(huì)回調(diào)到前面Application中的 FlutterBoostPlugin.init 方法中的startActivity方法中混槐,只會(huì)在用PageRouter來(lái)接收即可编兄。
之后自行做界面的跳轉(zhuǎn)
5.打包的坑
在打release包的時(shí)候需要在Flutter的跟目錄下執(zhí)行以下命令
flutter build apk
之后是常規(guī)的Android的打包,不然打包出來(lái)的apk跳轉(zhuǎn)到Flutter頁(yè)面就會(huì)閃退