Flutter遠程依賴簡單實踐

??19年初,準(zhǔn)備嘗試 Flutter 實現(xiàn)部分業(yè)務(wù)頁面士聪,一個因為 Native 主工程已經(jīng)較為龐大锦援,一個因為目前只有少部分人投入 Flutter 的嘗試,因此不可能重建一個 Flutter 工程來實現(xiàn)整個主工程剥悟,而且因為少部分人嘗試灵寺,所以也不可能每個人都安裝 Flutter 環(huán)境曼库,所以,在 Native 工程中引入 Flutter 過程中略板,最好能像引入 其它第三方組件一樣通過 pod 引入 Flutter毁枯,而其他非 Flutter 的業(yè)務(wù)開發(fā)人員無需安裝 Flutter 環(huán)境來實現(xiàn)無痕的嵌入使用
?? 接下來我們就關(guān)于 Native 工程中引入 Flutter 的一些做法進行簡單說明

  • 簡單的實現(xiàn)

  1. 新建了一個 flutter_appFlutter 工程,用來實現(xiàn)相關(guān)的 flutter 業(yè)務(wù)叮称,它的目錄結(jié)構(gòu)如下

    ?? 由 Flutter 目錄分別包含兩個平臺的 Native 工程的目錄組成种玛,我們通過 flutter build ios --release 后可以查看到 ios 的 Flutter 目錄下包含了一些構(gòu)建運行后的產(chǎn)物:
    App.framework - dart代碼生成
    Flutter.framework - 引擎
    flutter_assets - 相關(guān)資源(這塊資源在新的Fluterr版本中包含在App.framework中)
    ??而這也正是 Navtive 工程引入 Flutter 需要的依賴,所以很容易想到收集這些中間產(chǎn)物作為組件內(nèi)容瓤檐,并通過 pod 引入即可
    ????????以上的產(chǎn)物均為 flutter 平臺相關(guān) dart 代碼資源赂韵,若是引入 plugin,那理應(yīng)還有 plugin 對應(yīng) Navtive 平臺的代碼挠蛉,通過圖上目錄右锨,.flutter-plugins 即項目引用的 plugins 及對應(yīng)本地路徑,也就是說這一步我們目前可知需要的內(nèi)容如下
.flutter-plugins - 引用的 plugins 及對應(yīng)本地路徑
App.framework - dart代碼生成
Flutter.framework - 引擎
flutter_assets - 相關(guān)資源
Source - Flutter 工程的原生代碼碌秸,一些 channel 代碼绍移,混合棧的構(gòu)建代碼
  1. 新建一個 product_flutter 的中間產(chǎn)物模塊, Flutter 編譯過后的產(chǎn)物讥电、plugin Navtive平臺代碼蹂窖,Flutter 工程的原生代碼 - Source 進行收集放置 product_flutter 這個模塊中,然后上傳至 git 倉庫恩敌,目錄如下


.podspec 需要??的一個就是 .flutter-plugins,pluginspodhelper.rb,plugins在pod下載后不要刪除瞬测,否則工程項目分析及pod plugin會缺少文件,所以.podspec的內(nèi)容如下:

# MARK: converted automatically by spec.py. @liya

Pod::Spec.new do |s|
    s.name = 'product_flutter'
    s.version = '1.0'
    s.description = 'product_flutter纠炮,喵喵'
    s.license = 'MIT'
    s.summary = 'product_flutter'
    s.homepage = 'https://xxx'
    s.authors = { 'Liya' => 'xxx@qq.com' }
    s.source = { :git => '.../product_flutter', :branch => 'master' }
    s.ios.deployment_target = '8.0'

    s.vendored_frameworks = 'Flutter.framework', 'App.framework'
    s.resources = 'flutter_assets'
    s.source_files = 'Source/**/*.{h,m,c}'
    s.preserve_paths = 'pluginspodhelper.rb', '.flutter-plugins', 'Plugins/**/*.{*}'
end

收集腳本較為簡單月趟,這里就發(fā)下 plugins 的收集部分

flutter_res_plugins=$PWD/.flutter-plugins

......

while read -r line
  do
    if [[ ! "$line" =~ ^// && ! "$line" =~ ^# ]]; then
      array=(${line//=/ })

      iosClasses=${array[1]}ios/Classes
      plugin=$PWD/Plugins/${array[0]}
      if [ -d $plugin ]; then
        rm -rf $plugin
      fi

      if [ -d $iosClasses ]; then
        mkdir -p $plugin
        cp -rf $iosClasses $plugin
// 這里是為了解決 plugins 相關(guān)的依賴傳遞,所以把.podspec也進行包含
        podspec=${array[1]}ios/${array[0]}.podspec
        if [ -d $iosClasses ]; then
            cp -f $podspec $plugin
            podspec=$plugin/${array[0]}.podspec
            echo "刪除 s.dependency 'Flutter' in $podspec"
            sed -i '' -e "s/s.dependency 'Flutter'//g" $podspec
        fi

        echo "plugin $plugin"
        echo "iosClasses $iosClasses"
      fi
    fi
  done < $flutter_res_plugins
  1. 在前兩步完成后恢口,考慮到參與 Flutter 項目的人員可能 Flutter 環(huán)境不一致等情況孝宗,還有就是每次都需要手動 build 并更新上傳至 product_flutter 倉庫,所以借助 ci 完成部分手動工作耕肩,同時 ci Flutter 環(huán)境單一因妇,可以確保打出來的中間產(chǎn)物環(huán)境一致
    ?? 在 ci 創(chuàng)建 test_flutter 的任務(wù),設(shè)定腳本每天在凌晨進行一次打包后自動上傳中間產(chǎn)物至 product_flutter(也可手動去 ci 點擊進行打包)猿诸,整個腳本目前很簡單婚被,主要也就是
#...
export PATH=/usr/local/bin:$PATH
export PATH=$PATH:$HOME/XXX/flutter/bin

echo "flutter begin"
flutter packages get

echo "pod install or update"
cd ios
if [ ! -d "$PWD/Pods"]; then
    pod install
else
    pod update
fi
cd -

echo "flutter release -- "
flutter clean
flutter build ios --release

# 接下來其它操作也僅僅就是將產(chǎn)物拷貝打tag并上傳
  1. 而在需要使用 Flutter 的工程中,調(diào)用較為簡單梳虽,但是同時要注意到 plugin 的 pod 使用
   # pod product_flutter址芯,這里進行本地實驗,放git上一樣
    pod 'product_flutter',:git => '../product_flutter'
  # 產(chǎn)物收集時同時也收集了.flutter-plugins
  # 使用時依然分析一次 .flutter-plugins 并依次對 plugin 進行 pod 引用
    flutter_pod_fold ||= File.join(__dir__,"Pods","product_flutter")
    flutter_plugin_rb ||= File.join(flutter_pod_fold,"pluginspodhelper.rb")
    if File.exists? flutter_plugin_rb
        load flutter_plugin_rb
        pod_KV_file(flutter_pod_fold)
    end

其中 pluginspodhelper.rb 腳本主要內(nèi)容如下

....
def pod_KV_file(pod_file)
    # If this wasn't specified, assume it's two levels up from the directory of this script.
    print "進行 pod plugin "
    flutter_pod_path ||= File.join(pod_file)
    plugin_pods_file = parse_KV_file(File.join(flutter_pod_path, '.flutter-plugins'))
    plugin_pods_file.map { |r|
        print "plugin_pods_file = ",r
        pod r[:name], :path => File.join(flutter_pod_path, 'Plugins', r[:name])
    }
end
  • 題外話

  1. 目前是通過 ci 實現(xiàn)定時任務(wù),打包后自動上傳中間產(chǎn)物谷炸,也可以通過 git hook 判斷 flutter_app 提交的新代碼删顶,然后自動觸發(fā) ci 進行 flutter_app 打包
    采取哪種方式或者打包頻次根據(jù)自身需要即可
  2. flutter 打包在不同模式下的中間產(chǎn)物具有差異
    a. debug 模式下有JIT支持(所以支持熱重載 HotReload),App.framework 只有幾個簡單的 API淑廊,其 Dart 代碼生成標(biāo)記化的源代碼,運行時編譯特咆,解釋執(zhí)行季惩,存在于 flutter_assetskernel_blob.bin 文件里
    b. release 模式下是AOT支持App.framework 是所有的 dart 代碼(業(yè)務(wù)代碼腻格,第三方 package 代碼画拾,及所依賴的 flutter 框架代碼等等)編譯所成,Flutter.framework 則是 Flutter 架構(gòu)中的 engine 部分菜职,flutter_assets 是圖片青抛,字體等相關(guān)資源
  • 莫名其妙

?? 也不懂為啥突然想在大年初一寫這個,也沒完全規(guī)劃好酬核,寫的也很簡單蜜另,不過本身遠程依賴這一步并不復(fù)雜~~權(quán)當(dāng)作新年開關(guān)好了~~ON 一下~~

=======================后續(xù)的一點補充===============================

  • Native 主工程動態(tài)引入Debug及Release環(huán)境的中間產(chǎn)物包

    因為如題外話所說,flutter打包的產(chǎn)物在不同模式下是有差異的嫡意,所以導(dǎo)致在開發(fā)模式中需要用的Debug举瑰,但是打包上架需要Release,而作為Flutter開發(fā)人員蔬螟,有時有希望能在本地主工程引用中看效果此迅,因此可能需要手動切換等,耗時耗力旧巾,這真是萬萬不能忍呀~~耸序,所以對這塊的腳本及流程進行了一些稍稍優(yōu)化
    1 . 收集產(chǎn)物時,進行兩模式的分開收集鲁猩,一是 Debug 模式坎怪,一是 Release 模式
flutter build ios --no-codesign  --debug
//跟以上一樣收集對應(yīng)的真機的debug產(chǎn)物
flutter build ios --simulator  --debug
//同上并合并
lipo -create $res_dir/App.framework/App $target_debug_dir/App.framework/App -output $target_debug_dir/App.framework/App

....

Release 模式的

flutter build ios --no-codesign --release
//收集Release產(chǎn)物,并注意要將注冊文件一起收集到Source中
cp {$source_runner_res_dir/GeneratedPluginRegistrant.h,$source_runner_res_dir/GeneratedPluginRegistrant.m} $target_source_dir

Flutter 是 Debug 模式下的產(chǎn)物廓握,F(xiàn)lutter_Release 是 Release 模式產(chǎn)物芋忿,與第一次的區(qū)別在圖中

pod 執(zhí)行腳本及 plugin 引用在 PluginTool 文件夾中
  1. 收集產(chǎn)物后,就是pod的相關(guān)操作了
    1). 將 Flutter Debug 及 Release 產(chǎn)物分別對應(yīng)一個 podspec 文件疾棵,而個人工程中相關(guān)的原生代碼對應(yīng)一個 podspec 文件戈钢,引用如下,即可解決不同模式下引用是尔,方便了手動操作
    ( PS 這個如果有更好的 framework search 路徑設(shè)置及 flutter_assets 資源路徑設(shè)置方法殉了,請留言,之前嘗試過直接在 podfile 中設(shè)置拟枚,依然有各種問題 )
    pod 'LYFlutter', :git => "...", :branch => branch
    pod 'FlutterFrame_Debug', :git => "...", :branch => branch, :configurations => 'Debug'
    pod 'FlutterFrame_Release', :git => "...", :branch => branch, :configurations => 'Release'

當(dāng)然薪铜,在實際使用中均放置在 FlutterPodHeleper.rb 腳本中众弓,并在其中下載 .flutter-plugins文件,并解析并pod相關(guān)文件

# flutter遠程依賴 - release的產(chǎn)物
# $flutter_pod_path : 工程 pods 的路徑
# $flutter_branch : LYFlutter的分支隔箍,未設(shè)置默認 "master"
    $flutter_pod_path = __dir__+"/Pods"
    eval(File.read(File.join(__dir__, 'FlutterPodHelper.rb')), binding)

# flutter本地依賴 
# $flutter_application_path : flutter工程的路徑
    $flutter_application_path = "/Users/.../Liya_flutter"
    eval(File.read(File.join(__dir__, 'FlutterPodHelper.rb')), binding)

post_install hook

post_install do |installer|
#調(diào)用配置 - bitcode設(shè)置
    update_flutter_configs(installer, $flutter_application_path)
end
  1. FlutterPodHeleper.rb 腳本實現(xiàn)主要如下谓娃,其實就是之前的 pluginspodhelper .rb 腳本,改后承接較多的內(nèi)容
# 遠程的plugins文件解析
def pod_remote_flugins_file(plugin_helper_local_path, pod_file)
    # If this wasn't specified, assume it's two levels up from the directory of this script.
    print "解析并寫入pod plugin \n"
    plugin_pods_file = parse_KV_file(File.join(plugin_helper_local_path))
    plugin_pods_file.map { |r|
        print "plugin_pods_file = ",r[:name]," \n"
        pod r[:name], :path => File.join(pod_file, 'LYFlutter/Plugins', r[:name])
    }
end

# 遠程的plugins文件下載并解析
def down_remote_plugins_file(branch, pod_file)
    lyflutter_url = "https://.../LYFlutter"
    lyflutter_git_url = lyflutter_url+".git"
    plugin_helper_url = lyflutter_url+"/raw/"+branch+"/PluginTool/.flutter-plugins"
    
    plugin_helper_local_path = './.flutter-plugins'
    
    print "下載 plugins 解析文件 \n"
    download = open(plugin_helper_url)
    IO.copy_stream(download, plugin_helper_local_path)
    
    pod 'LYFlutter', :git => lyflutter_url, :branch => branch
    pod 'FlutterFrame_Debug', :git => lyflutter_url, :branch => branch, :configurations => 'Debug'
    pod 'FlutterFrame_Release', :git => lyflutter_url, :branch => branch, :configurations => 'Release'
    
    pod_remote_flugins_file(plugin_helper_local_path, pod_file)
    print "刪除下載 plugins 相關(guān)文件 \n"
    File.delete(plugin_helper_local_path)
end

本地的引用

# 本地的引用
def local_remote_plugins_file(flutter_application_path)
    native_application_path = File.join(flutter_application_path, 'ios')
    framework_dir = File.join(native_application_path, 'Flutter')
    
    pod 'Flutter', :path => native_application_path
    pod 'LYFlutter', :path => native_application_path
    
    symlinks_dir = File.join(native_application_path, '.symlinks')
    FileUtils.mkdir_p(symlinks_dir)
    plugin_pods = parse_KV_file(File.join(flutter_application_path, '.flutter-plugins'))
    plugin_pods.map { |r|
        symlink = File.join(symlinks_dir, 'plugins', r[:name])
        FileUtils.rm_f(symlink)
        File.symlink(r[:path], symlink)
        pod r[:name], :path => File.join(symlink, 'ios')
    }
end

如上基本就是引用腳本的主要代碼了蜒滩,遠程依賴及產(chǎn)物收集腳本及目錄結(jié)構(gòu)詳情點??

這文章組織上自己沒做好滨达,就將就吧~~??

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市俯艰,隨后出現(xiàn)的幾起案子捡遍,更是在濱河造成了極大的恐慌,老刑警劉巖竹握,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件画株,死亡現(xiàn)場離奇詭異,居然都是意外死亡啦辐,警方通過查閱死者的電腦和手機谓传,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來芹关,“玉大人良拼,你說我怎么就攤上這事〕浔撸” “怎么了庸推?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長浇冰。 經(jīng)常有香客問我贬媒,道長,這世上最難降的妖魔是什么肘习? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任际乘,我火速辦了婚禮,結(jié)果婚禮上漂佩,老公的妹妹穿的比我還像新娘脖含。我一直安慰自己,他們只是感情好投蝉,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布养葵。 她就那樣靜靜地躺著,像睡著了一般瘩缆。 火紅的嫁衣襯著肌膚如雪关拒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天,我揣著相機與錄音着绊,去河邊找鬼谐算。 笑死,一個胖子當(dāng)著我的面吹牛归露,可吹牛的內(nèi)容都是我干的洲脂。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼剧包,長吁一口氣:“原來是場噩夢啊……” “哼恐锦!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起玄捕,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎棚放,沒想到半個月后枚粘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡飘蚯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年馍迄,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片局骤。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡攀圈,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出峦甩,到底是詐尸還是另有隱情赘来,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布凯傲,位于F島的核電站犬辰,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏冰单。R本人自食惡果不足惜幌缝,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望诫欠。 院中可真熱鬧涵卵,春花似錦、人聲如沸荒叼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽被廓。三九已至贴硫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背英遭。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工间护, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人挖诸。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓汁尺,卻偏偏與公主長得像,于是被迫代替她去往敵國和親多律。 傳聞我的和親對象是個殘疾皇子痴突,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350