iOS專案接入Flutter Module探索

語言: CN / TW / HK

Flutter Module官網三種接入方式

- 方式1:使用 CocoaPods 和 Flutter SDK 整合

  都在本地安裝 Flutter SDK。你的工程在每次構建的的時候,都將會從原始碼裡編譯 Flutter 模組。只需要在 Xcode 中編譯應用,就可以自動執行指令碼來整合 Dart 程式碼和外掛。這個方法允許你使用 Flutter module 中的最新程式碼快速迭代開發,而無需在 Xcode 以外執行額外的命令,這個方法也是Flutter官網推薦的整合方法,具體步驟如下:

  1.在 Podfile 中新增下面程式碼

some/path/ ├── my_flutter/ │ └── .ios/ │ └── Flutter/ │ └── podhelper.rb └── MyApp/ └── Podfile flutter_application_path = '../my_flutter' load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
  2.每個需要整合 Flutter 的 Podfile target,執行 install_all_flutter_pods(flutter_application_path)target 'MyApp' do install_all_flutter_pods(flutter_application_path) end


  3.在 Podfile 的 post_install 部分,呼叫 flutter_post_install(installer)post_install do |installer| flutter_post_install(installer) if defined?(flutter_post_install) end   總結:此整合方法需要開發者本地集成了Flutter的執行環境,整合方式比較方便,便於管理,但在Podfile中整合的路徑需要明確,也就是說Flutter Module模組的程式碼需要和iOS專案的程式碼統一提交在一個倉庫中,但Flutter Module的模組程式碼肯定是希望有自己程式碼倉庫,並且提供多端的能力支援,所以此時會以subModule或者subTree的方式進行整合,這種在多人開發中提交維護會比較耗時耗力。

- 方式2:在 Xcode 中整合 frameworks

  除了上面的方法,你也可以建立必備的 frameworks,手動修改既有 Xcode 專案,將他們整合進去。當你組內其它成員們不能在本地安裝 Flutter SDK 和 CocoaPods,或者你不想使用 CocoaPods 作為既有應用的依賴管理時,這種方法會比較合適。但是每當你在 Flutter module 中改變了程式碼,都必須執行 flutter build ios-framework。具體步驟如下:

  1.生成Flutter Modole產物
  下面的示例假設你想在 some/path/MyApp/Flutter/ 目錄下建立 frameworks:

flutter build ios-framework --output=some/path/MyApp/Flutter/ 執行指令後產生的三種類型的產物如下: ``` some/path/MyApp/ └── Flutter/ ├── Debug/ │ ├── Flutter.xcframework │   ├── App.xcframework │   ├── FlutterPluginRegistrant.xcframework (only if you have plugins with iOS platform code) │   └── example_plugin.xcframework (each plugin is a separate framework) ├── Profile/ │ ├── Flutter.xcframework │ ├── App.xcframework │ ├── FlutterPluginRegistrant.xcframework │ └── example_plugin.xcframework └── Release/ ├── Flutter.xcframework ├── App.xcframework ├── FlutterPluginRegistrant.xcframework └── example_plugin.xcframework

`` &emsp;&emsp;2.連結到專案中<br> &emsp;&emsp;在產生的產物中對應了三種類型,三種類型的使用區別可以自行搜尋查閱本文不過多贅述,直接將Release中的產物拖到Targets-General下面的Frameworks, Libraries, and Embedded Content中,正常編譯執行即可!<br> &emsp;&emsp;總結:`此方式接入Flutter Module的優點是不需要開發人員安裝Flutter環境的,缺點也很明顯,由於不是原始碼接入,所以在Debug開發時除錯比較困難,同時打包釋出需要一些必要的手動操作來替換Framework。

- 方式3:使用 CocoaPods 在 Xcode 和 Flutter 框架中內嵌應用和外掛框架

  除了將一個很大的 Flutter.framework 分發給其他開發者、機器或者持續整合 (CI) 系統之外,你可以加入一個引數 --cocoapods 將 Flutter 框架作為一個 CocoaPods 的 podspec 檔案分發。這將會生成一個 Flutter.podspec 檔案而不再生成 Flutter.framework 引擎檔案。就像第二種整合方式那樣,它將會生成 App.framework 和外掛框架。步驟如下:
  1.生成Flutter Modole產物
  要生成 Flutter.podspec 和框架,命令列切換到 Flutter module 根目錄,然後執行以下命令:
flutter build ios-framework --cocoapods --output=some/path/MyApp/Flutter/

some/path/MyApp/ └── Flutter/ ├── Debug/ │ ├── Flutter.podspec │   ├── App.xcframework │   ├── FlutterPluginRegistrant.xcframework │   └── example_plugin.xcframework (each plugin with iOS platform code is a separate framework) ├── Profile/ │ ├── Flutter.podspec │ ├── App.xcframework │ ├── FlutterPluginRegistrant.xcframework │ └── example_plugin.xcframework └── Release/ ├── Flutter.podspec ├── App.xcframework ├── FlutterPluginRegistrant.xcframework └── example_plugin.xcframework   2.連結到專案中
  在步驟1中生成的產物中我們可以看到既有spec檔案也有xcframework檔案,其中的spec檔案對應的是Flutter SDK也就是Flutter的執行環境,這個環境在每次的編譯中幾乎不會改變,所以官網生成了一個遠方的spec依賴,可以在podfile中進行遠方依賴引入。

pod 'Flutter', :podspec => 'some/path/MyApp/Flutter/[build mode]/Flutter.podspec'   其他的xcframework檔案就是在業務迭代中需要經常變動的業務程式碼和一些三方庫,這個可以繼續使用方式2的整合方式進行拖入工程中引入。
  總結:此方式接入Flutter Module和方式2有些類似,只是在生成的產物中由原來的~Flutter.xcframework變成了Flutter.podspec,並且引入Flutter的方式由原來的本地引入變成遠端引用,也是不需要開發人員本機配置Flutter開發環境。 ## Flutter Module整合的最佳實踐   以上是Flutter官網提供的在iOS工程中整合Flutter Module的三種方式;在討論Flutter Module的整合最佳實踐中,需要丟擲兩個問題:
1、希望Flutter Module生成的產物可以不手動拖入專案,可以進行遠端依賴
2、希望在Debug模組是可以直接原始碼除錯Flutter Module模組程式碼,可以進行熱過載

  首先看第一個問題,想讓iOS整合Flutter Module可以遠端依賴,這個我們可以在方式3中得到啟發,方式三中使用了spec對Flutter SDK進行了遠端依賴,那麼我們可不可以也使用自建的spec來遠端依賴.xcframework產物呢?
  其實是可以的,我們可以在遠端建一個倉庫,名稱就叫做FlutterFramewok,然後我們本地新建一個spec檔名為FlutterModuleSDK.podspec

```

Pod::Spec.new do |spec| spec.name = "FlutterFramewok" spec.version = "1.0.1" spec.summary = "flutter module framework" spec.description = <<-DESC Flutter Module 產物 DESC spec.homepage = "http://EXAMPLE/FlutterFramewok" spec.license = { :type => 'MIT', :file => 'LICENSE' } spec.platform = :ios, "8.0" spec.source = { :git => "你自己的遠端倉庫地址"} spec.requires_arc = true spec.vendored_frameworks = '*.xcframework' end

`` &emsp;&emsp;將方式三中生成的產物中的Release下的所有.xcframework檔案同步到你的遠端倉庫FlutterFramewok中,之後在iOS工程目錄下引入FlutterModuleSDK.podspecFlutter.podspec,我是在根目錄下建立了一個單獨的資料夾FlutterSpecs`進行管理

some/path/MyApp/ └──FlutterSpecs/ └──Flutter.podspec └──FlutterModuleSDK.podspec └── Podfile   在引入了spec檔案後,可以在podFile中進行遠端依賴了,如下:

pod 'FlutterModuleSDK', :podspec => './FlutterSpecs/FlutterModuleSDK.podspec' pod 'Flutter', :podspec => './FlutterSpecs/Flutter.podspec'   至此,第一個問題就解決了,iOS工程不需要本地依賴Framework了,所有的開發人員可以統一依賴遠端倉庫的Module產物以及Flutter環境,只是在遠端的產物更新中稍顯麻煩,不過後續也可以通過指令碼進行遠端倉庫的更新操作。
  那麼對於第二個問題,想要在Debug環境下進行原始碼熱更新除錯,該怎麼實現呢?其實我們可以使用方式1中的pod整合來進行debug環境下的熱更新除錯,只是需要一個開關來控制下即可。在podFile中使用enable_flutter來手動控制Flutter Module的整合方式,當在開發業務時,需要原始碼的熱更新功能,此時可以設定enable_fluttertrue,當需要打包時可以設定enable_flutterfalse

```

platform :ios, '12.0'

支援原始碼除錯開關

$enable_flutter = false

if $enable_flutter

flutter_application_path = 'Flutter Module在你電腦上的絕對路徑(這裡的每個開發人員的路徑會不一樣,不要求統一,只要路徑正確就可以)'

load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')

end

target 'MyApp' do   #新增原始碼除錯開關   if $enable_flutter

install_all_flutter_pods(flutter_application_path)

else

pod 'FlutterModuleSDK', :podspec => './FlutterSpecs/FlutterModuleSDK.podspec'

pod 'Flutter', :podspec => './FlutterSpecs/Flutter.podspec'

end

end

``` 開關開啟時,可以使用VSCode開啟Flutter Module模組,使用Attach to Flutter on Device來進行斷點、熱更新等相關除錯了。 image.png

參考資料: - #Flutter混合開發-iOS - #在iOS專案中依賴Flutter Module