Flutter - 將 Flutter 整合到現有專案(iOS - Framework篇)

Flutter筆記發表於2020-06-10

本篇文章大幅參考了 caijinglong 大佬的總結文章: 把flutter作為framework新增到已存在的iOS中

用 Flutter 來開發,從來都不可能是新開的一個純 Flutter 專案,很大一部分都是 老專案接入 Flutter 來混編。

Flutter 官網 - Adding to an iOS app 這裡,官方也給出了一些將 Flutter 整合進入現有 iOS 專案的方法。但是,這些都多多少少的不符合我們的需求。

1. 從 Flutter Module 說起

想要把 Flutter 整合進現有 iOS 專案,我們就必須使用 Flutter Module

那就先用命令建立一個 Flutter Module:flutter create --template module flutter_test_module

Flutter - 將 Flutter 整合到現有專案(iOS - Framework篇)

Flutter APP 和 Flutter Module 的不同之處在於 pubspec.yaml 最後一段:

# This section identifies your Flutter project as a module meant for
# embedding in a native host app.  These identifiers should _not_ ordinarily
# be changed after generation - they are used to ensure that the tooling can
# maintain consistency when adding or modifying assets and plugins.
# They also do not have any bearing on your native host application's
# identifiers, which may be completely independent or the same as these.
module:
androidX: true
androidPackage: com.example.flutter_test_module
iosBundleIdentifier: com.example.flutterTestModule
複製程式碼

這一段程式碼,把該 Flutter 專案標註為一個 module,用於嵌入到原生 app 裡。

這裡面設定了是否使用 androidx,Android 和 iOS 的 APP id。

2. iOS原生專案所需的檔案

先說一下,iOS 原生專案引入 Flutter Module 需要如下 Framework:

  1. Flutter.framework
  2. App.framework
  3. FlutterPluginRegistrant.framework (如果有用到原生的外掛 - 非純 dart 編寫)
  4. Pods_Runner.framework(如果有用到原生的外掛 - 非純 dart 編寫)
  5. *.framework(外掛的 framework)

下面繼續整合。

Flutter Module 建立完成後,先來給 iOS 打個包,命令如下:flutter build ios --release --no-codesign

然後看一下打包出來的東西,路徑為 build->ios->Release-iphoneos

Flutter - 將 Flutter 整合到現有專案(iOS - Framework篇)

如果有第三方庫的話,這裡面應該是有上面說的 3、4、5 的 framework,但是我們剛建立專案,什麼都沒有加,所以是沒有任何 framework的。

然後去 .ios/Flutter 裡找 1、2:

Flutter - 將 Flutter 整合到現有專案(iOS - Framework篇)

但是我們寫程式不可能什麼外掛都不用,所以加上一個shared_preferences,再來打包看一下 build 資料夾:

Flutter - 將 Flutter 整合到現有專案(iOS - Framework篇)

可以看到確實出現了我們上面說的 3、4、5 framework,這樣我們所需的 framework 全部集齊。

3. 使用 cocoapods + git 來管理

因為 caijinglong 大佬 文章內說:

因為找遍了 podfile 的相關文件, 沒有找到可以直接引用 framework 的方式

所以需要一個 pod 庫作為"中轉”

所以我們就要 跟著做!

Flutter - 將 Flutter 整合到現有專案(iOS - Framework篇)

使用命令 pod lib create flutter-lib 來建立一個名為 flutter-lib的私有庫。

建立完成之後,開啟 flutter-lib.podspec ,在 end 前面加入一行:

Flutter - 將 Flutter 整合到現有專案(iOS - Framework篇)

接著我們在該資料夾內建立一個名為 ios_frameworks 的資料夾,把我們剛才的那麼多 framework 全都貼上過來。

Flutter - 將 Flutter 整合到現有專案(iOS - Framework篇)

這個時候我們的iOS原生專案就可以引入本地這個庫了:

platform :ios, '8.0'
use_frameworks!

target 'xxx.xxx.xxx' do
   pod 'flutter-lib', :path => 'somepath/flutter-lib'
end
複製程式碼

當然,我們不可能都用本地路徑來引入,所以我們把這整個 flutter-lib資料夾傳到 git 上,然後這樣引用:

platform :ios, '8.0'
use_frameworks!

target 'xxx.xxx.xxx' do
   pod 'flutter-lib', :git => 'http://xxxx.git'
end
複製程式碼

這樣我們就可以從 git 上來遠端引用該私有庫了。

如果執行有錯誤的話,可以去 caijinglong 大佬的部落格檢視解決辦法。

4. 編寫指令碼自動處理

上面都是手動來處理的,包括打包->移動檔案->上傳git等。

下面就寫一個指令碼來處理一下(基於 caijinglong 大佬):

ios_project_name='xxx'	# 專案名稱
ios_out_path='xxx/ios_frameworks'	# 檔案輸出路徑
flutter_git_path='http://xxx/xxx/xxx.git'	# git 專案路徑

function customEcho(){
  echo "\033[1;32m$1\033[0m"
}
customEcho '\n1. 執行 flutter clean'
flutter clean || exit -1

customEcho '\n2. 清空build資料夾'
rm -rf $ios_project_name
rm -rf build
echo '清空完成'

customEcho '\n3. 生成 iOS frameworks'
flutter build ios --release --no-codesign || exit -1 

customEcho "\n4. 從 git 上克隆 frameworks 專案"
git clone $flutter_git_path  || exit -1 

customEcho "\n5. 輸出檔案到 $ios_out_path"
rm -rf $ios_out_path
mkdir $ios_out_path


cp -r build/ios/Release-iphoneos/*/*.framework $ios_out_path
cp -r .ios/Flutter/App.framework $ios_out_path
# cp -r .ios/Flutter/engine/Flutter.framework $out
echo '輸出完成'

customEcho "\n6. 提交檔案到 git"
cd $ios_project_name
git add .
git commit -m 'update lib'
git push -u origin master


customEcho "\n7. 刪除該資料夾"
cd ..
rm -rf $ios_project_name

customEcho "\nAll Done."
複製程式碼

解釋就不用解釋了,上面的輸出都有寫。

這裡有一點,就是 Flutter.framework 超級大,有四五百兆,我們把它單獨放在了一個 pod 裡,而剩下的一些每次新增外掛或變更程式碼都會跟著變動,所以他們是一個單獨的 pod。

也就是說,該 Flutter Module 一共有三個 git 倉庫:

  1. Flutter Module 專案的倉庫(編寫程式碼等)
  2. Flutter Module 打包出來的 frameworks(不包含 Flutter.framework)
  3. Flutter.framework 倉庫

這樣的好處就是在我們編寫完程式碼,執行 sh 檔案的時候,不用去下載一個四五百兆的 flutter 引擎,指令碼速度提升很快,並且其他的 iOS 專案也可以引用。

接著改一下 flutter-lib.podspec 檔案,

Flutter - 將 Flutter 整合到現有專案(iOS - Framework篇)

把這一行改成如下:

p = Dir::open("ios_frameworks")
arr = Array.new
p.each do |f|
  if f == '.' || f == '..'
  else
    arr.push('ios_frameworks/'+f)
  end
end
s.ios.vendored_frameworks = arr
複製程式碼

這樣就完成了引入所有的 frameworks。

5. 總結

到這裡 Flutter Module 就完全引入到了現有的 iOS 工程中,關於如何執行程式碼,可以去官方文件 - Adding a Flutter screen to an iOS app 中查詢。

這樣整合的方案,感覺是目前最方便的了。(如有更佳方案,煩請告知)

Flutter 端寫完程式碼直接執行 ./build_module.sh 就可以了。

iOS 端直接 pod install,超級簡單。

Flutter - 將 Flutter 整合到現有專案(iOS - Framework篇)

如有缺陷,希望大家提出,共同學習!?

Flutter - 將 Flutter 整合到現有專案(iOS - Framework篇)

相關文章