本文首發於微信公眾號「Android開發之旅」,歡迎關注 ,獲取更多技術乾貨
前言
前一篇文章講解了Android原生工程如何整合Flutter專案的具體過程,Flutter混合開發(一):Android專案整合Flutter模組詳細指南 ,本篇將帶著大家來一起學習原生iOS專案如何整合Flutter。
因為每個版本的整合邏輯都是有差別的,所以這裡交代下本篇文章的整合版本:
Flutter (channel dev,v1.10.16)
dart (v2.7.0)
Xcode (v11.2)
cocoapds (1.8.4)
複製程式碼
建立Flutter module
假如iOS專案的路徑是這樣的:flutter/flutter_hybrid/iOS Project,那麼我們需要在iOS Project上一層目錄flutter_hybrid中建立Flutter module。
cd flutter/flutter_hybrid/
flutter create -t module flutter_module
複製程式碼
輸入後控制檯列印如下:
$ flutter create -t module flutter_module
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/Flutter_for_Android.xml (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... 1.2s
Wrote 12 files.
All done!
Your module code is in flutter_module/lib/main.dart.
複製程式碼
看到All done就表示我們專案建立好了。整個module目錄和原生Flutter基本一樣,主要就是Android、iOS的宿主工程和lib目錄以及pubspec.yaml檔案。
#新增Flutter module依賴
為iOS專案新增依賴需要使用CocoaPods,如果你還沒有用到CocoaPods,可以參考cocoapods.org/上面的說明來安裝CocoaPods。
如果你的專案之前沒有使用過cocoapods,那麼需要進行初始化生成podfile檔案,進入iOS專案的根目錄執行:
pod init
複製程式碼
然後開啟podfile檔案,進行配置:
# 配置
flutter_application_path = '../flutter_module/'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
target 'iOSFlutterHybrid' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
# Pods for iOSFlutterHybrid
# 配置
install_all_flutter_pods(flutter_application_path)
target 'iOSFlutterHybridTests' do
inherit! :search_paths
# Pods for testing
end
target 'iOSFlutterHybridUITests' do
# Pods for testing
end
複製程式碼
配置新增好後在專案根目錄執行以下命令進行安裝:
pod install
複製程式碼
控制檯輸出:
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 `iOSFlutterHybrid.xcworkspace` for this project from now on.
Pod installation complete! There are 3 dependencies from the Podfile and 3 total pods installed.
[!] Automatically assigning platform `iOS` with version `13.2` on target `iOSFlutterHybrid` because no platform was specified. Please specify a platform for this target in your Podfile. See `https://guides.cocoapods.org/syntax/podfile.html#platform`.
複製程式碼
這裡我們看到有三個依賴安裝完成了。並提醒我們關閉當前專案,在根目錄下面使用iOSFlutterHybrid.xcworkspace來開啟執行專案。這裡可能很多人在執行命令的時候會發現提示0個依賴完成。這裡有可能是你的Xcode版本的問題。因為Flutter要求最低版本是10.2及以上。
當在flutter_module/pubspec.yaml中新增一個Flutter外掛時,需要在flutter_module目錄下執行:
flutter packages get
複製程式碼
來重新整理podhelper.rb指令碼中的外掛列表,然後在iOS目錄下執行:
pod install
複製程式碼
這樣podhelper.rb指令碼才能確保新增的外掛和Flutter.framework能夠新增到iOS專案中。
目前Flutter還不支援Bitcode,所以整合了Flutter的iOS專案需要禁用Bitcode。
在以下路徑下找到Bitcode並禁用:
Build Settings->Build Options->Enable Bitcode
複製程式碼
flutter以前的版本是需要新增build phase以構建Dart程式碼,但是最新的版本已經不需要新增了,可以自動構建。
呼叫Flutter module
Flutter為我們提供了兩種呼叫方式:FlutterViewController和FlutterEngine,FlutterEngine在使用的時候會有一些問題,將在下文進行說明。
FlutterViewController方式:
我們開啟ViewController.m檔案,在裡面新增一個載入flutter頁面的方法並且新增一個按鈕看來呼叫:
#import "ViewController.h"
#import <Flutter/Flutter.h>
#import "AppDelegate.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self action:@selector(handleButtonAction) forControlEvents:UIControlEventTouchUpInside];
[button setTitle:@"載入Flutter" forState:UIControlStateNormal];
[button setBackgroundColor:[UIColor blueColor]];
button.frame = CGRectMake(100, 100, 160, 60);
[self.view addSubview:button];
}
- (void)handleButtonAction{
FlutterViewController *flutterViewController =[FlutterViewController new];
//設定路由引數
[flutterViewController setInitialRoute:@"route2"];
[self presentViewController:flutterViewController animated:false completion:nil];
}
@end
複製程式碼
當我們執行專案點選載入Flutetr按鈕時,將會呼叫Flutter頁面。和Android專案整合一樣,這裡的setInitialRoute可以設定一個json陣列來傳遞需要互動的引數。並在Flutter中使用window.defaultRouteName來獲取傳遞的引數。
FlutterEngine方式:
我們需要在AppDelegate中對FlutterEngine進行初始化。開啟AppDelegate.h檔案:
#import <UIKit/UIKit.h>
#import <Flutter/Flutter.h>
@interface AppDelegate : FlutterAppDelegate
@property (nonatomic,strong) FlutterEngine *flutterEngine;
@end
複製程式碼
在開啟AppDelegate.m檔案:
// 如果你需要用到Flutter外掛時
#import <FlutterPluginRegistrant/GeneratedPluginRegistrant.h>
#include "AppDelegate.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.flutterEngine = [[FlutterEngine alloc] initWithName:@"io.flutter" project:nil];
[self.flutterEngine runWithEntrypoint:nil];
[GeneratedPluginRegistrant registerWithRegistry:self.flutterEngine]; //如果你需要用到Flutter外掛時
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end
複製程式碼
然後在ViewController.m檔案定義的handleButtonAction中呼叫:
- (void)handleButtonAction{
FlutterEngine *flutterEngine = [(AppDelegate *)[[UIApplication sharedApplication] delegate] flutterEngine];
FlutterViewController *flutterViewController = [[FlutterViewController alloc] initWithEngine:flutterEngine nibName:nil bundle:nil];
[flutterViewController setInitialRoute:@"route2"];
[self presentViewController:flutterViewController animated:false completion:nil];
}
複製程式碼
當我們執行專案點選載入Flutter按鈕時,將會呼叫Flutter頁面。前文講到使用FlutterEngine會有問題,就是我們setInitialRoute傳遞的引數在flutter中永遠獲取到的都是 “/” ,這個是Fltter SDK的一個Bug,所以如果必須依賴setInitialRoute,還是使用FlutterViewController的形式來載入Flutter模組。
熱重啟/重新載入
大家在寫純Flutter應用的時候,知道是有熱重啟/重新載入功能的,但是在做混合開發的過程中,你會發現熱重啟/重新載入功能失效了。那麼如何在混合開發中開啟熱重啟/重新載入功能呢?
- 首先接入我們的裝置或者模擬器
- 將我們的App關閉,退出後臺,在terminal中執行 flutter attach命令
$ flutter attach
Waiting for a connection from Flutter on Android SDK built for x86...
複製程式碼
複製程式碼此時就在等待裝置的連線。這裡要注意的是,如果電腦連線了多臺裝置需要使用 -d 命令來指定一臺裝置,引數為裝置的id。
flutter attach -d '你的裝置id'
複製程式碼
然後啟動我們的應用會看到控制檯輸出:
Done.
Syncing files to device Android SDK built for x86... 1,393ms
? To hot reload changes while running, press "r". To hot restart (and rebuild state), press "R".
An Observatory debugger and profiler on Android SDK built for x86 is available at: http://127.0.0.1:59354/zRsDBfpesrk=/
For a more detailed help message, press "h". To detach, press "d"; to quit, press "q".
複製程式碼
這樣就表示我們連線成功了。在輸出的日誌中也告訴了我們如何使用熱重啟/重新載入功能。
在Terminal中輸入以下命令:
r : 熱載入;
R : 熱重啟;
h : 獲取幫助;
d : 斷開連線;
q : 退出;
複製程式碼
這裡的的 d 和 q 的命令都有退出除錯,區別在於 d 命令只是單純的斷開而 q 命令會將應用退到後臺。
除錯Dart程式碼
同樣在混合開發過程中我們如何除錯dart程式碼呢?
- 關閉我們的應用
- 點選Android Studio工具欄上的Flutter Attach按鈕(需要安裝Flutter與Dart外掛)
- 啟動我們的應用
接下來就可以像除錯普通Flutter專案一樣來除錯混合開發模式下的Dart程式碼了。
總結
本文主要是講解了iOS整合Flutter專案的步驟,其中也遇到了一些問題,由於我的Xcode版本較低,在整合的過程中iOS專案的依賴一直失敗。最後才發現是Xcode的版本問題。這裡花費了很多時間去排查問題,所以大家在整合的過程中有問題可以關注公眾號加我微信,給我留言,我會幫助大家解決問題。
全部Demo原始碼已經上傳到後臺,關注公眾號回覆「混合開發」即可獲得下載連結。
如果你覺得文章還不錯,請大家點贊分享下,你的肯定是對我最大的鼓勵和支援。
推薦閱讀
Flutter混合開發(一):Android專案整合Flutter模組詳細指南