Flutter與Android混合開發及Platform Channel的使用

  1. 相對于單獨開發Flutter應用,混合開發對于線上項目更具有實際意義,可以把風險控制到最低,也可以進行實戰上線。所以介紹 集成已有項目

  2. 混合開發涉及原生Native和Flutter進行通信傳輸,還有插件編寫,所以介紹 兩端通信Flutter Platform Channel的使用

WanAndroid客戶端簡單Flutter版 Apk

集成已有項目

官方方案 | 閑魚團隊方案 | 頭條團隊方案

采用官方的實現方式,對個人和小團隊相對簡單易用,并沒有實踐閑魚和頭條等大項目的方式。個中利弊上述推薦均有提到。

開始

  1. 在已有項目根目錄運行命令

    flutter create -t module my_flutter

    不一定非在項目下創建,兼顧ios,位置路徑尋址對即可

  2. 在項目的settings.gradle 文件添加如下代碼

    // MyApp/settings.gradle
    include ':app'                                     // assumed existing content
    setBinding(new Binding([gradle: this]))                                 // new
    evaluate(new File(                                                      // new
      settingsDir.parentFile,                                               // new
      'my_flutter/.android/include_flutter.groovy'                          // new
    ))                                                                      // new
    

    Binding飄紅不予理會,強迫癥的不用導包
    'my_flutter/.android/include_flutter.groovy'為my_flutter文件路徑,報錯找不到可寫項目全路徑'ChannelFlutterAndroid/my_flutter/.android/include_flutter.groovy'

  3. 在運行模塊app的build.gradle添加依賴

    // MyApp/app/build.gradle
    dependencies {
        implementation project(':flutter')
    }
    
  4. 在原生Android端創建并添加flutterView

     val flutterView = Flutter.createView(this, lifecycle, "route1")
     val layoutParams = FrameLayout.LayoutParams(-1, -1)
     addContentView(flutterView, layoutParams)
    
  5. 在Flutter端入口操作

    void main() => runApp(_widgetForRoute(window.defaultRouteName));
    
    Widget _widgetForRoute(String route) {
      switch (route) {
        case 'route1':
          return SomeWidget(...);
        default:
          return Center(
            child: Text('Unknown route: $route', textDirection: TextDirection.ltr),
          );
      }
    }
    

    至此,集成完畢

兩端通信Flutter Platform Channel的使用

本文主要是介紹使用方式,閑魚團隊詳盡的介紹了實現原理

Flutter提供 MethodChannelEventChannelBasicMessageChannel 三種方式

  1. 類似注冊監聽,發送的模式 原則
  2. 使用順序:先注冊,后發送,否則接收不到。尤其使用 MethodChannelEventChannel 不符合該原則會拋出異常,BasicMessageChannel方式只是收不到消息

方式一 MethodChannel

應用場景:Flutter端 調用 Native端

Flutter端代碼:

 var result = await MethodChannel("com.simple.channelflutterandroid/method", 
                      StandardMethodCodec())
                      .invokeMethod("toast", {"msg": msg})

Android端代碼:

  MethodChannel(flutterView, "com.simple.channelflutterandroid/method",
              StandardMethodCodec.INSTANCE)
             .setMethodCallHandler { methodCall, result ->
        when (methodCall.method) {
             "toast" -> {
                //調用傳來的參數"msg"對應的值
                val msg = methodCall.argument<String>("msg")
                //調用本地Toast的方法
                Toast.makeText(cxt, msg, Toast.LENGTH_SHORT).show()
                //回調給客戶端
                 result.success("native android toast success")
             }
            "other" -> {
               // ...
             }
             else -> {
               // ...
             }
         }
   }
  • 注意點1:兩端需要對應一致的點
    方法名稱:com.simple.channelflutterandroid/method,可以不采取包名,對應一致即可,不同的方式最好不要重復
    傳參key:"msg"

  • 注意點2:以下為Flutter為例,Android同理
    StandardMethodCodec() 非必傳,默認是 StandardMethodCodec(),是一種消息編解碼器

    對于 MethodChannelEventChannel 兩種方式,有兩種編解碼器,均實現自MethodCodec ,分別為 StandardMethodCodecJsonMethodCodec

    對于 BasicMessageChannel 方式,有四種編解碼器,均實現自MessageCodec ,分別為 StandardMessageCodecJSONMessageCodecStringCodecBinaryCodec

  • 注意點3:setMethodCallHandler(),針對三種方式一一對應,屬于監聽
    MethodChannel - setMethodCallHandler()
    EventChannel - setStreamHandler()
    BasicMessageChannel - setMessageHandler()
    其中setStreamHandler()方式稍微特殊,具體查看上面提的閑魚文章

  • 注意點4:FlutterView 實現 BinaryMessenger 接口

以上,以下兩種方法不再贅述

方式二 EventChannel

應用場景:Native端 調用 Flutter端,方式稍微特殊

Flutter端代碼:屬于接收方

   EventChannel("com.simple.channelflutterandroid/event")
           .receiveBroadcastStream()
           .listen((event){
                   print("It is Flutter -  receiveBroadcastStream $event");
   })

注意 receiveBroadcastStream

Android端代碼:屬于發送方

   EventChannel(flutterView, "com.simple.channelflutterandroid/event")
         .setStreamHandler(object : EventChannel.StreamHandler {
               override fun onListen(o: Any?, eventSink: EventChannel.EventSink) {
                     eventSink.success("我是發送Native的消息")
               }

               override fun onCancel(o: Any?) {
                       // ...
               }
   })

方式三 BasicMessageChannel

應用場景:互相調用

兩種使用方式,創建方式和格式不一樣

第一種

Flutter端

    _basicMessageChannel = BasicMessageChannel("com.simple.channelflutterandroid/basic", 
                                                StringCodec())

    // 發送消息
    _basicMessageChannel.send("我是Flutter發送的消息");

    // 接收消息
    _basicMessageChannel.setMessageHandler((str){
        print("It is Flutter -  receive str");
    });

Android端

    val basicMessageChannel = BasicMessageChannel<String>(flutterView, "com.simple.channelflutterandroid/basic", 
                                                          StringCodec.INSTANCE)

    // 發送消息
    basicMessageChannel.send("我是Native發送的消息")

    // 接收消息
    basicMessageChannel.setMessageHandler { o, reply ->
        println("It is Native - setMessageHandler $o")
        reply.reply("It is reply from native")
    }

其中StringCodec(),四種方式可選

第二種

Flutter端

   static const BASIC_BINARY_NAME = "com.simple.channelflutterandroid/basic/binary";

   // 發送消息
   val res = await BinaryMessages.send(BASIC_BINARY_NAME, ByteData(256))

   // 接收消息
   BinaryMessages.setMessageHandler(BASIC_BINARY_NAME, (byteData){
       println("It is Flutter - setMessageHandler $byteData")
   });

Android端

   const val BASIC_BINARY_NAME = "com.simple.channelflutterandroid/basic/binary"

   // 發送消息
   flutterView.send(BASIC_BINARY_NAME,ByteBuffer.allocate(256));

   // 接收消息
   flutterView.setMessageHandler(BASIC_BINARY_NAME) { byteBuffer, binaryReply ->
       println("It is Native - setMessageHandler $byteBuffer")
       binaryReply.reply(ByteBuffer.allocate(256))
   }

此組合可以進行圖片的傳遞

help 在操作中使用此方式傳輸數據總報錯,所以只傳了默認ByteBuffer。還是姿勢不對???目前未發現,求大神指教

如有錯誤之處,萬望各位指出!謝謝

其他

  1. Native端接收方收到消息后都能進行回傳信息,在Flutter進行異步接收
    MethodChannel:result.success("我是回傳信息");
    EventChannel:eventSink.success("我是回傳信息");
    BasicMessageChannel:binaryReply.reply(-);- Flutter端:ByteData;Android端:ByteBuffer

Q&A

以上均為理想情況,過程中還是存在許多問題,以下提供參考

Q:使用命令行flutter create創建的project或者module,文件android/ios為隱藏打點開頭的.android/.ios文件
A:所以有的時候會出現問題,尋找不到文件的情況

Q: flutter create module 和project的區別
A: ?? 目前沒發現

Q:couldn't locate lint-gradle-api-26.1.2.jar for flutter project
A: https://stackoverflow.com/questions/52945041/couldnt-locate-lint-gradle-api-26-1-2-jar-for-flutter-project

Q: Could not resolve all files for configuration ':app:androidApis'.
Failed to transform file 'android.jar' to match attributes {artifactType=android-mockable-jar, returnDefaultValues=false} using transform MockableJarTransform
A:https://github.com/anggrayudi/android-hidden-api/issues/46

Q: Flutter Error: Navigator operation requested with a context that does not include a Navigator
A: https://github.com/flutter/flutter/issues/15919

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,238評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,430評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,134評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,893評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,653評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,136評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,212評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,372評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,888評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,738評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,939評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,482評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,179評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,588評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,829評論 1 283
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,610評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,916評論 2 372

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,631評論 25 708
  • 用兩張圖告訴你,為什么你的 App 會卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 12,775評論 2 59
  • afinalAfinal是一個android的ioc,orm框架 https://github.com/yangf...
    wgl0419閱讀 6,298評論 1 9
  • 我立在陽臺前,窗外風雨飄搖,人流滾滾,生活依然以不變的步伐前行。當贊譽聲像雪片一樣紛紛飛來,那耀眼的黃綠色,風馳電...
    愛笑的美人魚閱讀 930評論 1 2
  • 前幾周都沒有記錄 因為去三亞過年了,然后回來后的那個周末不舒服,于是推遲到今天。 在三亞過年沒啥好說的,每年都會去...
    小梨渦妹閱讀 445評論 1 0