iOS - Flutter混合開發項目集成Flutter模塊詳細指南

前言

前一篇文章講解了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,可以參考https://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
image

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插件)
image
  • 啟動我們的應用

接下來就可以像調試普通Flutter項目一樣來調試混合開發模式下的Dart代碼了。

總結

本文主要是講解了iOS集成Flutter項目的步驟,其中也遇到了一些問題,由于我的Xcode版本較低,在集成的過程中iOS項目的依賴一直失敗。最后才發現是Xcode的版本問題。

如果你覺得文章還不錯,請大家點贊分享下,你的肯定是對我最大的鼓勵和支持。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。