22.原生專案和Flutter的混合開發(三)

CoorChice發表於2019-03-22

目錄傳送門:《Flutter快速上手指南》先導篇

通過閱讀 混合開發(一)混合開發(二) ,相信你已經讓一個 原生 + Flutetr 的混合應用執行起來了。

恭喜你 ???!

現在,你可能遇到了 Flutter程式碼 和 原生程式碼 之前無法互相呼叫的難題。

因為 Flutter 作為獨立於原生 Android 的一套開發框架,肯定是不能直接互相呼叫和愉快的交換資訊的。

現在,來看看 Flutter 是如何解決這些問題的。

1.Platform Channels

Flutter 使用 Platform Channels 架構來實現 Flutter 和 原生 之間的通訊。

上圖是其中 MethodChannel 的架構示意圖,Flutter 可以通過 MethodChannel 非同步的傳送和接收資訊。

MethodChannel 是經過封裝的比較方便的通訊方式,Flutter 官網的例子也是通過 MethodChannel 來實現的。

Platform Channels 僅允許以下幾種的資料型別在通訊中使用:

DartAndroidiOS
nullnullnil (NSNull when nested)
booljava.lang.BooleanNSNumber numberWithBool
intjava.lang.IntegerNSNumber numberWithInt
int, if 32 bits not enoughjava.lang.LongNSNumber numberWithLong
doublejava.lang.DoubleNSNumber numberWithDouble
Stringjava.lang.StringNSString
Uint8Listbyte[]FlutterStandardTypedData typedDataWithBytes
Int32Listint[]FlutterStandardTypedData typedDataWithInt32
Int64Listlong[]FlutterStandardTypedData typedDataWithInt64
Float64Listdouble[]FlutterStandardTypedData typedDataWithFloat64
Listjava.util.ArrayListNSArray
Mapjava.util.HashMapNSDictionary

2.如何使用 MethodChannel

MethodChannel 通過特定的通道,來建立起 Flutter 和 Native 之間通訊橋樑。

當然,我們需要在 Flutter 和 Native 兩端都需要定義相同的通道。

2.1 第一步:定義通訊通道

  • Flutter 端:

    先匯入 import 'package:flutter/services.dart'; 包,然後建立一個 MethodChannel。

    const channel = MethodChannel('foo');
    複製程式碼
  • Native - Android 端:

    MethodChannel channel = new MethodChannel(flutterView, "foo");複製程式碼
  • Native - iOS 端:

    let channel = FlutterMethodChannel(
      name: "foo", binaryMessenger: flutterView)
    複製程式碼

建立一個通訊通道的方式很簡單,只需要使用相同的名稱(比如上面例子中的 "foo")建立 MethodChannel 就行。

在一個大型的專案中。你可能會需要建立很多的通訊通道,所以建議統一的管理這些通訊通道。

2.2 Flutter to Native

建立好通訊通道,來看看如何讓 Flutter 主動和 Native 通訊。

  • Flutter 端:

    final String greeting = await channel.invokeMethod('bar', 'world');
    print(greeting);複製程式碼

    通過 invokeMethod(<標識>, <資料>) 函式可以主動發起和 Native 的一次通訊,且能夠獲得響應,允許的資料型別就是前面表格中列出的資料型別。

    當然,為了不阻塞 UI,你需要在非同步中進行。

  • Native - Android 端:

    channel.setMethodCallHandler((methodCall, result) -> {
        if (methodCall.method.equals("bar")) {
            result.success("success, " + methodCall.arguments);
        }
    });複製程式碼

    在 Native 端,通過為 MethodChannel 設定一個處理器 MethodCallHandler

    當 Flutter 向 Native 發起通訊時,能夠回撥處理器中的 onMethodCall() 函式。

    在該回撥中,能夠通過 MethodCall 獲取 Flutter 傳送過來的資訊,通過 MethodChannel.Result 來向 Flutter 傳送響應結果。

  • Native - iOS 端:

    channel.setMethodCallHandler {
      (call: FlutterMethodCall, result: FlutterResult) -> Void in
      switch (call.method) {
      case "bar": result("Hello, \(call.arguments as! String)")
      default: result(FlutterMethodNotImplemented)
      }
    }
    複製程式碼

2.3 Native to Flutter

  • Flutter 端:

    設定接收 Native 資訊的處理器:

    channel.setMethodCallHandler((MethodCall call) async {
      switch (call.method) {
        case 'bar':
          return 'Hello, ${call.arguments}';
        case 'baz':
          throw PlatformException(code: '400', message: 'This is bad');
        default:
          throw MissingPluginException();
      }
    })
    複製程式碼

    通過 setMethodCallHandler 函式設定一個 Future<dynamic> handler(MethodCall call) 函式。

    該函式會在接收到 Native 資訊時被呼叫,從 MethodCall 中能夠獲得 Native 傳送過來的資料。

    最後的 return 環節可以返回資料給 Native。

  • Native - Android 端:

    channel.invokeMethod("bar", "message", new MethodChannel.Result
        @Override
        public void success(@Nullable Object o) {
            // 傳送成功時回撥
        }
        @Override
        public void error(String s, @Nullable String s1, @Nullable
            // 傳送失敗時回撥
        }
        @Override
        public void notImplemented() {
            // 如果該通道在Flutter端未實現,會回撥這裡
        }
    });
    複製程式碼

    第一個引數是 Flutter 端通過 call.method 獲得的標示。

    第二個引數是需要傳送的資料。

    第三個引數用於監聽通訊是完成狀態。

  • Native - iOS 端:

    channel.invokeMethod(name, arguments: value) {
      (result: Any?) -> Void in
      if let error = result as? FlutterError {
        os_log("%@ failed: %@", type: .error, name, error.message!)
      } else if FlutterMethodNotImplemented.isEqual(result) {
        os_log("%@ not implemented", type: .error, name)
      } else {
        os_log("%@", type: .info, result as! NSObject)
      }
    }複製程式碼

目錄傳送門:《Flutter快速上手指南》先導篇

如何找到我?

傳送門:CoorChice 的主頁

傳送門:CoorChice 的 Github


相關文章