一、前言:目前混合開發屬於主流,因為多數都在原來的專案上整合Flutter模組,除非新的專案用純Flutter,那是挺爽的。混合開發多數會有點坑吧。現在記錄下混合開發的坑
二、整合(以iOS為例),使用Pods方式 1、首先建立一個Flutter模組(非Flutter專案,是模組) 2、建立後之後,把原生專案和Flutter模組放在一個資料夾下,同一層級。 3、原生專案開啟Podfile,加入Flutter,如下
// my_flutter 是建立Flutter的模組名稱
flutter_application_path = '../my_flutter'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
platform :ios, '9.0'
target 'NativeIOS' do
use_frameworks!
/// 這邊引入
install_all_flutter_pods(flutter_application_path)
/// 其他
...
end
複製程式碼
4、在原生目錄下,pod install,在pod install之前,先在Flutter模組下執行 flutter pub get
4.1、
Flutter模組下 執行 flutter pub get
4.2、
在原生專案下 執行 pod install
如果以上不報錯,混合開發模式到這裡就整合完了。,可以好好的玩耍了。不過好像想的有點多...
5、Flutter模組那邊怎麼寫還是怎麼寫,Flutter模組也是可以跑起來的。
6、在原生專案中註冊Flutter引擎, 就是flutterEngine
。 在啟動的時候就註冊,這樣後續就不會出現卡頓的樣式,有點兒難受。
/// 在AppDelegate入口初始化即可
#pragma mark - initFlutterEngine
- (void)initFlutterEngine {
self.flutterEngine = [[FlutterEngine alloc] initWithName:@"WMFlutterEngine"];
[self.flutterEngine run];
[GeneratedPluginRegistrant registerWithRegistry:self.flutterEngine];
}
/// 修改如下改成 FlutterEngine
@interface AppDelegate : FlutterEngine
複製程式碼
7、在原先專案需要跳轉的地方寫業務即可了。
/// 某個原生控制器
// testPushFlutterPage 跳轉的地方 ,其中self.flutterVC 是我單獨的一個類 見8
/// 跳轉到Flutter頁面。
- (void)testPushFlutterPage {
self.flutterVC.fd_prefersNavigationBarHidden = YES;
[self showViewController:self.flutterVC sender:nil];
}
- (void)initMethodChannel {
self.flutterVC = [[WMFlutterViewController alloc] init];
[self.flutterVC initMethodChannel];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self initMethodChannel];
}
複製程式碼
8、flutterVC類
#pragma mark - Initial Methods // 初始化的方法
- (instancetype)init
{
self = [super init];
if (self) {
self = [[WMFlutterViewController alloc] initWithEngine:[self getFlutterEngine] nibName:nil bundle:nil];
}
return self;
}
//
- (void)initMethodChannel {
FlutterMethodChannel *methodChannel = [FlutterMethodChannel methodChannelWithName:@"PatientSearchChannel" binaryMessenger:self.binaryMessenger];
self.methodChannel = methodChannel;
//通過block回撥監聽通道中來自flutter的訊息體 這裡做一個dismiss方法,由於iOS中將flutter頁面push出來,次數實現dismiss方法,給flutter傳送dismss訊息,就知道是讓iOS將當前頁面關閉的動作,iOS收到後,執行關閉操作
__weak typeof(self) weakself = self;
[methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
__strong typeof(weakself) strongself = weakself;
//dissmiss當前頁面
if([call.method isEqualToString:@"dismiss"]){
// [strongself.flutterVC dismissViewControllerAnimated:YES completion:nil];
[strongself.navigationController popViewControllerAnimated:YES];
}
if (result) {
result(@"回到的地方");
}
//dissmiss當前頁面
if([call.method isEqualToString:@"pushNative"]){
WMLog(@"pushNative 進來了 資料是 %@", call.arguments);
WMNoticeSetViewController *VC = [[WMNoticeSetViewController alloc] init];
WMLog(@"%@", self .navigationController);
[self.navigationController pushViewController:VC animated:YES];
}
//dissmiss當前頁面
if([call.method isEqualToString:@"pushNativeTwo"]){
WMLog(@"pushNativeTwo 進來了 資料是 %@", call.arguments);
NSDictionary *dataDic = call.arguments;
WMTestViewController *VC = [[WMTestViewController alloc] init];
VC.name = dataDic[@"name"];
WMLog(@"%@", self.navigationController);
[self.navigationController pushViewController:VC animated:YES];
}
}];
}
/// 獲取引擎
- (FlutterEngine *)getFlutterEngine {
FlutterEngine *flutterEngine = ((AppDelegate *)UIApplication.sharedApplication.delegate).flutterEngine;
return flutterEngine;
}
複製程式碼
以後原生部分就寫完了。
9、Flutter部分,我寫了一個工具類,來和原生互動的類
class NativeChannelUtils {
static const MethodChannel _patientSearchChannel =
MethodChannel('PatientSearchChannel');
/// 患者搜尋關閉
static patientSearchDismiss({WMValueCallBack valueCallBack}) {
_patientSearchChannel.invokeMethod("dismiss").then((value) {
Utils.logs('回來的資料 = ${value}');
if (valueCallBack != null) {
valueCallBack(value);
}
});
}
/// 患者搜尋到原生介面
static patientSearchPushToNative({WMValueCallBack valueCallBack}) {
_patientSearchChannel.invokeMethod(
"pushNative", {"data": "我是Flutter資料", 'code': '1000'}).then((value) {
Utils.logs('回來的資料 = ${value}');
if (valueCallBack != null) {
valueCallBack(value);
}
});
}
/// 患者搜尋到原生介面
static patientSearchPushToNativeTwo(
{Map arguments, WMValueCallBack valueCallBack}) {
_patientSearchChannel
.invokeMethod("pushNativeTwo", arguments)
.then((value) {
Utils.logs('回來的資料 = ${value}');
if (valueCallBack != null) {
valueCallBack(value);
}
});
}
}
複製程式碼
在Flutter需要的地方呼叫。
NativeChannelUtils.patientSearchDismiss(valueCallBack: (value) {
Utils.logs("哈哈哈哈");
});
複製程式碼
` 注意點:原生和Flutter互動有三種方式,目前使用的MethodChannel方式
MethodChannel:Flutter 與 Native 端相互呼叫,呼叫後可以返回結果,可以 Native 端主動呼叫,也可以Flutter主動呼叫,屬於雙向通訊。此方式為最常用的方式, Native 端呼叫需要在主執行緒中執行。
BasicMessageChannel:用於使用指定的編解碼器對訊息進行編碼和解碼,屬於雙向通訊,可以 Native 端主動呼叫,也可以Flutter主動呼叫。
EventChannel:用於資料流(event streams)的通訊, Native 端主動傳送資料給
複製程式碼
這個是Flutter原生方式混合開發。由於是在專案中整合的,後期看下 提出demo.
這邊我用閒魚的flutter_boost 混合開發方案 寫了一個demo。 demo地址:github.com/yj229201093…
但總覺得和自己想要的差一點點東西。所以目前採用原生方式混合開發。
注意:
如果使用原生方式,儘量不要開多個引擎,不然開銷很大,就是:下面就開啟了兩個引擎。Flutter引擎是相互獨立的。互不干擾的。
原生A->FlutterB,
FlutterB->FlutterC,
FlutterC->原生D,
原生D->FlutterE
建議是一個閉環開發,一個專案開啟一個Flutter引擎。就是原生進入Flutter模組,然後Flutter模組結束後就回到原生,這樣算一個閉環。
如果反覆跳轉可以使用閒魚的flutter_boost方案。
後續可能採用flutter_boost方案。目前導航欄方便還有點沒有理清。