【Flutter】如何寫一個Flutter自動打包成iOS代碼模塊的腳本

相信不少使用原生+Flutter的iOS項目都會遇到混合開發的集成問題,也有大神寫了一些解決方案,下面就記錄一下個人心路歷程:ios

前期準備

開始以前,我先拜讀了一些大神的文章(這裏只挑出對我幫助最大的):xcode

Flutter混合開發組件化與工程化架構緩存

混沌初始,iOS現有項目集成Flutterbash

方案篩選

通過探索,結合項目的實際狀況(我司的項目採用模塊化開發,pods方式集成),有下面的兩個方案:架構

  • 使用google的集成方案
  • 將flutter編譯後的產物打包到一個新的子模塊中,並在其中實現對應的接口和交互邏輯。

不管是從使用方便的角度仍是對代碼的侵入程度來看,採用方案2都是瓜熟蒂落的。iphone

實現方式

寫腳本以前,先來看看打包步驟(其實就是收集編譯產物)模塊化

打包步驟

打包的步驟以下:組件化

一、flutter build ios。ui

二、進入對應flutter項目的../ios(或者.ios)/Flutter/文件夾,找到App.framwork和Flutter.framework以及FlutterPluginRegistrant文件夾,拷貝到子模塊中。google

三、進入對應flutter項目的build/ios/Debug-iphoneos(或者Release-iphoneos),拷貝各個依賴庫的.a文件到子模塊中。

四、若是項目有依賴到第三方的插件(通常來講都會有),須要根據.flutter-plugins文件中的路徑到對應模塊的源代碼的ios/Classes中拷貝各個依賴庫的.h文件(這一步能夠說是至關繁瑣了)。

使用自動化腳本執行上面的操做

如下代碼均在flutter工程的目錄下操做:

首先是打包:

echo "===清理flutter歷史編譯==="
flutter clean

echo "===從新生成plugin索引==="
flutter packages get

echo "===生成App.framework和flutter_assets==="
flutter build ios --debug
# 或者 flutter build ios --release
複製代碼

而後是拷貝App.framework和Flutter.framework:

framework_dir=...
echo "===copy App.framework和Flutter.framework==="
cp -r "./.ios/Flutter/App.framework" $framework_dir
cp -r "./.ios/Flutter/engine/Flutter.framework" $framework_dir
複製代碼

拷貝註冊器:

classes_dir=...
echo "===copy註冊器:FlutterPluginRegistrant==="
regist_dir="./.ios/Flutter/FlutterPluginRegistrant/Classes/"
model_class=${classes_dir}/flutter/FlutterPluginRegistrant
mkdir -p $model_class
cp -r $regist_dir $model_class
複製代碼

接下來是各個插件的拷貝,這裏有一個小坑,因爲各個插件是被打包成.a的形式進行引入,那麼極可能致使模擬器上沒法運行的問題,須要打一個真機包和一個模擬器包,並將它們進行合併,才能在使用過程當中用模擬器進行調試:

# 合成的.a文件緩存
    temp_dir=...
    mkdir -p ${temp_dir}
    
current_path="$PWD"
# 執行clean並從新編譯pods部分
cd .ios/Pods
    /usr/bin/env xcrun xcodebuild clean
    /usr/bin/env xcrun xcodebuild build -configuration Release ARCHS='arm64 armv7' BUILD_AOT_ONLY=YES VERBOSE_SCRIPT_LOGGING=YES -workspace Runner.xcworkspace -scheme Runner BUILD_DIR=../build/ios -sdk iphoneos
    
# 遍歷.flutter-plugins文件
cat .flutter-plugins | while read line
    do
    array=(${line//=/ })
        plugin_name=${array[0]}
        echo "===修改註冊器(修正引用)==="
        perl -pi -e "s|\<${plugin_name}\/|\"|g" ${model_class}/GeneratedPluginRegistrant.m
        perl -pi -e "s|.h\>|.h\"|g" ${model_class}/GeneratedPluginRegistrant.m
        temp_library=${temp_dir}/lib${plugin_name}.a
        echo ">>>生成lib${plugin_name}.a<<<"
        cd .ios/Pods
        /usr/bin/env xcrun xcodebuild build -configuration Release ARCHS='arm64 armv7' -target ${plugin_name} BUILD_DIR=../../build/ios -sdk iphoneos -quiet
        /usr/bin/env xcrun xcodebuild build -configuration Debug ARCHS='x86_64' -target ${plugin_name} BUILD_DIR=../../build/ios -sdk iphonesimulator -quiet
        echo ">>>合併lib${plugin_name}.a<<<"
        lipo -create "../../build/ios/Debug-iphonesimulator/${plugin_name}/lib${plugin_name}.a" "../../build/ios/Release-iphoneos/${plugin_name}/lib${plugin_name}.a" -o $temp_library
        cd $current_path
        if [[ -f "$temp_library" ]]; then
            echo "===copy ${plugin_name}==="
            plugin=${framework_dir}/${plugin_name}
            rm -rf $plugin
            mkdir -p $plugin
            cp -f $temp_library $plugin
            classes=${array[1]}ios/Classes
            class=$dest_dir/Classes/flutter/${plugin_name}
            rm -rf $class
            mkdir -p $class
            for header in `find "$classes" -name *.h`; do
                cp -f $header $class
            done
        fi
    done
    rm -rf ${temp_dir}
fi
複製代碼

可能你會注意到上面的===修改註冊器(修正引用)===內容,這是因爲咱們將flutter的插件部分的文件直接打包成靜態庫,並將其.h文件所有導入到模塊內部了,所以自動生成的#import <xxx/xxx.h>模式不適用了(會報錯喲),須要改爲#import "xxx.h"的形式進行引用。

到此,flutter的自動打包腳本基本完成,上面的各個文件路徑須要根據實際狀況進行調整,改成適合本身的項目的路徑。

但願這篇可以幫助你們少走彎路。

相關文章
相關標籤/搜索