從零搭建 iOS Native Flutter 混合工程
本文來實現一個靈活、無侵入、低耦合的 iOS Flutter 混合工程。 我們希望混合開發至少得保證如下特點:
- 對Native工程無侵入
- 對Native工程零耦合
- 不影響Native工程的開發流程與打包流程
- 易本地除錯
一、Flutter 提供的 Native Flutter 混合工程方式
Flutter 官方提供的混合工程搭建方法: Add Flutter to existing apps 文章中介紹瞭如何在現有 App 里加入Flutter,下面進行逐步介紹一下
1. 建立 Flutter 工程
請自行 百度/Google Flutter 安裝教程,安裝Flutter。然後到任意目錄下執行flutter create -t module my_flutter
2. 通過 Cocoapods 將 Flutter 引入 現有 Native 工程
在Podfile新增以下下程式碼
flutter_application_path = "xxx/xxx/my_flutter"
eval(File.read(File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')), binding)
複製程式碼
然後執行pod install
3. 修改 Native 工程
開啟Xcode工程,選擇要加入 Flutter App 的 target,選擇 Build Phases
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" build
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" embed
複製程式碼
二、分析 Native Flutter 混合工程
按照上面三個步驟進行逐一分析每一步的問題,並提供優化方案。
1. 建立 Flutter 工程
這一步首先在自己電腦上安裝 Flutter,然後使用 flutter create
。這裡就存在問題,在團隊開發中每個人安裝的 Flutter 版本可能並不同,這樣會出現Dart層Api相容性或Flutter虛擬機器不一致等問題。 在團隊協作中一定要保證 Flutter 工程依賴相同的 Flutter SDK,所有需要一個工具在執行 flutter
flutterw
代替 flutter
指令,工具會自動將 Flutter SDK 放在當前 Flutter 工程目錄下,並執行當前工程中的 flutter
命令,這樣就不再依賴本地電腦安裝的 Flutter SDK。
flutter_wrapper使用:
flutter create
建立 Flutter 工程,這裡使用的是本地的 Flutter SDK- 進入 Flutter 工程目錄安裝 'flutter_wrapper',執行
sh -c "$(curl -fsSL https://raw.githubusercontent.com/passsy/flutter_wrapper/master/install.sh)"
- 此後在當前 Flutter 工程需要使用
flutter
命令的地方都使用./flutterw
來代替
2. 通過 Cocoapods 將 Flutter 引入 現有 Native 工程
這一步在 Podfile 裡添加里一個 'podhelper.rb' ruby 指令碼,指令碼會在 pod install/update
時執行,指令碼主要做4點事情:
- 解析 'Generated.xcconfig' 檔案,獲取 Flutter 工程配置資訊,檔案在'my_flutter/.ios/Flutter/'目錄下,檔案中包含了 Flutter SDK 路徑、Flutter 工程路徑、Flutter 工程入口、編譯目錄等。
- 將 Flutter SDK 中的
Flutter.framework
通過 pod 新增到 Native 工程。 - 將 Flutter 工程依賴的外掛通過 pod 新增到 Native 工程,因為有些外掛有 Native 部分程式碼。
- 使用
post_install
這個 pod hooks 來關閉 Native 工程的 bitcode,並將 'Generated.xcconfig' 檔案加入 Native 工程。
這一步存在問題是,'podhelper.rb'指令碼是通過一個本地 Flutter 工程路徑'flutter_application_path'來讀取,在團隊協作中我們很難保證每個人的本地 Flutter 工程路徑都一樣,在同步程式碼時大家可能都要頻繁修改'flutter_application_path'變數,這樣很不友好。
解決這個問題的思路就是將 Flutter 工程放在當前 Native 工程的目錄下,我們可以再加入一個 ruby 指令碼,在每次執行 pod install/update
時,將 Flutter 工程從 git 上拉取一份放在當前目錄下,這樣 Flutter 工程的路徑就統一了。大致程式碼如下:
flutter_application_path = __dir__ + "/.flutter/app"
`git clone git://xxxx/my_flutter.git #{flutter_application_path}`
# 如果想要除錯本地的 Flutter 工程,就把下面這行註釋放開
# flutter_application_path = "xxx/xxx/my_flutter"
eval(File.read(File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')), binding)
複製程式碼
上述程式碼只是臨時程式碼,為了演示將 Flutter 工程放在當前目錄下這個思路,後面會有完整的實現程式碼。
3. 修改 Native 工程
這裡執行了一個'xcode_backend.sh'指令碼的兩個命令build、embed,兩個命令分別的作業是:
- build: 根據當前 Xcode 工程的 'configuration' 和其他編譯配置編譯 Flutter 工程,'configuration'通常為'debug'或者'release'
- embed: 將 build 出來的 framework、資源包放入 Xcode 編譯目錄,並簽名 framework
這裡存在的問題是:Flutter 工程依賴 Native工程來執行編譯,並影響Native工程的開發流程與打包流程。
通常 'configuration' 裡不止有 'debug' 或者 'release',可能會有自定義的名稱,如果我們使用自定義的 'configuration' 編譯,那麼 xcode_backend.sh build
就會執行失敗。因為Flutter 編譯模式是通過 'configuration' 獲取的,Flutter 支援 Debug、Profil、Release 三種編譯模式,而我們自定義的名稱不在這三種之中,Flutter 就不知道該怎麼編譯。
每次 Native 編譯時 Flutter 就需要編譯,其實是產生了相互依賴:Flutter 編譯依賴 Native 編譯環境,Native 依賴 Flutter 編譯通過。
我們希望做到:Native 依賴 Flutter 編譯出來的產物,並且保留依賴 Flutter 原始碼進行除錯的能力。
實現這個目標我們需要兩部分:
- 第一部分:Flutter 工程裡建立一個打包指令碼,可以一鍵產生 Flutter 工程產物;
- 第二部分:在 Native 工程獲取 FLutter 工程的編譯產物,並通過 pod 新增到工程;並且保留依賴 Flutter 工程原始碼的功能。
三、實現 Native Flutter 混合工程
下面我們來實現上文提到的兩個部分
第一部分實現“打包指令碼”
這一部分我們需要實現指令碼自動打包 Flutter 工程,拆分一下這個指令碼流程,大致分為一下幾個步驟:
- 檢查 Flutter 環境,拉取 Flutter plugin
- 編譯 Flutter 工程產物
- 複製 Flutter 外掛中的 Native 程式碼
- 將產物同步到產物釋出的伺服器
下面來一步一步的分析並實現每一步:
(1) 檢查 Flutter 環境,拉取 Flutter plugin
這一步做的工作是檢查是否安裝了 'flutter_wrapper',如果安裝則進行安裝,然後執行 ./flutterw packages get
,Shell程式碼如下:
flutter_get_packages() {
echo "================================="
echo "Start get flutter app plugin"
local flutter_wrapper="./flutterw"
if [ -e $flutter_wrapper ]; then
echo 'flutterw installed' >/dev/null
else
bash -c "$(curl -fsSL https://raw.githubusercontent.com/passsy/flutter_wrapper/master/install.sh)"
if [[ $? -ne 0 ]]; then
# 上一步指令碼執行失敗
echo "Failed to installed flutter_wrapper."
exit -1
fi
fi
${flutter_wrapper} packages get --verbose
if [[ $? -ne 0 ]]; then
# 上一步指令碼執行失敗
echo "Failed to install flutter plugins."
exit -1
fi
echo "Finish get flutter app plugin"
}
複製程式碼
(2) 編譯 Flutter 工程產物
這一步是指令碼的核心,主要邏輯和上文中'xcode_backend.sh build'類似,大致程式碼如下:
# 預設debug編譯模式
BUILD_MODE="debug"
# 編譯的cpu平臺
ARCHS_ARM="arm64,armv7"
# Flutter SDK 路徑
FLUTTER_ROOT=".flutter"
# 編譯目錄
BUILD_PATH=".build_ios/${BUILD_MODE}"
# 存放產物的目錄
PRODUCT_PATH="${BUILD_PATH}/product"
# 編譯出的flutter framework 存放的目錄
PRODUCT_APP_PATH="${PRODUCT_PATH}/Flutter"
build_flutter_app() {
echo "================================="
echo "Start Build flutter app"
# 建立目錄
mkdir -p -- "${PRODUCT_APP_PATH}"
# flutter 工程入口 dart檔案
local target_path="lib/main.dart"
# flutter sdk 目錄解析
local artifact_variant="unknown"
case "$BUILD_MODE" in
release*)
artifact_variant="ios-release"
;;
profile*)
artifact_variant="ios-profile"
;;
debug*)
artifact_variant="ios"
;;
*)
echo "ERROR: Unknown FLUTTER_BUILD_MODE: ${BUILD_MODE}."
exit -1
;;
esac
if [[ "${BUILD_MODE}" != "debug" ]]; then
# 非debug編譯模式
# build fLutter app,output App.framework
${FLUTTER_ROOT}/bin/flutter --suppress-analytics \
--verbose \
build aot \
--output-dir="${BUILD_PATH}" \
--target-platform=ios \
--target="${target_path}" \
--${BUILD_MODE} \
--ios-arch="${ARCHS_ARM}"
if [[ $? -ne 0 ]]; then
echo "Failed to build flutter app"
exit -1
fi
else
# debug編譯模式直接使用編譯好的App.framework,
# 因為在 debug 模式下 flutter 程式碼並沒有編譯成二進位制機器碼,而是在後續build bundle時被打包進資源包,
# 在'xcode_backend.sh'腳本里,這一步這裡只是編譯成一個App.framework空殼。
# 提前編譯好的原因是'xcode_backend.sh'指令碼執行和Xcode一起執行,所以執行時能獲取到Xcode設定的編譯配置,能正確的編譯出'App.framework',
# 而本指令碼不依賴Xcode執行,即便把'xcode_backend.sh'對應的程式碼拷貝出來也不能正確的編譯出'App.framework',除非我們能正確的配置編譯環境。
#
# 而我又不想那麼麻煩,選擇另闢蹊徑:
# 隨便建立了一個 Flutter 工程,
# 在debug模式下,先在模擬器編譯執行一下,得到x86_64的App.framework,
# 再到真機執行一下,得到arm64/armv7的App.framework,
# 最後使用lipo命令將兩個App.framework合併,得到x86_64/arm64/armv7的App.framework,
# 這樣最後得到的App.framework在模擬器和真機都可以用
# 因為debug模式下App.framework就是佔位的空殼,所以其他flutter工程一樣用
local app_framework_debug="iOSApp/Debug/App.framework"
cp -r -- "${app_framework_debug}" "${BUILD_PATH}"
fi
# copy info.plist to App.framework
app_plist_path=".ios/Flutter/AppFrameworkInfo.plist"
cp -- "${app_plist_path}" "${BUILD_PATH}/App.framework/Info.plist"
local framework_path="${FLUTTER_ROOT}/bin/cache/artifacts/engine/${artifact_variant}"
local flutter_framework="${framework_path}/Flutter.framework"
local flutter_podspec="${framework_path}/Flutter.podspec"
# copy framework to PRODUCT_APP_PATH
cp -r -- "${BUILD_PATH}/App.framework" "${PRODUCT_APP_PATH}"
cp -r -- "${flutter_framework}" "${PRODUCT_APP_PATH}"
cp -r -- "${flutter_podspec}" "${PRODUCT_APP_PATH}"
local precompilation_flag=""
if [[ "$BUILD_MODE" != "debug" ]]; then
precompilation_flag="--precompiled"
fi
# build bundle
${FLUTTER_ROOT}/bin/flutter --suppress-analytics \
--verbose \
build bundle \
--target-platform=ios \
--target="${target_path}" \
--${BUILD_MODE} \
--depfile="${BUILD_PATH}/snapshot_blob.bin.d" \
--asset-dir="${BUILD_PATH}/flutter_assets" \
${precompilation_flag}
if [[ $? -ne 0 ]]; then
echo "Failed to build flutter assets"
exit -1
fi
# copy Assets
local product_app_assets_path="${PRODUCT_APP_PATH}/Assets"
mkdir -p -- "${product_app_assets_path}"
cp -rf -- "${BUILD_PATH}/flutter_assets" "${PRODUCT_APP_PATH}/Assets"
# setting podspec
# replace:
# 'Flutter.framework'
# to:
# 'Flutter.framework', 'App.framework'
# s.resource='Assets/*'
sed -i '' -e $'s/\'Flutter.framework\'/\'Flutter.framework\', \'App.framework\'\\\n s.resource=\'Assets\/*\'/g' ${PRODUCT_APP_PATH}/Flutter.podspec
echo "Finish build flutter app"
}
複製程式碼
(3) 複製 Flutter 外掛中的 Native 程式碼
Flutter 使用的各種外掛可能會包含 Native 程式碼,並且這些程式碼已經提供了podspec,可以使用 pod 直接引入。我們要做的就是把外掛的 Native 程式碼拷貝到產物目錄。 Flutter 建立了一個給 Native 註冊外掛的 pod 庫 'FlutterPluginRegistrant',這個也需要拷貝出來, 在 Flutter 工程根目錄下有一個 .flutter-plugins 檔案,檔案內部記錄了外掛的名字和外掛的路徑,格式為 pugin_name=/xx/xx/xx
,解析這個檔案就可以得到外掛資訊,程式碼如下:
flutter_copy_packages() {
echo "================================="
echo "Start copy flutter app plugin"
local flutter_plugin_registrant="FlutterPluginRegistrant"
local flutter_plugin_registrant_path=".ios/Flutter/${flutter_plugin_registrant}"
echo "copy 'flutter_plugin_registrant' from '${flutter_plugin_registrant_path}' to '${PRODUCT_PATH}/${flutter_plugin_registrant}'"
cp -rf -- "${flutter_plugin_registrant_path}" "${PRODUCT_PATH}/${flutter_plugin_registrant}"
local flutter_plugin=".flutter-plugins"
if [ -e $flutter_plugin ]; then
OLD_IFS="$IFS"
IFS="="
cat ${flutter_plugin} | while read plugin; do
local plugin_info=($plugin)
local plugin_name=${plugin_info[0]}
local plugin_path=${plugin_info[1]}
if [ -e ${plugin_path} ]; then
local plugin_path_ios="${plugin_path}ios"
if [ -e ${plugin_path_ios} ]; then
if [ -s ${plugin_path_ios} ]; then
echo "copy plugin 'plugin_name' from '${plugin_path_ios}' to '${PRODUCT_PATH}/${plugin_name}'"
cp -rf ${plugin_path_ios} "${PRODUCT_PATH}/${plugin_name}"
fi
fi
fi
done
IFS="$OLD_IFS"
fi
echo "Finish copy flutter app plugin"
}
複製程式碼
(4) 將產物同步到保留產物的伺服器
經過上面的幾個步驟後會生成一個產物目錄,這個目錄下會有幾個二級目錄,每個二級目錄裡都包含一個 podspec 檔案。
也就是說這個產物目錄裡存放的就是 cocoapods 庫,將目錄拷貝到 Native 工程,然後用 pod 'pod_name', :path=>'xx/xxx'
的形式引用就可以了。
有了產物後我們需要一個存放產物的地方, 大家可以去這個地方下載,這一步比較靈活,可以選擇將產物放在git倉庫、http伺服器、ftp伺服器等。我最終選擇將產物壓縮成 zip 上傳到 Maven 上,原因是為了和 Android Flutter 產物放在一個地方,並且 Maven 已成做好的產物版本管理。
Maven上傳程式碼比較簡單,這裡不再贅述,有興趣可以到文末的github倉庫檢視程式碼。
Flutter 工程版本設定是在工程目錄下的 'pubspec.yaml' 檔案,打包指令碼讀取這個檔案來確定產物的版本。
最後這個指令碼使用方式為 ./build_ios.h -m debug
./build_ios.h -m release
,上文中沒有提到的一點是隻有 release 模式編譯的包才會上傳的伺服器,debug 只是編譯到產物目錄。
第二步 Native 依賴 Flutter 產物
這部分我們需要實現獲取指定版本 Flutter 工程 release 產物,並整合到 Native 專案,並保留可以除錯 Flutter 工程的能力。
也是來拆分一下指令碼流程:
- 獲取 Flutter 工程產物
- 獲取 release 產物
- 獲取 debug 產物
- 通過 pod 引入 Flutter 工程產物
(1) 獲取 Flutter 工程產物
上文說到只有 release 產物放在了產物伺服器上,debug 只是編譯到產物目錄。不上傳 debug 的原因是,debug 階段就是開發階段,舉個不太恰當的例子:哪有開發階段就把包上傳 app store 的? 也就代表這 release 的產物和 debug 的產物獲取邏輯不一樣,並且我們的指令碼支援兩種方式的切換,所以在 Podfile 新增如下程式碼:
# 設定要引入的 flutter app 的版本
FLUTTER_APP_VERSION="1.1.1"
# 是否進行除錯 flutter app,
# 為true時FLUTTER_APP_VERSION配置失效,下面的三項配置生效
# 為false時FLUTTER_APP_VERSION配置生效,下面的三項配置失效
FLUTTER_DEBUG_APP=false
# Flutter App git地址,從git拉取的內容放在當前工程目錄下的.flutter/app目錄
# 如果指定了FLUTTER_APP_PATH,則此配置失效
FLUTTER_APP_URL="git:/xxxx.git"
# flutter git 分支,預設為master
# 如果指定了FLUTTER_APP_PATH,則此配置失效
FLUTTER_APP_BRANCH="master"
# flutter本地工程目錄,絕對路徑或者相對路徑,如果有值則git相關的配置無效
FLUTTER_APP_PATH="../my_flutter"
eval(File.read(File.join(__dir__, 'flutterhelper.rb')), binding)
複製程式碼
Podfile 其實就是 Ruby 程式碼,上面幾個由大寫字母組成的變數是全域性變數,最後一句程式碼的作用為讀取'flutterhelper.rb'裡的程式碼並執行,在'flutterhelper.rb'裡可以獲取到上面定義的全域性變數,根據這幾個變數做不同的操作,其中選擇使用 release 還是 debug 的程式碼如下:
if FLUTTER_DEBUG_APP.nil? || FLUTTER_DEBUG_APP == false
# 使用 flutter release 模式
puts "開始安裝 release mode flutter app"
install_release_flutter_app()
else
# 存在debug配置,使用 flutter debug 模式
puts "開始安裝 debug mode flutter app"
install_debug_flutter_app()
end
複製程式碼
install_release_flutter_app
為操作 release 產物的函式,install_debug_flutter_app
為操作 debug 產物的函式。
處理 release 模式主要就是獲取 release 產物,程式碼如下:
# 安裝正式環境環境app
def install_release_flutter_app
if FLUTTER_APP_VERSION.nil?
raise "Error: 請在 Podfile 裡設定要安裝的 Flutter app 版本 ,例如:FLUTTER_APP_VERSION='1.0.0'"
else
puts "當前安裝的 flutter app 版本為 #{FLUTTER_APP_VERSION}"
end
# 存放產物的目錄
flutter_release_path = File.expand_path('.flutter_release')
# 是否已經存在當前版本的產物
has_version_file = true
if !File.exist? flutter_release_path
FileUtils.mkdir_p(flutter_release_path)
has_version_file = false
end
# 存放當前版本產物的目錄
flutter_release_version_path = File.join(flutter_release_path, FLUTTER_APP_VERSION)
if !File.exist? flutter_release_version_path
FileUtils.mkdir_p(flutter_release_version_path)
has_version_file = false
end
# 產物包
flutter_package = "flutter.zip"
flutter_release_zip_file = File.join(flutter_release_version_path, flutter_package)
if !File.exist? flutter_release_zip_file
has_version_file = false
end
# 產物包下載完成標誌
flutter_package_downloaded = File.join(flutter_release_version_path, "download.ok")
if !File.exist? flutter_package_downloaded
has_version_file = false
end
if has_version_file == true
# 解壓
flutter_package_path = unzip_release_flutter_app(flutter_release_version_path, flutter_release_zip_file)
# 開始安裝
install_release_flutter_app_pod(flutter_package_path)
else
# 刪除老檔案
FileUtils.rm_rf(flutter_release_zip_file)
# 刪除標誌物
FileUtils.rm_rf(flutter_package_downloaded)
# 下載
download_release_flutter_app(FLUTTER_APP_VERSION, flutter_release_zip_file, flutter_package_downloaded)
# 解壓
flutter_package_path = unzip_release_flutter_app(flutter_release_version_path, flutter_release_zip_file)
# 開始安裝
install_release_flutter_app_pod(flutter_package_path)
end
end
複製程式碼
unzip_release_flutter_app
為解壓zip格式產物的函式,download_release_flutter_app
為從 Maven 下載產物的函式,這兩個比較簡單,詳細程式碼請看文末 github 倉庫。 install_release_flutter_app_pod
為通過 pod 將產物新增到 Native 的函式,後面會詳細介紹。
處理 debug 模式的操作為,獲取 Flutter 工程原始碼,執行 build_ios.sh -m debug
進行打包,然後得到 debug 產物目錄,詳細程式碼如下:
# 安裝開發環境app
def install_debug_flutter_app
puts "如果是第一次執行開發環境Flutter專案,此過程可能會較慢"
puts "請耐心等️待☕️️️️️☕️☕️\n"
# 預設Flutter App 目錄
flutter_application_path = __dir__ + "/.flutter/app"
flutter_application_url = ""
flutter_application_branch = 'master'
# 指定了FLUTTER_APP_PATH就用原生代碼,複製從git拉取
if FLUTTER_APP_PATH != nil
File.expand_path(FLUTTER_APP_PATH)
if File.exist?(FLUTTER_APP_PATH)
flutter_application_path = FLUTTER_APP_PATH
else
flutter_application_path = File.expand_path(FLUTTER_APP_PATH)
if !File.exist?(flutter_application_path)
raise "Error: #{FLUTTER_APP_PATH} 地址不存在!"
end
end
puts "\nFlutter App路徑: "+flutter_application_path
else
if FLUTTER_APP_URL != nil
flutter_application_url = FLUTTER_APP_URL
if FLUTTER_APP_BRANCH != nil
flutter_application_branch = FLUTTER_APP_BRANCH
end
else
raise "Error: 請在'Podfile'裡增加Flutter App git地址配置,配置格式請檢視'flutterhelper.rb'檔案"
end
puts "\n拉取 Flutter App 程式碼"
puts "Flutter App路徑: "+flutter_application_path
update_flutter_app(flutter_application_path, flutter_application_url, flutter_application_branch)
end
puts "\n編譯 Flutter App"
# PUB_HOSTED_URL FLUTTER_STORAGE_BASE_URL 為了加快速度,使用國內映象地址
`export PUB_HOSTED_URL=https://pub.flutter-io.cn && \
export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn && \
cd #{flutter_application_path} && \
#{flutter_application_path}/build_ios.sh -m debug`
if $?.to_i == 0
flutter_package_path = "#{flutter_application_path}/.build_ios/debug/product"
# 開始安裝
install_release_flutter_app_pod(flutter_package_path)
else
raise "Error: 編譯 Flutter App失敗"
end
end
複製程式碼
update_flutter_app
為從 git 拉取程式碼的函式也不贅述,詳情見文末 github 倉庫。
(2) 通過 pod 引入 Flutter 工程產物
上文兩個函式執行完成後,就得到了產物的存放目錄,下面只需要引入到 Native 倉庫就可以了,也就是install_release_flutter_app_pod
函式,從程式碼如下:
# 將 Flutter app 通過 pod 安裝
def install_release_flutter_app_pod(product_path)
if product_path.nil?
raise "Error: 無效的 flutter app 目錄"
end
puts "將 flutter app 通過 pod 匯入到 工程"
Dir.foreach product_path do |sub|
if sub.eql?('.') || sub.eql?('..')
next
end
sub_abs_path = File.join(product_path, sub)
pod sub, :path=>sub_abs_path
end
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['ENABLE_BITCODE'] = 'NO'
end
end
end
end
複製程式碼
如果要修改 release 產物版本,則設定FLUTTER_APP_VERSION
。 如果想要 debug flutter,則設定 FLUTTER_DEBUG_APP=true
,如果除錯原生代碼則設定 FLUTTER_APP_PATH="../my_flutter"
,負責將 FLUTTER_APP_PATH
註釋掉,配置 FLUTTER_APP_URL
FLUTTER_APP_BRANCH
。
四、總結
對照上文中提到的對混合工程的要求,總結一下:
- Flutter 工程完全不依賴 Native 工程,而是通過 'build_ios.sh' 指令碼進行編譯打包;
- 通過 pod 引入 Flutter 工程對 Native 也沒有浸入,不要在 Native 工程裡增加 Flutter 打包指令碼;
- Native 開發工程師只需要執行
pod install
所有的 Flutter 依賴就都加入進工程,不需要工程師配置 Flutter 開發環境;也不影響 Native 打包; - 也保留了本地除錯 Flutter 工程的功能;
Github 倉庫:iOS_Flutter_Hybrid_Project