從零搭建 iOS Native Flutter 混合工程

iOS開發2019-07-06 04:02:55

黑客技術
點擊右側關注,瞭解黑客的世界!

Linux編程
點擊右側關注,免費入門到精通!

程序員嚴選
甄選正品好物,程序員生活指南!


作者丨CaffreySun

https://juejin.im/post/5c3ae5ef518825242165c5ca


本文來實現一個靈活、無侵入、低耦合的 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,"my_flutter" 是要創建的 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,點擊頂部的 + 號,選擇 New Run Script Phase,然後輸入以下腳本


"$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 指令時可以根據當前 Flutter 工程使用對應版本的 Flutter SDK,目前有一個名叫flutter_wrapper的工具,使用 flutterw 代替 flutter  指令,工具會自動將 Flutter SDK 放在當前 Flutter 工程目錄下,並執行當前工程中的 flutter 命令,這樣就不再依賴本地電腦安裝的 Flutter SDK。


flutter_wrapper使用:


  1. flutter create創建 Flutter 工程,這裏使用的是本地的 Flutter SDK

  2. 進入 Flutter 工程目錄安裝 'flutter_wrapper',執行 sh -c "$(curl -fsSL https://raw.githubusercontent.com/passsy/flutter_wrapper/master/install.sh)"

  3. 此後在當前 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 工程,拆分一下這個腳本流程,大致分為一下幾個步驟:


  1. 檢查 Flutter 環境,拉取 Flutter plugin

  2. 編譯 Flutter 工程產物

  3. 複製 Flutter 插件中的 Native 代碼

  4. 將產物同步到產物發佈的服務器


下面來一步一步的分析並實現每一步:


(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
    cp -rf -- "${BUILD_PATH}/flutter_assets" "${PRODUCT_APP_PATH}/App.framework"

    # setting podspec
    # replace:
    # 'Flutter.framework'
    # to:
    # 'Flutter.framework', 'App.framework'
    sed -i '' -e $'s/'Flutter.framework'/'Flutter.framework', 'App.framework'/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 "請耐心等️待☕️️️️️☕️☕️
"


    # 默認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 "
Flutter 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 "
拉取 Flutter App 代碼"

        puts "Flutter App路徑: "+flutter_application_path
        update_flutter_app(flutter_application_path, flutter_application_url, flutter_application_branch)
    end

    puts "
編譯 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 倉庫:https://github.com/CaffreySun/iOS_Flutter_Hybrid_Project


 推薦↓↓↓ 

👉16個技術公眾號】都在這裏!

涵蓋:程序員大咖、源碼共讀、程序員共讀、數據結構與算法、黑客技術和網絡安全、大數據科技、編程前端、Java、Python、Web編程開發、Android、iOS開發、Linux、數據庫研發、幽默程序員等。

萬水千山總是情,點個 “在看” 行不行
https://hk.wxwenku.com/d/201078296