日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

技术干货 | Flutter 混合开发基础

發(fā)布時(shí)間:2025/3/8 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 技术干货 | Flutter 混合开发基础 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?

?

導(dǎo)讀:Flutter 支持以獨(dú)立頁(yè)面、甚至是 UI 片段的方式,集成到現(xiàn)有的應(yīng)用中,即所謂的混合開發(fā)模式。本文主要談?wù)?Android 平臺(tái)下, Flutter 的混合開發(fā)與構(gòu)建。

?

文|李成達(dá) 網(wǎng)易云信資深移動(dòng)端開發(fā)工程師

Flutter 作為 Google 開源的新一代跨平臺(tái)、高性能 UI 框架,旨在幫助開發(fā)者高效地構(gòu)建出跨平臺(tái)的、UI 與交互體驗(yàn)一致的精美應(yīng)用,推出后一直倍受開發(fā)者的青睞。

當(dāng)需要開發(fā)一個(gè)全新的應(yīng)用時(shí),我們可以很方便地從零開始,完全使用 Flutter 進(jìn)行開發(fā)。但如果是針對(duì)一個(gè)現(xiàn)有的應(yīng)用,需要引入 Flutter 技術(shù),顯然使用 Flutter 全部重寫一遍是不現(xiàn)實(shí)的。幸運(yùn)的是,Flutter 很好地支持了以獨(dú)立頁(yè)面、甚至是 UI 片段的方式集成到現(xiàn)有的應(yīng)用中,即所謂的混合開發(fā)模式。本文主要從一個(gè) Android 開發(fā)的視角,談?wù)?Android 平臺(tái)下, Flutter 的混合開發(fā)與構(gòu)建。

?

Hello Flutter

相信現(xiàn)在應(yīng)該很少會(huì)有移動(dòng)端開發(fā)者不知道 Flutter,這里不再做過多介紹。對(duì)于這門技術(shù),使用過的應(yīng)該絕大多數(shù)都會(huì)說好;沒用過的推薦嘗試一下,跑個(gè) Demo 體驗(yàn)體驗(yàn),有可能它就是你需要學(xué)習(xí)和掌握的最后一門新技術(shù)了。回過頭來,Flutter 究竟有什么獨(dú)特的魅力讓它能從一眾技術(shù)中脫穎而出呢?總結(jié)一下,主要有以下幾點(diǎn):

  • 跨平臺(tái):可以做到一套代碼完美適配 Android、iOS 平臺(tái),未來還會(huì)覆蓋更多平臺(tái),大大節(jié)省了開發(fā)人力與維護(hù)成本,同時(shí)擁有出色的跨端 UI 表現(xiàn)一致性。

  • 高效開發(fā):SDK 提供了豐富的 UI 組件,開箱即用;聲明式的 UI 構(gòu)建方式,大大減少出錯(cuò)率;Debug 模式提供熱重載能力,可實(shí)時(shí)預(yù)覽代碼變更,不需要重新編譯安裝。

  • 高性能:采用自建渲染引擎,獨(dú)立于系統(tǒng)并可單獨(dú)優(yōu)化;區(qū)別于 RN、WEEX,沒有中間層轉(zhuǎn)換的額外開銷;Release 模式下代碼編譯為 AOT 指令,運(yùn)行高效。

受益于以上的核心優(yōu)勢(shì),Flutter 推出后圈了很多移動(dòng)開發(fā)者的粉,各互聯(lián)網(wǎng)大廠也紛紛將其作為一項(xiàng)基礎(chǔ)技術(shù)進(jìn)行研究。在 Flutter 初期,其應(yīng)用場(chǎng)景主要是從 0 構(gòu)建一個(gè)全新 App,對(duì)混合開發(fā)的支持很不友好。但作為一門跨平臺(tái)的技術(shù)框架,到底還是需要依賴原生平臺(tái)提供的諸多系統(tǒng)能力,此外還有眾多現(xiàn)存原生 App 躍躍欲試,因此在這個(gè)需求背景下,混合開發(fā)的支持與完善至今已發(fā)展得越來越好,下面我們就用一個(gè)簡(jiǎn)單的示例開始 Android 端的 Flutter 混合開發(fā)與構(gòu)建之旅。

?

引入 Flutter 模塊

要在一個(gè)已有的 Android Project 中使用 Flutter,需要引入一個(gè) Flutter Module。在 Android Studio(需要確保 Flutter 插件已經(jīng)成功安裝并啟用)中打開現(xiàn)有 Android 工程,通過使用 File > New > New Module… 菜單,我們可以新創(chuàng)建一個(gè) Flutter 模塊或是導(dǎo)入一個(gè)外部的 Flutter 模塊。

這里以最簡(jiǎn)單的 Android App 項(xiàng)目為例,導(dǎo)入 Flutter 模塊。在 Flutter 模塊導(dǎo)入成功之后,原工程文件、結(jié)構(gòu)都會(huì)發(fā)生一些變化,主要有:

  • settings.gradle 文件新增了以下內(nèi)容。其實(shí)就是執(zhí)行對(duì)應(yīng) Flutter 模塊下 .android/include_flutter.groovy 腳本文件,該步驟會(huì)引入一個(gè)名為 Flutter 的 Android Library Module,同時(shí)還會(huì)引入 Flutter 模塊所依賴的所有插件。

setBinding(new Binding([gradle: this])) evaluate(new File( settingsDir.parentFile, 'flutter_module/.android/include_flutter.groovy' )) include ':flutter_module' project(':flutter_module').projectDir = new File('../flutter_module')
  • 項(xiàng)目結(jié)構(gòu)變化,如下圖所示:

在引入 Flutter 模塊之前,項(xiàng)目中僅有 app 一個(gè) Module;而在引入之后,可以看到除了原有的 app Module 外,Flutter Gradle 插件自動(dòng)引入了額外幾個(gè)子 Module:

  • flutter_module:指代要引入的目標(biāo) Flutter Module,不會(huì) apply Android 相關(guān)的任何插件,主要是包含 Flutter 相關(guān)源碼、資源、依賴等。

  • flutter:為 Flutter Gradle 插件引入的 Android Library Module;主要負(fù)責(zé)編譯 flutter_module 及其依賴的第三方 Package、Plugin 的 Dart 代碼,以及打包 Flutter 資源等。

  • device_info:為 Flutter Gradle 插件自動(dòng)引入的 Flutter Android Plugin Library Module,這是因?yàn)橐婚_始我在 flutter_module 的 pubspec.yaml 文件中添加了對(duì) device_info 這個(gè)插件的依賴。Flutter Gradle 工具會(huì)將 flutter_module 依賴到的所有插件其 Android 平臺(tái)側(cè)的代碼、資源作為一個(gè) Library Module 引入到項(xiàng)目中一起參與構(gòu)建。如果要查看 flutter_module 引入了哪些 Plugin,可以查看其對(duì)應(yīng)目錄下的 .flutter-plugins 與 .flutter-plugins-dependencies 文件,這兩個(gè)文件是執(zhí)行 flutter pub get 時(shí)生成的,記錄了插件的本地文件目錄、依賴信息等。

注意:一個(gè)工程不能包含多個(gè) Flutter Module,最多只能引入一個(gè),這是由 Flutter 的 Gradle 插件決定的。

?

使用 Flutter

完成 Flutter 模塊的引入后,我們?cè)賮砜纯慈绾问褂?Flutter。

?添加依賴?

首先需要在 App 模塊的build.gradle腳本文件中添加對(duì)Flutter工程的依賴,只有這樣 Flutter 模塊才會(huì)參與到整個(gè)應(yīng)用的構(gòu)建中來,我們也才能夠在 App 模塊中調(diào)用到 Flutter 提供的 Java 層 API。如下所示:

dependencies { implementation project(':flutter') }

?運(yùn)行 Flutter 頁(yè)面?

我們可以選擇使用 Activity、Fragment 或者 View 來承載 Flutter 的 UI,這里主要介紹前面兩種方式,并假設(shè)flutter_module中已經(jīng)通過runApp方法渲染了一個(gè)widget。

  • 運(yùn)行 Flutter Activity。使用io.flutter.embedding.android.FlutterActivity類可以很方便的啟動(dòng)一個(gè) Flutter Activity,當(dāng)然我們也可以繼承它并擴(kuò)展自己的邏輯。示例代碼如下:

FlutterActivity .withNewEngine() .build(context) .also { startActivity(it) }
  • 運(yùn)行 Flutter Fragment。可以使用FlutterFragmentActivity或者FlutterFragment來添加 Flutter UI 片段:a. 使用FlutterFragmentActivity可以自動(dòng)創(chuàng)建并添加一個(gè)FlutterFragment;b. 手動(dòng)創(chuàng)建FlutterFragment后添加到目標(biāo) Activity 中。示例代碼如下:

val flutterFragment = FlutterFragment.withNewEngine() .dartEntrypoint(getDartEntrypointFunctionName()) .initialRoute(getInitialRoute()) .appBundlePath(getAppBundlePath()) .flutterShellArgs(FlutterShellArgs.fromIntent(intent)) .handleDeeplinking(shouldHandleDeeplinking()) .renderMode(renderMode) .transparencyMode(transparencyMode) .shouldAttachEngineToActivity(shouldAttachEngineToActivity()) .build<FlutterFragment>() fragmentManager .beginTransaction() .add( FRAGMENT_CONTAINER_ID, flutterFragment, TAG_FLUTTER_FRAGMENT ) .commit()
  • 平臺(tái)層和 Flutter 層通信。不論是開發(fā) Plugin 還是業(yè)務(wù)邏輯,平臺(tái)層與 Flutter 層通信是必不可少的,為此就需要使用到MethodChannel。平臺(tái)層通過MethodChannel請(qǐng)求調(diào)用 Flutter 層 API 時(shí),數(shù)據(jù)在經(jīng)過打包編碼后,通過 JNI、DartVM 傳到 Flutter 層解碼后使用;待結(jié)果計(jì)算完成后,又會(huì)重新打包編碼,經(jīng)過 DartVM、JNI 傳回到 Native 層;同理,在 Flutter 層請(qǐng)求調(diào)用平臺(tái)層的 API 時(shí),數(shù)據(jù)處理是一致的,只是流轉(zhuǎn)方向相反。通過這種方式,平臺(tái)層與 Flutter 層就建立了一個(gè)雙向的、異步的通信通道。在下面的示例代碼中,Native 層使用dev.flutter.example/counter創(chuàng)建一個(gè)MethodChannel,并設(shè)置 Handler 接收 Dart 的遠(yuǎn)程方法調(diào)用 incrementCounter,并調(diào)用 reportCounter 將結(jié)果回傳。

channel = MethodChannel(flutterEngine.dartExecutor, "dev.flutter.example/counter") channel.setMethodCallHandler { call, _ -> when (call.method) { "incrementCounter" -> { count++ channel.invokeMethod("reportCounter", count) } } }

Dart 層使用相同的名稱創(chuàng)建 MethodChannel,并設(shè)置 Handler 處理回調(diào)結(jié)果,隨后調(diào)用 incrementCounter 方法請(qǐng)求 counter。示例代碼如下:

final _channel = MethodChannel('dev.flutter.example/counter'); _channel.setMethodCallHandler(_handleMessage); _channel.invokeMethod('incrementCounter'); Future<dynamic> _handleMessage(MethodCall call) async { if (call.method == 'reportCounter') { _count = call.arguments as int; notifyListeners(); } }

這里我們是通過手動(dòng)創(chuàng)建 MethodChannel 進(jìn)行通信的,這在進(jìn)行簡(jiǎn)單通信的場(chǎng)景是沒問題的,但在通信接口 API 比較復(fù)雜的情況就不是很適用了。

一是繁瑣,因?yàn)槲覀冃枰謱懘罅康拇虬⒉鸢a;二是容易出錯(cuò)。這個(gè)時(shí)候就輪到 ?Pigeon 大顯身手了。Pigeon 是一個(gè)官方推出的代碼生成工具,可以生成類型安全的雙向通信 API 接口,具體可以參考官方的 Example,這里不再贅述。

Pigeon :https://flutter.dev/docs/development/platform-integration/platform-channels#pigeon

?

Flutter APK 解析

到這里,我們已經(jīng)了解了如何在現(xiàn)有 Android 項(xiàng)目中引入并使用 Flutter,接下來我們?cè)賮硖骄恳幌?Flutter APK 的結(jié)構(gòu),看看 Flutter Tools 在這個(gè) APK 包內(nèi)到底打包了哪些東西。下面兩圖分別為 Debub 模式和 Release 模式下構(gòu)建出來的 Flutter APK 包結(jié)構(gòu),忽略了非 Flutter 相關(guān)的項(xiàng)。

可以看到兩個(gè)模式下的 APK 結(jié)構(gòu)大致相同,說明如下:

  • lib/{arch}/libflutter.so:為對(duì)應(yīng)架構(gòu)的 Flutter Engine 共享庫(kù),負(fù)責(zé) Flutter 渲染、JNI 通信、DartVM。如果不需要對(duì)應(yīng)架構(gòu)的版本,通過 abiFilters 可以 Exclude 掉。

  • lib/{arch}/libapp.so:只存在于 Release 模式下,共享庫(kù)中包含 Dart AOT 生成的二進(jìn)制指令和數(shù)據(jù)。在運(yùn)行時(shí),Flutter Engine 通過 Dynamic Load 的方式,從共享庫(kù)中讀取對(duì)應(yīng)的可執(zhí)行機(jī)器指令以及數(shù)據(jù)。

  • assets/flutter_assets:Flutter 引用到的相關(guān)資源:

    • fonts:包含字體庫(kù)。

    • FontManifest.json:引用到的字體庫(kù)清單文件,json 格式,所有使用到的字體、以及字體文件在 flutter_assets 下的路徑。

    • AssetManifest.json:其他資源清單文件,json 格式,為所有資源名稱到資源路徑的映射,Flutter 在加載某一項(xiàng)資源時(shí),會(huì)通過這個(gè)配置清單找到對(duì)應(yīng)路徑的資源進(jìn)行讀取后加載。

    • kernel_blob.bin、isolate_snapshot_data、vm_snapshot_data:只存在于 Debug 模式下,分別為 DartVM 字節(jié)碼與數(shù)據(jù),其作用類似于 libapp.so,只是存在形式、打包方式不同。在 Debug 模式下,Flutter Tools 將指令和數(shù)據(jù)分別打包,主要是為了熱重載(HotReload)服務(wù)的,而在 Release 模式下是統(tǒng)一打包成共享庫(kù)。

?

踩過的坑

這里,也總結(jié)了幾個(gè)我們?cè)趹?yīng)用的時(shí)候遇到的問題,供大家參考避坑。

  • 路由管理復(fù)雜:這里面包括 Flutter 層內(nèi)部的頁(yè)面路由管理以及 Flutter 與原生的混合棧管理。前者在 Navigator 2.0 API 中已經(jīng)得到了很好的完善與支持,但后者仍面臨著諸多限制與不足,需要改進(jìn)。目前項(xiàng)目中還未涉及到后者這種很復(fù)雜的業(yè)務(wù)場(chǎng)景,因此對(duì)這一塊的研究比較少,感興趣的同學(xué)可以了解一下諸如 flutter_boost 此類的開源解決方案。

  • 生命周期不對(duì)應(yīng):Android 的組件一般都會(huì)有自己的生命周期,Flutter 的 Widget State 也有一套自己的生命周期,但這兩者其實(shí)并不是一一對(duì)應(yīng)的。比如原生的 Activity 頁(yè)面雖然已經(jīng)被 Finish 并 Destroy 掉了,但 Flutter 層的頁(yè)面并不一定會(huì)隨之而被 Dispose,尤其是在使用 Cache Flutter Engine 的時(shí)候。Flutter 頁(yè)面是可以脫離原生頁(yè)面而存在的,它們可以被動(dòng)態(tài)地 Attach 和 Detach,Attach 時(shí)會(huì)觸發(fā)重新渲染,Detach 時(shí) UI 相關(guān)的所有操作都會(huì) Pending 直到重新被 Attach。所以在混合開發(fā)中,業(yè)務(wù)邏輯不應(yīng)該過度依賴 Widget State 的一些生命周期方法,因?yàn)樗鼈兛赡軙?huì)被延后執(zhí)行從而導(dǎo)致一些奇怪的 Bug。

?

總結(jié)

Flutter 混合開發(fā)使得開發(fā)者可以漸進(jìn)式地進(jìn)行 Flutter 開發(fā)與遷移,是 Flutter 寄生于原生平臺(tái)至關(guān)重要的一環(huán)。

本文主要從一個(gè) Android 開發(fā)的視角,介紹了 Flutter 混合開發(fā)的入門知識(shí)。隨著 Flutter 開源項(xiàng)目的不斷迭代與演進(jìn),混合開發(fā)的體驗(yàn)正在變得越來越好、性能也越來越高。但美中不足的是仍然有一些應(yīng)用場(chǎng)景與問題并未得到很好地完善與解決,比如 Flutter 多實(shí)例問題(我們也將在下個(gè)月的另一篇文章中跟大家分享介紹我們?cè)?strong>實(shí)踐 Flutter 多實(shí)例遇到的問題與解決方案,敬請(qǐng)關(guān)注)。

瑕不掩瑜,Flutter 這門技術(shù)整體而言還是非常不錯(cuò)的,它如今仍處于快速發(fā)展的階段,相信在 Flutter 團(tuán)隊(duì)與開源社區(qū)的共同努力下,未來的生態(tài)值得期待。

?作者介紹?

李成達(dá),網(wǎng)易云信資深移動(dòng)端開發(fā)工程師,熱衷于研究跨平臺(tái)開發(fā)技術(shù)以及工程提效,目前主要負(fù)責(zé)視頻會(huì)議組件化 SDK 的相關(guān)研發(fā)工作。

?延伸閱讀?

  • 技術(shù)干貨 | 基于 Qt Quick Plugin 快速構(gòu)建桌面端跨平臺(tái)組件

  • 技術(shù)實(shí)踐 | Android 設(shè)備音視頻兼容性適配

  • 技術(shù)干貨 | iOS 高階容器詳解

?

總結(jié)

以上是生活随笔為你收集整理的技术干货 | Flutter 混合开发基础的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。