flutter 與native通訊初探

散人丶發表於2019-07-24

flutter 從入門到放棄

背景

從搭建環境到專案開發,入坑flutter已經快一週了,不得不說,從android原生開發者角度來說,相對於其他的跨平臺方案,不管是效能,UI渲染還是學習成本,flutter還是相對比較友好的,內部維護幾套UI邏輯,skia引擎渲染,而不依賴於原生控制元件的侷限性,Hotload開發快捷等等,但我們要明白一點,flutter始終是一個跨平臺的UI方案,最終還是要根據平臺生成.apk(android)/.ipa(ios)包的,所以在涉及到一些系統平臺的介面或者資料,比如系統電量什麼的,還是需要native層去搞定的,再將資料返回給flutter層去展示,所以難免就會出現flutter與native的通訊問題,那麼Flutter是如何做到的呢?答案是Platform Channels

Platform Channels

1975877-6079b324ae9d7bf7

上圖來自Flutter官網,表明了Platform Channels的架構示意圖。有細心的同學就要問了,你不是說Flutter和Native通訊是通過Platform Channels嗎?怎麼架構圖裡面連線他們的是MethodChannel? 其實呢,MethodChannel是Platform Channels中的一種,顧名思義,MethodChannel用起來應該和方法呼叫差不多。那麼還有別的channel?有的,還有EventChannel,BasicMessageChannel等。如果你需要把資料從Native平臺傳送給Flutter,推薦你使用EventChannel。Flutter framework也是在用這些通道和Native通訊

例子1:flutter呼叫android logcat

雖然flutter本身提供了2種日誌輸出方式,print(),debugprint(),但是對於android開發者來說還是不太習慣,而且資訊冗餘在console欄裡面,沒法過濾等等,所以可以通過這個Channels去呼叫android原生的logcat

Flutter端
import 'package:flutter/services.dart';

class LogUtils {
  static const perform = const MethodChannel("android_log");

  static void v(String tag, String message) {
    perform.invokeMethod('logV', {'tag': tag, 'msg': message});
  }

  static void d(String tag, String message) {
    perform.invokeMethod('logD', {'tag': tag, 'msg': message});
  }

  static void i(String tag, String message) {
    perform.invokeMethod('logI', {'tag': tag, 'msg': message});
  }

  static void w(String tag, String message) {
    perform.invokeMethod('logW', {'tag': tag, 'msg': message});
  }

  static void e(String tag, String message) {
    perform.invokeMethod('logE', {'tag': tag, 'msg': message});
  }
}
複製程式碼

可以看到,程式碼很簡單,初始化一個MethodChannel物件,然後去呼叫invokeMethod方法,傳入引數即可

android端
public class MainActivity extends FlutterActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        GeneratedPluginRegistrant.registerWith(this);
        new MethodChannel(getFlutterView(),CHANNEL).setMethodCallHandler(new MethodChannel.MethodCallHandler() {
            @Override
            public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
                String tag = methodCall.argument("tag");
                String msg = methodCall.argument("msg");
                switch (methodCall.method) {
                    case "logV":
                        Log.v(tag,msg);
                        break;
                    case "logD":
                        Log.d(tag,msg);
                        break;
                    case "logI":
                        Log.i(tag,msg);
                        break;
                    case "logW":
                        Log.w(tag,msg);
                        break;
                    case "logE":
                        Log.e(tag,msg);
                        break;
                    default:
                        Log.d(tag,msg);
                        break;
                }
            }
        });
}

複製程式碼

這裡也是建立一個MethodCallHandler物件,在回撥中收到MethodCall物件,取出對應的method和arguments,這裡判斷method來呼叫android本身的log方法即可。

例子2:android推送訊息到flutter

因為現在其實大部分都是flutter和native原生開發,所以有很多flutter需要主動去推送訊息給native層,native層就可以建立EventChannel來監聽與flutter的狀態,再通過EventSink物件回覆訊息obj

android端
new EventChannel(getFlutterView(), "com.flutter/notify").setStreamHandler(
                new EventChannel.StreamHandler() {
                    private TokenReceiver tokenReceiver;
                    @Override
                    public void onListen(Object args, final EventChannel.EventSink events) {
                        Log.e("tag", "adding listener");
                        events.success("data callback");
                    }

                    @Override
                    public void onCancel(Object args) {
                        Log.e("tag", "cancelling listener");
                    }
                }
        );
複製程式碼
flutter
static const EventChannel eventChannel = EventChannel('com.flutter/notify');
@override
  void initState() {
    // TODO: implement initState
    super.initState();
    //初始化監聽
   eventChannel.receiveBroadcastStream().listen(_onDataBack, onError: _onError);
  }
void _onError(Object error){

  }
void _onDataBack(String callback) {
   print(callback)
  }
複製程式碼

程式碼也很簡單,建立相同Channel名字的EventChannel,監聽到資料做相應的邏輯即可

相關文章