欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android集成Flutter

 更新時(shí)間:2021年08月24日 14:53:57   作者:xiangzhihong  
本文主要從一個(gè) Android 開(kāi)發(fā)的視角,談?wù)?Android 平臺(tái)下, Flutter 的混合開(kāi)發(fā)與構(gòu)建,如果你也感興趣的話一起參與學(xué)習(xí)吧

Android 集成Flutter

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

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

1, Hello Flutter

對(duì)于這門技術(shù),使用過(guò)的應(yīng)該絕大多數(shù)都會(huì)說(shuō)好;沒(méi)用過(guò)的推薦嘗試一下,跑個(gè) Demo 體驗(yàn)體驗(yàn),有可能它就是你需要學(xué)習(xí)和掌握的最后一門新技術(shù)了?;剡^(guò)頭來(lái),F(xiàn)lutter 究竟有什么獨(dú)特的魅力讓它能從一眾技術(shù)中脫穎而出呢?總結(jié)一下,主要有以下幾點(diǎn):

  • 跨平臺(tái):可以做到一套代碼完美適配 Android、iOS 平臺(tái),未來(lái)還會(huì)覆蓋更多平臺(tái),大大節(jié)省了開(kāi)發(fā)人力與維護(hù)成本,同時(shí)擁有出色的跨端 UI 表現(xiàn)一致性。
  • 高效開(kāi)發(fā):SDK 提供了豐富的 UI 組件,開(kāi)箱即用;聲明式的 UI 構(gòu)建方式,大大減少出錯(cuò)率;Debug 模式提供熱重載能力,可實(shí)時(shí)預(yù)覽代碼變更,不需要重新編譯安裝。
  • 高性能:采用自建渲染引擎,獨(dú)立于系統(tǒng)并可單獨(dú)優(yōu)化;區(qū)別于 RN、WEEX,沒(méi)有中間層轉(zhuǎn)換的額外開(kāi)銷;Release 模式下代碼編譯為 AOT 指令,運(yùn)行高效。

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

2, 引入 Flutter 模塊

要在一個(gè)已有的 Android Project 中使用 Flutter,需要引入一個(gè) Flutter Module。在 Android Studio(需要確保 Flutter 插件已經(jīng)成功安裝并啟用)中打開(kāi)現(xiàn)有 Android 工程,通過(guò)使用 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')

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

說(shuō)明如下:

  • 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)橐婚_(kāi)始我在 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í)生成的,記錄了插件的本地文件目錄、依賴信息等。

3,使用Flutter

3.1 添加依賴

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

dependencies { 
  implementation project(':flutter') 
}

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

3.2.1 添加Flutter頁(yè)面

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

Flutter Activity

首先,我們介紹下使用 Flutter Activity的方式。使用io.flutter.embedding.android.FlutterActivity類可以很方便的啟動(dòng)一個(gè) Flutter Activity,當(dāng)然我們也可以繼承它并擴(kuò)展自己的邏輯。

FlutterActivity 
  .withNewEngine() 
  .build(context) 
  .also { 
    startActivity(it) 
  }
Flutter Fragment

另外一種就是 Flutter Fragment方式??梢允褂肍lutterFragmentActivity或者FlutterFragment來(lái)添加 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()
 3.2.2 平臺(tái)層和 Flutter 層通信

不論是開(kāi)發(fā) Plugin 還是業(yè)務(wù)邏輯,平臺(tái)層與 Flutter 層通信是必不可少的,為此就需要使用到MethodChannel。平臺(tái)層通過(guò)MethodChannel請(qǐng)求調(diào)用 Flutter 層 API 時(shí),數(shù)據(jù)在經(jīng)過(guò)打包編碼后,通過(guò) JNI、DartVM 傳到 Flutter 層解碼后使用;待結(jié)果計(jì)算完成后,又會(huì)重新打包編碼,經(jīng)過(guò) DartVM、JNI 傳回到 Native 層;同理,在 Flutter 層請(qǐng)求調(diào)用平臺(tái)層的 API 時(shí),數(shù)據(jù)處理是一致的,只是流轉(zhuǎn)方向相反。通過(guò)這種方式,平臺(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(); 
    } 
  }

在上面的示例中,我們是通過(guò)手動(dòng)創(chuàng)建 MethodChannel 進(jìn)行通信的,這在進(jìn)行簡(jiǎn)單通信的場(chǎng)景是沒(méi)問(wèn)題的,但在通信接口 API 比較復(fù)雜的情況就不是很適用了。一是繁瑣,因?yàn)槲覀冃枰謱懘罅康拇虬?、拆包代碼;二是容易出錯(cuò)。

這個(gè)時(shí)候就輪到 Pigeon 大顯身手了。Pigeon 是一個(gè)官方推出的代碼生成工具,可以生成類型安全的雙向通信 API 接口,具體可以參考官方的 例子,Pigeon官方鏈接。

4,F(xiàn)lutter APK 解析

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

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

  • lib/{arch}/libflutter.so:為對(duì)應(yīng)架構(gòu)的 Flutter Engine 共享庫(kù),負(fù)責(zé) Flutter 渲染、JNI 通信、DartVM。如果不需要對(duì)應(yīng)架構(gòu)的版本,通過(guò) abiFilters 可以 Exclude 掉。
  • lib/{arch}/libapp.so:只存在于 Release 模式下,共享庫(kù)中包含 Dart AOT 生成的二進(jìn)制指令和數(shù)據(jù)。在運(yùn)行時(shí),F(xiàn)lutter Engine 通過(guò) 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 格式,為所有資源名稱到資源路徑的映射,F(xiàn)lutter 在加載某一項(xiàng)資源時(shí),會(huì)通過(guò)這個(gè)配置清單找到對(duì)應(yīng)路徑的資源進(jìn)行讀取后加載。
  • kernel_blob.bin、isolate_snapshot_data、vm_snapshot_data:只存在于 Debug 模式下,分別為 DartVM 字節(jié)碼與數(shù)據(jù),其作用類似于 libapp.so,只是存在形式、打包方式不同。在 Debug 模式下,F(xiàn)lutter Tools 將指令和數(shù)據(jù)分別打包,主要是為了熱重載(HotReload)服務(wù)的,而在 Release 模式下是統(tǒng)一打包成共享庫(kù)。

5,踩過(guò)的坑

Flutter 混合開(kāi)發(fā)使得開(kāi)發(fā)者可以漸進(jìn)式地進(jìn)行 Flutter 開(kāi)發(fā)與遷移,是 Flutter 寄生于原生平臺(tái)至關(guān)重要的一環(huán),不過(guò)在接入Flutter的過(guò)程中,也出現(xiàn)了一些問(wèn)題:

  • 路由管理復(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 此類的開(kāi)源解決方案。
  • 生命周期不對(duì)應(yīng):Android 的組件一般都會(huì)有自己的生命周期,F(xiàn)lutter 的 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。所以在混合開(kāi)發(fā)中,業(yè)務(wù)邏輯不應(yīng)該過(guò)度依賴 Widget State 的一些生命周期方法,因?yàn)樗鼈兛赡軙?huì)被延后執(zhí)行從而導(dǎo)致一些奇怪的 Bug。

到此這篇關(guān)于Android 集成Flutter的文章就介紹到這了,更多相關(guān)Android內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論