Flutter 三端分離模式開發(fā)(先基于原有iOS項目開發(fā)崇堵,更新中···)

2020年之前有些教程創(chuàng)建方式已經(jīng)不適用,要么缺文件客燕、要么原生項目運行報錯鸳劳,折騰幾天半個月都不行,還是官方文檔教程比較靠譜也搓。

目前原生App和Flutter混合開發(fā)有兩種模式:

  • 統(tǒng)一管理模式:將原生工程作為Flutter工程的子工程赏廓,由Flutter進(jìn)行統(tǒng)一管理。
  • 三端分離模式:將Flutter工程作為原生工程的子模塊傍妒,維持原有的原生工程管理方式不變幔摸。

一、基于原有iOS項目集成Flutter框架

前提要擁有CocoaPods和Flutter環(huán)境配置
Flutter官方文檔

1.1颤练、創(chuàng)建項目文件夾

新建總項目文件夾既忆,存放三端項目文件如:carry_sniper

1.2、創(chuàng)建Flutter模塊

在總項目文件夾內(nèi)嗦玖,創(chuàng)建Flutter模塊工程如:flutter_module

cd xxx/carry_sniper 你的文件夾路徑
flutter create --template module flutter_module

執(zhí)行結(jié)果:

Creating project flutter_module...
  flutter_module/test/widget_test.dart (created)
  flutter_module/flutter_module.iml (created)
  flutter_module/.gitignore (created)
  flutter_module/.metadata (created)
  flutter_module/pubspec.yaml (created)
  flutter_module/README.md (created)
  flutter_module/lib/main.dart (created)
  flutter_module/flutter_module_android.iml (created)
  flutter_module/.idea/libraries/Dart_SDK.xml (created)
  flutter_module/.idea/modules.xml (created)
  flutter_module/.idea/workspace.xml (created)
Running "flutter pub get" in flutter_module...                      0.8s
Wrote 11 files.

All done!
Your module code is in flutter_module/lib/main.dart.
1.3患雇、創(chuàng)建iOS項目工程

在總項目文件夾,使用Xcode創(chuàng)建iOS項目工程如:CarrySniperiOS

1.4宇挫、關(guān)聯(lián)操作
1.4.1為iOS工程添加CocoaPods依賴庆亡,生成Proflie文件

終端指令執(zhí)行:

cd xxx/carry_sniper/CarrySniperiOS 你的iOS工程項目路徑
pod init
1.4.2打開Proflie文件添加、修改內(nèi)容

主要2段3行代碼捞稿,注意代碼存放位置又谋,和flutter_module名稱一致

flutter_application_path = '../flutter_module'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
install_all_flutter_pods(flutter_application_path)

配置結(jié)果如下:

platform :ios, '11.0'
# 1拼缝、Flutter模塊加入
flutter_application_path = '../flutter_module'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')

target 'CarrySniperiOS' do
  use_frameworks!
  # 2、安裝嵌入Flutter模塊
  install_all_flutter_pods(flutter_application_path)

  # Pods for CarrySniperiOS

end
1.4.3執(zhí)行指令彰亥,完成Flutter模塊的添加和CocoaPods依賴
pod install

執(zhí)行結(jié)果:
要看到Installing Flutter相關(guān)依賴的安裝咧七,否則運行報錯
關(guān)閉當(dāng)前Xcode項目,從此使用CarrySniperiOS.xcworkspac運行工程

/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/universal-darwin19/rbconfig.rb:229: warning: Insecure world writable dir /Users/Macbook/Documents/FlutterSDK/flutter/bin in PATH, mode 040777
Analyzing dependencies
Downloading dependencies
Installing Flutter (1.0.0)
Installing FlutterPluginRegistrant (0.0.1)
Installing flutter_module (0.0.1)
Generating Pods project
Integrating client project

[!] Please close any current Xcode sessions and use `CarrySniperiOS.xcworkspace` for this project from now on.
Pod installation complete! There are 3 dependencies from the Podfile and 3 total pods installed.
1.5任斋、完成基礎(chǔ)配置

可以直接打開項目運行继阻,沒問題就說明配置成功。部分目錄如下:

carry_sniper/
├── CarrySniperiOS/
│   ├── CarrySniperiOS/
│   ├── Pods/
│   ├── Podfile
│   ├── Podfile.lock
│   ├── CarrySniperiOS.xcodeproj
│   └── CarrySniperiOS.xcworkspace
├── flutter_module/
│   ├── .android/
│   ├── .ios/
│   │    ├── Runner.xcworkspace
│   │    └── Flutter/podhelper.rb
│   ├── lib/
│       └── main.dart
│   ├── flutter_module_android.iml
│   ├── flutter_module.iml
│   ├── pubspec.lock
│   ├── test/
│   └── pubspec.yaml

二废酷、原生iOS項目調(diào)用Flutter

根據(jù)官方Flutter文檔瘟檩,進(jìn)行簡單的原生app調(diào)用Flutter,列舉2種方法澈蟆,這里是Objective-C代碼墨辛,文檔有Swift代碼。更高級的調(diào)用方法可以繼續(xù)看文檔趴俘。

2.1方式一:使用FlutterViewController

直接在ViewController.m文件編寫代碼睹簇,運行項目即可:

#import "ViewController.h"
#import <Flutter/Flutter.h>

@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];

    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    [button addTarget:self action:@selector(showFlutter)
     forControlEvents:UIControlEventTouchUpInside];
    [button setTitle:@"Show Flutter!" forState:UIControlStateNormal];
    button.backgroundColor = UIColor.blueColor;
    button.frame = CGRectMake(80.0, 210.0, 160.0, 40.0);
    [self.view addSubview:button];
}

- (void)showFlutter {
    FlutterViewController *flutterViewController = [[FlutterViewController alloc] initWithProject:nil nibName:nil bundle:nil];
    [self presentViewController:flutterViewController animated:YES completion:nil];
}

@end
2.2、方式二:使用FlutterEngine
2.1.1寥闪、依賴FlutterAppDelegate創(chuàng)建一個實體FlutterEngine

AppDelegate.h文件內(nèi)容:

#import <UIKit/UIKit.h>
#import <Flutter/Flutter.h>

@interface AppDelegate : FlutterAppDelegate

@property (nonatomic,strong) FlutterEngine *flutterEngine;

@end

AppDelegate.m文件內(nèi)容:

#import "AppDelegate.h"
#import <FlutterPluginRegistrant/GeneratedPluginRegistrant.h>

@interface AppDelegate ()
@end

@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.flutterEngine = [[FlutterEngine alloc] initWithName:@"my flutter engine"];
    // Runs the default Dart entrypoint with a default Flutter route.
    [self.flutterEngine run];
    // Used to connect plugins (only if you have plugins with iOS platform code).
    [GeneratedPluginRegistrant registerWithRegistry:self.flutterEngine];
    return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end
2.2.2太惠、使用FlutterEngine調(diào)用Flutter頁面和傳參

ViewController.m文件內(nèi)容:

#import "ViewController.h"
#import "AppDelegate.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    // Make a button to call the showFlutter function when pressed.
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    [button addTarget:self action:@selector(showFlutter)
     forControlEvents:UIControlEventTouchUpInside];
    [button setTitle:@"Show Flutter!" forState:UIControlStateNormal];
    button.backgroundColor = UIColor.blueColor;
    button.frame = CGRectMake(80.0, 210.0, 160.0, 40.0);
    [self.view addSubview:button];
}

- (void)showFlutter {
    FlutterEngine *flutterEngine =
    ((AppDelegate *)UIApplication.sharedApplication.delegate).flutterEngine;
    FlutterViewController *flutterViewController =
    [[FlutterViewController alloc] initWithEngine:flutterEngine nibName:nil bundle:nil];
    [self presentViewController:flutterViewController animated:YES completion:nil];
}

@end
2.2.3、運行Xcode中的CarrySniperiOS項目

三疲憋、原生iOS項目也能使用熱更新凿渊、熱重載

官方文檔:
要先安裝homebrew,運行Xcode項目缚柳,保證原生App有安裝到手機(jī)/模擬器上嗽元,然后在Android Studio的Flutter項目跟路徑執(zhí)行指令:

flutter attach

如果有多個設(shè)備(或者輸入下標(biāo)選擇相應(yīng)設(shè)備):

flutter attach -d xxxxx設(shè)備id

如果有多個包名:

那么需要統(tǒng)一Android和iOS的包名后再試一遍

如果出現(xiàn)Waiting for a connection from Flutter on iPhone ...一直等待,

說明原生App沒有啟動喂击,控制臺連接不到設(shè)備應(yīng)用運行。
需要手動到手機(jī)/模擬器點擊運行App即可(只需運行Android Studio淤翔,不需要打開Xcode軟件翰绊,Xcode會在Flutter下默默運行。當(dāng)然不打開Xcode旁壮,就看不到控制臺打印輸出监嗜,但影響不大)。

執(zhí)行結(jié)果:

Waiting for iPhone 12 Pro to report its views...                     7ms
Syncing files to device iPhone 12 Pro...                                
 8,140ms (!)                                       

Flutter run key commands.
r Hot reload. ??????
R Hot restart.
h Repeat this help message.
d Detach (terminate "flutter run" but leave application running).
c Clear the screen
q Quit (terminate the application on the device).
An Observatory debugger and profiler on iPhone 12 Pro is available at: http://127.0.0.1:51810/ucfjPzF2_sY=/

四抡谐、原生iOS項目后續(xù)可能遇到的問題

  • 如果發(fā)現(xiàn)運行App進(jìn)度和Flutter開發(fā)進(jìn)度不一致裁奇,需要去Xcode運行原生項目App。需要保證打包的代碼是最新的麦撵,否則安裝的App再次啟動后刽肠,永遠(yuǎn)是之前的版本溃肪,沒有包含最新Flutter部分的代碼。
個人理解:已安裝的App音五,我們使用飯flutter attach惫撰,熱更新和熱重載只保證運行時代碼是最新的,運行結(jié)束之后就恢復(fù)原生App安裝時的模樣躺涝,并沒有把最新的Flutter代碼打包到安裝包里面厨钻。
  • Showing Recent Messages Undefined symbol: protocol conformance descriptor fo xxx 等幾十上百個報錯
莫名其妙的出現(xiàn),之前運行還好好的坚嗜,可能Flutter添加了某些package夯膀,在原生項目就突然出問題了。
可能解決方法:
嘗試一:升級CocoaPods苍蔬;
嘗試二:更新依賴庫 pod install --verbose --no-repo-update
嘗試三:為原生項目添加swift橋接文件诱建,任意直接New一個.swift文件,Xcode 提示 Create Bridging Header 银室,選擇創(chuàng)建即可涂佃。記得.swift文件保留不刪除。
  • Command PhaseScriptExecution failed with a nonzero exit code
  • /packages/flutter_tools/bin/xcode_backend.sh: No such file or directory
先檢查Flutter SDK里面存不存在xcode_backend.sh文件蜈敢,不存在就去找一個或者重新下載sdk辜荠;
存在的話,可能就是Xcode項目配置可能缺少FLUTTER_ROOT抓狭,Target -> Build Setting -> User-Defined 添加FLUTTER_ROOT對應(yīng)sdk路徑伯病;
如果不知道路徑可以直接復(fù)制flutter項目的.ios的Generated.xcconfig里面的FLUTTER_ROOT內(nèi)容,會自動幫導(dǎo)入到User-Defined否过。
  • Support for empty structs is deprecated and will be removed in the next stable version of Dart. Use Opaque instead.
遇到SDK版本更新午笛,API過期更替。不影響使用苗桂,需要等待第三方插件更新支持最新包药磺。可以用'flutter downgrade'指令降級SDK煤伟。

五癌佩、一些想法

三端分離,flutter里面iOS的info.plist文件很容易在安卓合并代碼或pub get指令執(zhí)行時會被重置便锨,影響開發(fā)和調(diào)試围辙。當(dāng)然原生項目的info.plist文件是不影響的,只是不想開發(fā)期間直接用原生項目放案,效率不一樣姚建。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市吱殉,隨后出現(xiàn)的幾起案子掸冤,更是在濱河造成了極大的恐慌厘托,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贩虾,死亡現(xiàn)場離奇詭異催烘,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)缎罢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門伊群,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人策精,你說我怎么就攤上這事舰始。” “怎么了咽袜?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵丸卷,是天一觀的道長。 經(jīng)常有香客問我询刹,道長谜嫉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任凹联,我火速辦了婚禮沐兰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蔽挠。我一直安慰自己住闯,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布澳淑。 她就那樣靜靜地躺著比原,像睡著了一般。 火紅的嫁衣襯著肌膚如雪杠巡。 梳的紋絲不亂的頭發(fā)上量窘,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機(jī)與錄音氢拥,去河邊找鬼蚌铜。 笑死,一個胖子當(dāng)著我的面吹牛兄一,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播识腿,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼出革,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了渡讼?” 一聲冷哼從身側(cè)響起骂束,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤耳璧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后展箱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體旨枯,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年混驰,在試婚紗的時候發(fā)現(xiàn)自己被綠了攀隔。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡栖榨,死狀恐怖昆汹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情婴栽,我是刑警寧澤满粗,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站愚争,受9級特大地震影響映皆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜轰枝,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一捅彻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧狸膏,春花似錦沟饥、人聲如沸垦写。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽唉地。三九已至砾脑,卻和暖如春幼驶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背韧衣。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工盅藻, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人畅铭。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓氏淑,卻偏偏與公主長得像,于是被迫代替她去往敵國和親硕噩。 傳聞我的和親對象是個殘疾皇子假残,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容