iOS原生專案中整合flutter初試

醉了碼發表於2021-07-28

背景

我們公司一直用 Objective-C 語言來開發iOS的專案,最近提出要用跨平臺混合語言flutter來研發新的功能,並計劃逐步過渡到flutter專案。花了一整天的時間來研究flutterObjective-C中的整合,現將探索過程分享如下:

參考Flutter官方文件

一、安裝Flutter SDK

1、下載最新版的Flutter SDK

flutter_macos_2.2.3-stable.zip

2、將下載好的sdk解壓到合適的目錄

cd /Users/jim
unzip ~/Downloads/flutter_macos_2.2.3-stable.zip
複製程式碼

3、新增flutter環境變數

3.1 在.zshrc中新增下面一行程式碼(我用的zsh

export PATH="$PATH:[PATH_OF_FLUTTER_GIT_DIRECTORY]/bin"

3.2 驗證是否新增成功

echo $PATH

3.3 檢視 flutterdart

 $ which flutter dart
# 列印:
  /path-to-flutter-sdk/bin/flutter
  /path-to-flutter-sdk/bin/dart
複製程式碼

如果你操作的結果如上所示,說明安裝成功了!

二、iOS配置

1、到AppStore下載並安裝最新版本的Xcode;

2、配置Xcode command-line tools,在終端執行如下命令:

sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
sudo xcodebuild -runFirstLaunch
複製程式碼

二、安裝並配置開發工具Visual Studio Code

VS Code是一個輕量級的編輯器,支援Flutter app 的執行和除錯。

1、安裝

下載最新版本: Visual Studio Code 下載完成後,雙擊安裝即可!

2、安裝Flutter 和 Dart外掛

  1. Start VS Code.
  2. Invoke View > Command Palette….
  3. Type “install”, and select Extensions: Install Extensions.
  4. Type “flutter” in the extensions search field, select Flutter in the list, and click Install. This also installs the required Dart plugin.

3、使用Flutter doctor驗證配置是否成功

  1. Invoke View > Command Palette….
  2. Type “doctor”, and select the Flutter: Run Flutter Doctor.
  3. Review the output in the OUTPUT pane for any issues. Make sure to select Flutter from the dropdown in the different Output Options.

4、測試驅動

4.1 建立App

  1. Invoke View > Command Palette.
  2. Type “flutter”, and select the Flutter: New Application Project.
  3. Create or select the parent directory for the new project folder.
  4. Enter a project name, such as myapp, and press Enter.
  5. Wait for project creation to complete and the main.dart file to appear.·

4.2 執行App

4.2.1 檢視VS Code底部的狀態列:

image.png

4.2.2 選擇裝置

Device Selector區域,選擇一個裝置,如果裝置不存在,就點選No Devices來建立一個模擬器。

4.2.3 執行

Invoke Run > Start Debugging or press F5.

三、原生Objective-C專案整合Flutter

Flutter可以作為嵌入式框架增量地新增到現有的iOS應用程式中。

1、將開發好的 Flutter 專案放到與原生工程同級目錄下;

some/path/
├── my_flutter/
│   └── .ios/
│       └── Flutter/
│         └── podhelper.rb
└── MyApp/
    └── Podfile

複製程式碼

2、Use the CocoaPods dependency manager and installed Flutter SDK

2.1、 在 Podfile中新增下面的程式碼:

flutter_application_path = '../my_flutter'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
複製程式碼

2.2、 For each Podfile target that needs to embed Flutter, call install_all_flutter_pods(flutter_application_path).

target 'MyApp' do
  install_all_flutter_pods(flutter_application_path)
end
複製程式碼

2.3、 Run pod install.

3、新增Flutter screeniOS app

3.1 、建立一個FlutterEngine

In AppDelegate.h:

@import UIKit;
@import Flutter;

@interface AppDelegate : FlutterAppDelegate // More on the FlutterAppDelegate below.
@property (nonatomic,strong) FlutterEngine *flutterEngine;
@end
複製程式碼

In AppDelegate.m:

// Used to connect plugins (only if you have plugins with iOS platform code).
#import <FlutterPluginRegistrant/GeneratedPluginRegistrant.h>

#import "AppDelegate.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary<UIApplicationLaunchOptionsKey, id> *)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
複製程式碼

3.2 、使用FlutterEngine來展示一個FlutterViewController

@import Flutter;
#import "AppDelegate.h"
#import "ViewController.h"

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

    // 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
複製程式碼

四、後續開發工作

當修改my_flutter/pubspec.yaml外掛依賴的時候,需要在 Flutter module 目錄下執行flutter pub get命令,用被podhelper.rb指令碼來重新整理外掛列表,最後在原生專案目錄下some/path/MyApp,執行pod install即可。

四、常見報錯及解決辦法

1、 如果發現專案報target of uri doesn't exist

此時直接在Android studio軟體底部的terminal裡執行flutter upgrade

2、flutter 基於ocflutter專案使用基於swiftplugin導致報錯問題?

t.zoukankan.com/qqcc1388-p-…

github.com/mxcl/Promis…

3、flutter 中引用的 plugins 可能跟原工程定義的類有重複的

解決辦法:刪除原生工程裡面的第三方類;

4、iOS14 系統一啟動 App 就閃退

Due to low-level changes in iOS’s debugger mechanisms, developers using versions of Flutter earlier than 1.20.4 stable won’t be able to launch apps (by using flutter run or a Flutter-enabled IDE) on physical iOS devices running iOS 14. This affects debugprofile, and release builds. Simulator builds, add-to-app modules, and running directly from Xcode are unaffected.

Upgrading to Flutter 1.22 beta allows you to build, test, and deploy to iOS without issue. Upgrading to 1.20.4 stable allows you to build and deploy to iOS 14, but not debug.

翻譯:

由於iOS偵錯程式機制的低階變化,使用1.20.4 stable之前版本的開發者將無法在執行iOS 14的物理iOS裝置上啟動應用(通過使用flutter run 執行或Flutter-enabled IDE)。這將影響除錯、profile和釋出構建。模擬器構建、新增到應用程式的模組,以及直接從Xcode執行都不受影響。

升級到Flutter 1.22 beta版可以讓你毫無問題地構建、測試和部署到iOS上。升級到1.20.4 stable允許你構建和部署到iOS 14,但不能除錯。

解決: 將 scheme 改成 release 即可

參考資料

1、flutter官方文件

相關文章