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