Flutter混合開發(二):iOS項目集成Flutter模塊詳細指南

本文首發於微信公衆號「Android開發之旅」,歡迎關注 ,獲取更多技術乾貨html

前言

前一篇文章講解了Android原生工程如何集成Flutter項目的具體過程,Flutter混合開發(一):Android項目集成Flutter模塊詳細指南 ,本篇將帶着你們來一塊兒學習原生iOS項目如何集成Flutter。android

由於每一個版本的集成邏輯都是有差異的,因此這裏交代下本篇文章的集成版本:ios

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。git

cd flutter/flutter_hybrid/

flutter create -t module flutter_module
複製代碼

輸入後控制檯打印以下:json

$ 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依賴bash

爲iOS項目添加依賴須要使用CocoaPods,若是你尚未用到CocoaPods,能夠參考cocoapods.org/上面的說明來安裝CocoaPods。微信

若是你的項目以前沒有使用過cocoapods,那麼須要進行初始化生成podfile文件,進入iOS項目的根目錄執行:session

pod init
複製代碼

而後打開podfile文件,進行配置:app

# 配置
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開發必備Dart基礎:Dart快速入門

Flutter混合開發(一):Android項目集成Flutter模塊詳細指南

Flutter混合開發(三):Android與Flutter之間通訊詳細指南

掃描下方二維碼關注公衆號,獲取更多技術乾貨。

相關文章
相關標籤/搜索