背景介紹:OC的iOS項目浮创,集成flutter模塊
注意忧吟,下文中"iOS項目"指將要集成flutter的原生項目,“.ios項目”指由flutter工程生成的被集成項目
準(zhǔn)備工作:
1斩披,flutter工程(第三方的溜族,或者其他同事開發(fā)的,需要集成到iOS項目的flutter工程)
2垦沉,本地flutter環(huán)境煌抒,建議與flutter工程的版本保持一致,不然后續(xù)會有兼容問題
3厕倍,iOS工程寡壮。
4,cocoapods環(huán)境
集成項目:
1,flutter項目編譯:
注意編譯出來的文件夾是隱藏的况既,可以用shift+command+.來顯示隱藏文件夾
終端cd到flutter路徑內(nèi)这溅,執(zhí)行命令:flutter run 。
無報錯:則生成了可用于集成的.iOS項目.ios文件夾默認(rèn)為隱藏狀態(tài)棒仍。生成后的flutter工程如下所示:
若有報錯:根據(jù)錯誤類型做對應(yīng)處理悲靴,一般分為以下幾種錯誤類型
1.1.0, 環(huán)境問題: 可以借助IDE比如Xcode降狠,vscode中打開对竣,會幫你配置好剩余環(huán)境。(比如No supported devices connected.我隨便打開個Xcode項目選中連接的真機后就)
1.1.1榜配, flutter項目代碼問題:使用相關(guān)開發(fā)工具檢查flutter代碼(比如:vscode否纬,添加flutter和dark插 件后。進行debug)蛋褥,flutter項目與本地flutter版本不一致時临燃,有時也會導(dǎo)致此問題。
1.1.2烙心,.ios項目內(nèi)問題:檢查.ios項目build有什么問題膜廊,(可以使用xcode打開.ios項目)檢查開發(fā)賬戶和證書配置是否正確,檢查cocoapods是否正常集成淫茵,檢查第三方庫是否需要項目添加swift依賴爪瓜,cd進入.iOS路徑下,cocoapod重新install匙瘪。
2铆铆,集成到iOS項目中:
2.1 修改iOS項目中的Podfile文件:(若iOS項目未使用cocoapods,需要新建Podfile文件丹喻,)
增加以下選中內(nèi)容:主要目的是按照所編輯路徑將上一步中的.ios項目集成到iOS項目中
2.2 將iOS項目和flutter項目按照以下位置關(guān)系置于同一文件夾下薄货。(符合上一步中的路徑關(guān)系)
2.3,pod刷新 終端cd到iOS項目路徑下碍论,執(zhí)行pod install(若有swift依賴問題見1.1.2配圖)谅猾。
完成項目集成后,可能后續(xù)打包會出現(xiàn)Bitcode設(shè)置問題鳍悠,將pod中TARGETS相關(guān)庫的Enable Bitcode設(shè)置為NO即可税娜。
3,代碼調(diào)用:
代碼部分主要分為兩部分:
1藏研,配置啟動器敬矩。
目前項目使用FlutterEngineGroup用以實現(xiàn)復(fù)合的flutter頁面集成。單一flutter項目也可以使用
FlutterEngine
在Appdelegate.h中添加:
#import <Flutter/Flutter.h>
//@property (nonatomic,strong) FlutterEngine *flutterEngine;
@property (nonatomic,strong) FlutterEngineGroup *flutterEngineGroup;
在Appdelegate.m中添加:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
.....
self.flutterEngineGroup = [[FlutterEngineGroup alloc] initWithName:@"flutterGroupName" project:NULL];
//若只有單一flutter頁面遥倦,也可以用以下代碼
//FlutterEngine:
// self.flutterEngine = [[FlutterEngine alloc] initWithName:@"my flutter engine"];
// [self.flutterEngine run];
// [GeneratedPluginRegistrant registerWithRegistry:self.flutterEngine];
return YES;
}
2谤绳,生成頁面及通道占锯。
以flutter里面提供了頁面page_one,通道名稱page_One_channal為例子缩筛。
flutter頁面為繼承FlutterViewController的類消略。
自定義類:XYFlutterViewController:
XYFlutterViewController.h代碼:
#import <Flutter/Flutter.h>
NS_ASSUME_NONNULL_BEGIN
@interface XYFlutterViewController : FlutterViewController
//返回flutter頁面
+(XYFlutterViewController *)flutterPageWithName:(NSString *)name;
@end
NS_ASSUME_NONNULL_END
FlutterMethodChannel:通道,flutter與原生交互依賴通道瞎抛,一般每個flutter頁面維護一個通道
setMethodCallHandler:給通道注冊方法艺演,調(diào)用原生內(nèi)容
invokeMethod:原生使用通道調(diào)用flutter內(nèi)的方法。
XYFlutterViewController.m代碼:
#import "AppDelegate.h"http://主要用來獲取全局flutterEngineGroup
#import <FlutterPluginRegistrant/FlutterPluginRegistrant-umbrella.h>
#import "XYFlutterViewController.h"
@interface XYFlutterViewController ()
@property (strong,nonatomic)FlutterMethodChannel *Channel;
@property (strong,nonatomic)NSMutableDictionary *flutterMCDic;//FlutterMethodChannel集合
@end
@implementation XYFlutterViewController
//懶加載flutter的MethodChannel桐臊,有則取胎撤,無則創(chuàng)建
/*
name為flutter約定的的通道名稱
*/
-(FlutterMethodChannel *)flutterMethodChannelWithName:(NSString *)name
{
if (self.flutterMCDic[name]) {
return self.flutterMCDic[name];
}
FlutterMethodChannel *notifationChannel = [FlutterMethodChannel methodChannelWithName:name binaryMessenger:self];
[self.flutterMCDic setObject:notifationChannel forKey:name];
return notifationChannel;
}
-(NSMutableDictionary *)flutterMCDic
{
if (!_flutterMCDic) {
_flutterMCDic = [NSMutableDictionary new];
}
return _flutterMCDic;
}
-(void)dealloc
{
[self.flutterMCDic removeAllObjects];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
/*
name為flutter提供的頁面名稱,以page_one頁面為例子,通道名稱為page_One_channal
*/
+(XYFlutterViewController *)flutterPageWithName:(NSString *)name
{
FlutterEngine *flutterEngine = [((AppDelegate *)UIApplication.sharedApplication.delegate).flutterEngineGroup makeEngineWithEntrypoint:name libraryURI:nil];
[GeneratedPluginRegistrant registerWithRegistry:flutterEngine];
XYFlutterViewController *flutterViewController = [[XYFlutterViewController alloc] initWithEngine:flutterEngine nibName:nil bundle:nil];
//頁面添加通道,page_One參數(shù)為futter中設(shè)置的
if ([name isEqualToString:@"page_One"]) {
[flutterViewController addActionWithName:@"page_One_channal"];
}
}
/*
name為flutter約定的的通道名稱
*/
-(void)addActionWithName:(NSString *)name
{
//call.method flutter方法名
//call.arguments flutter給到的參數(shù)
FlutterMethodChannel *notifationChannel = [self flutterMethodChannelWithName:name];
//設(shè)置回調(diào):以方法1:userChannel 方法2:jumpChannel為例
[notifationChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
//userChannel方法:需要數(shù)據(jù)回調(diào):
if ([@"userChannel" isEqualToString:call.method]) {
NSDictionary *dic = @{
@"userId":@"****",
};
result(dic);
}else if ([@"jumpChannel" isEqualToString:call.method]) {
//jumpChannel方法:從flutter頁面調(diào)用原生頁面
UIViewController *vc = [UIViewController new];
vc.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController:vc animated:YES];
}
}];
}
//主動調(diào)用flutter方法:
-(void)flutter_actionWithChannleName:(NSString *)channel Name:(NSString *)name
{
FlutterMethodChannel *notifationChannel = [self flutterMethodChannelWithName:channel];
if([name isEqualToString:@"refrish"]){
NSDictionary *dic = @{
@"userId":@"****",
};
//通道去調(diào)用flutter方法
[notifationChannel invokeMethod:name arguments:dic];
}
}