目前在已有的原生APP中嵌入Flutter頁面主要有兩種方案,一種是將原生工程作為Flutter工程的子工程,由Flutter進行統(tǒng)一管理琅催,這種模式稱為統(tǒng)一管理模式。一種是將Flutter工程作為原生工程的子模塊虫给,維持原有的原生工程管理方式不變藤抡,這種模式稱為三端分離模式。
三端代碼分離模式的原理是把Flutter模塊作為原生工程的子模塊抹估,從而快速地接入Flutter模塊缠黍,降低原生工程的改造成本。
原生iOS集成Flutter
環(huán)境要求:
Flutter支持iOS 8.0之后的版本
CocoaPods版本要求在1.10之后
一药蜻、創(chuàng)建Flutter模塊
進入原生工程目錄瓷式,執(zhí)行如下命令:
cd path/
flutter create --template module my_flutter
Flutter子工程將會創(chuàng)建在path/my_flutter
目錄下替饿,在這個目錄下你可以使用flutter的所有命令進行操作,如flutter run --debug
或者flutter build ios
等贸典。這個子工程包含一個單頁面示例视卢,可以單獨測試該模塊。
目錄結構大致如下:
之后就可以在path/my_flutter/lib/
編寫Dart代碼了
在path/my_flutter/pubspec.yaml
文件中添加Flutter依賴包或者插件
.ios
目錄是一個隱藏子文件夾廊驼,包含模塊可以獨立運行的內容据过,其中podhelper.rb
這個腳本文件可以幫助使用CocoaPods將依賴的Framework或者嵌入的模塊引入到已有原生工程中。
注意:原生代碼還在原生的結構目錄中進行編寫,不要寫在隱藏目錄
.ios
目錄之下,如果寫在該目錄下有可能被Flutter重寫掉膘滨。隱藏目錄.ios
不需要進行源碼管理,該隱藏文件夾是自動生成的幅聘。在新機器中運行只需要在path/my_flutter/
中執(zhí)行flutter pub get
就又可以自動生成了。
shift + Commond + ,
這個快捷鍵可以快速切換隱藏文件的顯隱
二、將Flutter模塊嵌入到原生工程中
有兩種方式:
方式一:使用Cocoapods依賴安裝Flutter SDK(推薦使用)
開放式可以使開發(fā)人員有一個本地安裝的Flutter SDK版本,只需要在Xcode中構建應用程序原朝,自動運行的腳本會嵌入Dart和插件代碼。
如果原生工程沒有Podfile彻消,先為工程添加一下竿拆。如果已有Podfile
(1)添加如下內容到Podfile文件中:
flutter_application_path = 'my_flutter'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
(2)在每個Podfile 的target中嵌入Flutter
target 'xxxx' do
install_all_flutter_pods(flutter_application_path)
end
(3)運行pod install
看到如下內容則嵌入完成宙拉,剩下的就是編寫代碼了
podhelper.rb
文件將你的插件宾尚、Flutter.framework和App.framework嵌入到你的項目中。應用程序的Debug和Release構建配置也會分別嵌入Flutter的Debug和Release構建模式下谢澈。Flutter.framework是Flutter的引擎相關bundle煌贴,App.framework是項目的編譯的Dart代碼。
注意:當改變Flutter中
pubspec.yaml
中依賴的插件后锥忿,執(zhí)行flutter pub get
刷新插件列表牛郑,也會通過podhelp.rb
腳本,在原生工程中需要重新執(zhí)行以下pod install
操作
方式二:將Flutter引擎敬鬓、編譯的Dart代碼和插件打包成Framework淹朋,然后引入工程
該方式可以具體查看官方文檔
三、增加一個Flutter頁面
1钉答、開啟FlutterEngine和FlutterViewController
FlutterEngine充當Dart VM和Flutter運行時的宿主础芍,F(xiàn)lutterViewController連接到一個FlutterEngine,將UIKit輸入時間傳遞到Flutter数尿,并顯示由FlutterEngine渲染的幀仑性。
FlutterEngine和FlutterViewController可能有著相同的生命周期,或者比FlutterViewController的生命周期更長右蹦。
注意:通常建議為應用程序預熱一個更長生命周期的FlutterEngine诊杆,這是因為:
(1)當展示一個FlutterViewController的時候歼捐,第一幀出現(xiàn)的比較快
(2)Flutter和Dart的狀態(tài)要比FlutterViewController生命更長一些
(3)在顯示UI之前,您的應用程序和插件可以與Flutter和Dart有一些邏輯交互晨汹。
2豹储、創(chuàng)建FlutterEngine
在APP的合適位置創(chuàng)建FlutterEngine,下邊以APP啟動在AppDelete中以暴露屬性的方式進行創(chuàng)建:
在AppDelegate.swift文件中
import UIKit
import Flutter
// Used to connect plugins (only if you have plugins with iOS platform code).
import FlutterPluginRegistrant
@UIApplicationMain
class AppDelegate: FlutterAppDelegate { // More on the FlutterAppDelegate.
lazy var flutterEngine = FlutterEngine(name: "my flutter engine")
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Runs the default Dart entrypoint with a default Flutter route.
flutterEngine.run();
// Used to connect plugins (only if you have plugins with iOS platform code).
GeneratedPluginRegistrant.register(with: self.flutterEngine);
return super.application(application, didFinishLaunchingWithOptions: launchOptions);
}
}
在事件或者調用的時候跳轉至FlutterViewController淘这,F(xiàn)lutterViewController使用在AppDelegate中創(chuàng)建的FlutterEngine實例颂翼。
/// 按鈕點擊
@objc func showFlutter() {
let flutterEngine = (UIApplication.shared.delegate as! AppDelegate).flutterEngine
let flutterViewController =
FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)
present(flutterViewController, animated: true, completion: nil)
}
到此,已經(jīng)在iOS應用中嵌入了Flutter頁面慨灭,這時候當調用FlutterEngine中的run
方法就能夠調到Dart中的main()
函數(shù)了
3朦乏、另外一種選擇,使用隱式FlutterEngine的方式創(chuàng)建FlutterViewController
可以讓FlutterViewController隱式的創(chuàng)建自己的FlutterEngine氧骤,不需要提前預熱呻疹,這種方式通常并不推薦,因為按需創(chuàng)建FlutterEngine可能會在FlutterViewController呈現(xiàn)和渲染其第一幀的時候有明顯的延遲筹陵。這種方式適合用在很少使用Flutter的頁面或者無法確定在何時應該啟動Dart VM的時候刽锤。
要讓FlutterViewController在沒有現(xiàn)有FlutterEngine的情況下出現(xiàn),忽略FlutterEngine的構造朦佩,并創(chuàng)建沒有引擎的FlutterViewController并思,可以如下使用:
func showFlutter() {
let flutterViewController = FlutterViewController(project: nil, nibName: nil, bundle: nil)
present(flutterViewController, animated: true, completion: nil)
}
4、使用FlutterAppDelegate
建議使用應用的UIApplicationDelegate子類FlutterAppDelegate语稠,但不是必需的宋彼。
FlutterAppDelegate執(zhí)行的函數(shù)如下:
- 轉發(fā)應用程序回調函數(shù),如openURL到插件仙畦,如local_auth输涕。
- 轉發(fā)狀態(tài)欄輕按(只能在AppDelegate中檢測到)來觸發(fā)滾動到頂部的行為。
如果你的應用代理不能直接使FlutterAppDelegate成為一個子類慨畸,可以讓你的應用代理實現(xiàn)FlutterAppLifeCycleProvider協(xié)議莱坎,以確保插件接收到必要的回調。否則寸士,依賴于這些事件的插件可能有未定義的行為檐什。