在上一篇# 在iOS專案中依賴Flutter Module-②遠端依賴Git資源實現了將Flutter編譯產物釋出到遠端Git倉庫以及iOS端遠端依賴Flutter編譯產物的方案。但是這個方案有一個很大的問題,就是Flutter.xcframework
檔案太大,新版Flutter編譯出來接近480M,如果隨其它產物一起打上版本tag,每次釋出到Git、從Git上拉取新版本都將耗費不少時間。由於我們並不需要改動Flutter Engine
,所以每次編譯匯出的Flutter.xcframework
都不會變,除非Flutter版本更新了。而App.xcframework
和其它第三方外掛庫跟我們編寫的Dart程式碼是關聯的,每次編譯都可能會變更。所以正常情況下,每次釋出新版本產物,只需要釋出除Flutter.xcframework
以外的產物即可。
回顧# 在iOS專案中依賴Flutter Module-①本地依賴 - 章節3,可以選擇編譯匯出Flutter.podspec
,Flutter.podspec
依賴了遠端伺服器上的Flutter.xcframework
壓縮檔案,並且支援CDN加速,壓縮後不到原檔案的一半大小,首次下載下來也比拉取Git快。Flutter.podspec
的版本號對應本機上的Flutter版本號,基本不會變化,CocoaPods根據版本號快取資源,就不會反覆下載更新。相比將Flutter.xcframework
放到Git上,通過本地的Flutter.podspec
中轉依賴Flutter.xcframework.zip
,不僅減少Git伺服器的儲存壓力,還能減少不必要的時間損耗,能明顯縮短整個流程的時間。
圍繞本地podspec中轉依賴遠端Flutter,編譯產物,我嘗試了幾種方案,最終我選擇了本地podspec中轉依賴檔案伺服器上的Flutter.xcframework.zip
+ 本地podspec中轉依賴Git上的其它.xcframework
,充分發揮遠端zip檔案的下載優勢和Git版本管理的優勢。
也可以自行搭建檔案伺服器,將其它的xcframework壓縮成zip檔案上傳到檔案伺服器,像Flutter.podspec一樣通過本地podspec中轉依賴zip檔案。但是不好做版本控制和版本回滾,檔案伺服器上面也會不斷累計舊版本的編譯產物,對於APP端開發者而言搭檔案伺服器也有點學習成本,整體而言我覺得沒`遠端zip & git混合依賴`的方案好用,後面就不做介紹了,如果感興趣,就進傳送門,可以找我要Node.js搭檔案伺服器的程式碼,網上找也可以。
複製程式碼
如果想看更多的試驗方案,請進傳送門?。
準備階段
為了方便測試程式碼,我把ios_module
/flutter_module
/andriod_module
放在了一個工作區目錄下。ios_module
就是iOS專案所在目錄,整體目錄結構如下:
some/path/
├── andriod_module
│ ├── ...
├── flutter_module
│ ├── ...
├──ios_module
│ ├── ...
複製程式碼
先建立一個Flutter Module,隨便加點flutter程式碼和第三方元件(比如flutter_boost);
cd some/path/
flutter create --template module flutter_module
複製程式碼
建立一個臨時目錄flutter_build/Frameworks/
,用於存放編譯匯出的產物,用完即刪,至此形成的目錄結構如下;
some/path/
├── andriod_module
│ ├── ...
├── flutter_build
│ ├── Frameworks
├── flutter_module
│ ├── README.md
│ ├── build
│ ├── flutter_module.iml
│ ├── flutter_module_android.iml
│ ├── lib
│ ├── pubspec.lock
│ ├── pubspec.yaml
│ └── test
├──ios_module
├── FlutterBoostPro
├── FlutterBoostPro.xcodeproj
├── FlutterBoostPro.xcworkspace
├── Podfile
├── Podfile.lock
└── Pods
複製程式碼
建立Git倉庫FlutterModuleSDK.git
,用來存放除Flutter.xcframework
以外的編譯產物,建好git之後克隆到本機(可以是工作區some/path/下)。
然後建立Git倉庫FlutterModuleSDKPodspec.git
,建好git之後克隆到本機(可以是工作區some/path/下),用來存放Flutter.podspec
和FlutterModuleSDK.podspec
。Flutter.podspec
是編譯匯出的檔案,FlutterModuleSDK.podspec
需要我們自行建立,並指定依賴前面建立的FlutterModuleSDK.git
,檔案內容如下:
Pod::Spec.new do |s|
s.name = 'FlutterModuleSDK'
s.version = '1.0.1'
s.summary = 'Flutter Module SDK'
s.source = { :git => 'https://a.gitlab.cn/flutter/FlutterModuleSDK.git', :tag => "#{s.version}" }
s.platform = :ios, '8.0'
s.requires_arc = true
s.vendored_frameworks = '*.xcframework'
end
複製程式碼
最後形成的目錄結構如下
井號 # 代表目前不存在,編譯後才會有,先佔個位而已
some/path/
├── andriod_module
│ ├── ...
├── flutter_build
│ ├── Frameworks
│ │ ├── # Debug
│ │ ├── # Profile
│ │ ├── # Release
├── flutter_module
│ ├── README.md
│ ├── build
│ ├── flutter_module.iml
│ ├── flutter_module_android.iml
│ ├── lib
│ ├── pubspec.lock
│ ├── pubspec.yaml
│ └── test
├──ios_module
│ ├── FlutterBoostPro
│ ├── FlutterBoostPro.xcodeproj
│ ├── FlutterBoostPro.xcworkspace
│ ├── Podfile
│ ├── Podfile.lock
│ └── Pods
├──FlutterModuleSDK
│ ├── # App.xcframework、FlutterPluginRegistrant.xcframework和其它.xcframework
├──FlutterModuleSDKPodspec
│ ├── FlutterModuleSDK.podspec
│ ├── # Flutter.podspec
複製程式碼
編譯
先編譯flutter_module
,指定匯出目錄是flutter_build/Frameworks/
,output
的引數是相對路徑。編譯失敗的話要麼是Dart程式碼問題,要麼是.ios/Runner.xcworkspace
的開發證書沒配置好。
cd flutter_module/
flutter build ios-framework --cocoapods --xcframework --no-universal --output=../flutter_build/Frameworks/
複製程式碼
編譯成功後,flutter_build/Frameworks/
目錄下面會新增以下資料夾。
├── flutter_build
│ ├── Frameworks
│ │ ├── Debug
│ │ ├── Profile
│ │ ├── Release
複製程式碼
處理產物
將App.xcframework、FlutterPluginRegistrant.xcframework和其它.xcframework
移到FlutterModuleSDK.git
本地目錄下;
├──FlutterModuleSDK
│ ├── App.xcframework
│ ├── FlutterPluginRegistrant.xcframework
│ ├── 其它.xcframework,比如flutter_boost.xcframework
複製程式碼
將Flutter.podspec
移到FlutterModuleSDKPodspec.git
本地目錄下(並不需要修改這個檔案,直接用);
├──FlutterModuleSDKPodspec
│ ├── FlutterModuleSDK.podspec
│ ├── Flutter.podspec
複製程式碼
修改FlutterModuleSDK.podspec
中的版本號;
釋出產物
提交FlutterModuleSDK.git
中的更新,打上版本tag,push到遠端倉庫;
提交FlutterModuleSDKPodspec.git
中的更新,push到遠端倉庫;
清空刪除flutter_build/Frameworks/
;
釋出版本更新通知(釘釘、微信、郵件);
iOS端拉取更新
同步剛剛釋出的*.podspec
到iOS開發機上,第一次需要克隆FlutterModuleSDKPodspec.git
到本地,後面只需要拉取更新FlutterModuleSDKPodspec.git
即可;
在Podfile中新增本地依賴,:podspec
指定FlutterModuleSDKPodspec.git
中對應的.podspec
檔案,並使用相對路徑;
pod 'Flutter', :podspec => './../FlutterModuleSDKPodspec/Flutter.podspec'
pod 'FlutterModuleSDK', :podspec => './../FlutterModuleSDKPodspec/FlutterModuleSDK.podspec'
複製程式碼
pod update or install
,執行程式碼測試;
儘量在.gitignore檔案中忽略掉編譯期間匯入的.xcframework,不然一併提交到Git會很慢,還明顯增加Git倉庫的檔案大小。
複製程式碼
由於Flutter.podspec
的版本號基本不會變,只有第一次下載zip檔案會耗費點時間,CocoaPods快取以後執行更新都會非常快。而FlutterModuleSDK.git
裡面的檔案並不大,在內網Git的話每次更新都會比較快。所以相比將Flutter.xcframework
放到Git上,通過本地的Flutter.podspec
中轉依賴Flutter.xcframework.zip
,不僅減少Git伺服器的儲存壓力,還能減少不必要的時間損耗,能明顯縮短整個流程的時間。 另外這種方案也不用iOS同事安裝Flutter開發環境,依賴Flutter側程式碼就跟依賴第三方庫一樣,由於*.xcframework
已經編譯過了,編譯iOS專案時不需要再編譯Flutter程式碼,相比本地依賴就要快得多。
但這個方案也有個短板,如果iOS團隊人多的話,要保證所有人在Podfile
中填的:podspec
相對路徑都是一樣的,也就是要求在每臺開發機上,本地FlutterModuleSDKPodspec.git
相對本地ios_module.git
的路徑是一致的。如果跟其他人填的相對路徑不一致,提交到Git就會發生衝突。當然也可以禁止大家在克隆git時重新命名本地倉庫名,並且把FlutterModuleSDKPodspec.git
、ios_module.git
在同一個目錄下,只是時間一久,難免會遺忘這個規則,另外還得跟新人強調這個規則。
改良
前面說了要保持相對路徑一致,而FlutterModuleSDKPodspec.git
和ios_module.git
是純人為建立並維護的關聯關係,時間久了容易遺忘這個共識,所以需要更強烈的繫結關係來解決這個隱患。我找到的方案是藉助git submodule
將FlutterModuleSDKPodspec.git
"內嵌"到ios_module.git
中,成為子模組,還能讓FlutterModuleSDKPodspec.git
保持獨立的Git倉庫。
關於
git submodule
的介紹可以看某大佬整理的《Git中submodule的使用》。
所以只需要修改iOS端拉取更新
流程,在ios_module.git
中增加git submodule
,解決相對路徑難以保持一致的問題,前面的編譯、釋出流程都不用改,FlutterModuleSDKPodspec.git
還是獨立的倉庫。
iOS端拉取更新-改良版
首先在ios_module.git
中新增子模組FlutterModuleSDKPodspec.git
;
cd some/path/ios_module
git submodule add 'https://a.gitlab.cn/flutter/FlutterModuleSDKPodspec.git'
複製程式碼
新增子模組後,主要會遇到兩種情況,首先是新同事首次克隆ios_module.git
,然後是後續的子模組更新。
- 如果是新同事首次克隆
ios_module.git
,可能會遇到2種情況。- 1.常規的克隆指令,可能指定分支,但沒有拉取
submodule
子模組,就需要額外執行指令去遞迴拉取更新子模組。
git clone -b a_branch https://a.gitlab.cn/ios/ios_module.git git submodule update --init --recursive 複製程式碼
- 2.克隆的同時指定遞迴拉取更新子模組,則需要在指令中加上
--recurse-submodules
git clone -b a_branch https://a.gitlab.cn/ios/ios_module.git --recurse-submodules 複製程式碼
- 1.常規的克隆指令,可能指定分支,但沒有拉取
FlutterModuleSDKPodspec.git
釋出更新後,需要在ios_module.git
中更新本地子模組,加上foreach
可以幫助我們遍歷所有的子模組。
git submodule foreach 'git pull origin master'
複製程式碼
如果更新了子模組(包括新增子模組),都會在ios_module.git
產生modify
,所以還需要額外提交更新到ios_module.git
。
git status
# 下面2步可以在SourceTree之類的客戶端操作,是可以看到submodule的
git add -A && git commit -m "新增或更新子模組 FlutterModuleSDKPodspec.git"
git push origin --tags && git push origin master
複製程式碼
然後在Podfile中新增本地依賴,:podspec
指定FlutterModuleSDKPodspec.git
中對應的.podspec
檔案,並使用子模組的相對路徑;
pod 'Flutter', :podspec => './FlutterModuleSDKPodspec/Flutter.podspec'
pod 'FlutterModuleSDK', :podspec => './FlutterModuleSDKPodspec/FlutterModuleSDK.podspec'
複製程式碼
pod update or install
,執行程式碼測試;
儘量在.gitignore檔案中忽略掉編譯期間匯入的.xcframework,不然一併提交到Git會很慢,還明顯增加Git倉庫的檔案大小。
複製程式碼
綜上所述,改良版就是把更新依賴的FlutterModuleSDKPodspec.git
改成了更新子模組,而FlutterModuleSDKPodspec.git
以子模組嵌入ios_module.git
後路徑是固定的,這樣就能保住每臺電腦上這2個git的相對路徑是始終一致的,不用擔心人為因素導致路徑不一致的問題。
至此就實現了在iOS專案中遠端依賴Flutter Module編譯產物,特別感謝閒魚團隊分享的《Flutter in action》,遠端依賴的思路也是從中獲取的,只是不知道閒魚團隊具體是怎麼實現的,所以花了不少時間在找合適的方案,試了幾種方案,有可行的也有行不通的方案,最後選擇了Git子模組
+ 本地podspec中轉遠端zip & git
的方案,具體的特點就是下面這些。總體而言,這個方案充分發揮了遠端zip檔案的下載優勢和Git版本管理的優勢,適合大小團隊使用,技術難度低,關鍵能為iOS端節省很多編譯時間,這一點特別實用。
- 將*.xcframework釋出到FlutterModuleSDK.git中
- 將*.podspec釋出FlutterModuleSDKPodspec.git中
- 將FlutterModuleSDKPodspec.git 以子模組的形式內嵌到 ios_module.git中
- 通過子模組的Flutter.podspec中轉依賴遠端伺服器上的zip檔案
- 通過子模組的FlutterModuleSDK.podspec中轉依賴遠端Git上的*.xcframework