Flutter(七)Flutter与Android通信

因为笔者本身主要从事是Android开发,所以很多角度都是作为一个Android开发者学习Flutter的角度出发,IOS或者H5的开发同学可以选择性阅读

目录

Demo地址:https://github.com/Geekholt/FlutterHybridAndroid

前言

用Flutter这样的跨平台技术进行商业级项目开发时,几乎不可避免的需要和Native进行通信,比如不同平台的底层服务如电量变化、网络连接变化、陀螺仪、传感器等等都有各自不同的实现,以及编译期的一些配置,比如包名、版本号、第三方依赖APPKEY等都需要通过原生的方法去获取。所以学习Native和Flutter的通信方式是非常有必要的

Native和Flutter之间可以通过Platform Channels APIs进行通信,Flutter定义了三种不同类型的Channel

  • MethodChannel:用于传递方法调用(method invocation),一次性通信

  • BasicMessageChannel:用于传递字符串和半结构化的消息,持续通信可回复

  • EventChannel: 用于事件流的发送(event streams),持续通信不可回复

MethodChannel通信

MethodChannel是最常用的Native和Flutter的通信方式,主要用于Flutter调用Native端方法,如调用Native相机功能

为了便于理解,这里我介绍一个前两天在公司项目中实际用到MethodChannel的场景。基本现在Android APP都会涉及到多渠道打包问题,针对不同的渠道,我们可能会在编译脚本(build文件)中进行一些不同的配置。但是Flutter如何才能拿到Android Gradle中的配置信息呢?其实很简单,也就是我们可以先通过Android代码拿到BuildConfig中的数据,再通过Flutter与Android进行通信拿到数据。这种一次性的调用Android中代码的情况就需要用到MethodChannel

Android端

创建MethodChannel,通过setMethodCallHandler接收Flutter端的方法调用

//1.创建android端的MethodChannel
MethodChannel channel = new MethodChannel(messenger, "com.geekholt.hybird/TestMethodChannel");
//2.通过setMethodCallHandler响应Flutter端的方法调用
channel.setMethodCallHandler(new MethodChannel.MethodCallHandler() {
    @Override
    public void onMethodCall(MethodCall call, MethodChannel.Result result) {
        switch (call.method) {
            case "getUmAppKey":
                    //3.返回结果给Flutter端
                result.success(BuildConfig.UMENG_APP_KEY);
                break;
            default:
                result.notImplemented();
        }
    }
});

注:messenger需要在FlutterActivity中使用getFlutterEngine().getDartExecutor()获取

Flutter端

Flutter端同样也有MethodChannel,可以通过类似方法调用的方式,调用Native层的方法,并拿到返回值

//1.创建Flutter端的MethodChannel
MethodChannel _methodChannel = MethodChannel('com.geekholt.hybird/TestMethodChannel');
//2.通过invokeMethod调用Native方法,拿到返回值
void _getChannel(value) async {
  String appKey = await _methodChannel.invokeMethod('getUmAppKey', value);
  print("appKey:" + appKey);
}

这里要注意两点:

  1. ChannelName要与Native端保持一致(即com.geekholt.hybird/TestMethodChannel
  2. MethodName要与Native端保持一致(即getUmAppKey

BasicMessageChannel通信

BasicMessageChannel用于Native和Flutter互相发送消息,一方给另一方发送消息,收到消息之后给出回复

Android给Flutter发送消息

Android端

创建一个BasicMessageChannel,通过send方法发送消息

//1.创建android端的BasicMessageChannel
BasicMessageChannel<String> messageChannel = new BasicMessageChannel<>(messenger, "com.geekholt.hybird/TestBasicMessageChannel", StringCodec.INSTANCE);
//2.向Flutter端发送消息
messageChannel.send(message, new BasicMessageChannel.Reply<String>() {
      @Override
      public void reply(String reply) {
         Log.i(TAG, "收到Flutter的消息回复:" + message);
      }
});

发送的消息会以二进制的形式进行处理,所以要针对不同类型的数据进行二进制编码

编码类型 消息格式
BinaryCodec 发送二进制消息时
JSONMessageCodec 发送Json格式消息时
StandardMessageCodec 发送基本型数据时
StringCodec 发送String类型消息时

Flutter端

Flutter端同样也有BasicMessageChannel,通过setMessageHandler接收并回复消息

//1.创建Flutter端的BasicMessageChannel
BasicMessageChannel<String> _basicMessageChannel = BasicMessageChannel('com.geekholt.hybird/TestBasicMessageChannel', StringCodec());

//2.接收来自Native的消息,并向Native回复
_basicMessageChannel.setMessageHandler((String message) => Future<String>(() {
      return "收到Native的消息:" + message;
}));

Flutter给Android发送消息

Flutter端

在Flutter端我们也可以通过send方法向Native发送消息,方法的返回值就是Native端的消息回复

注意flutter和Native的通信都是异步的

void _sendMessage(value) async {
  String response = await _basicMessageChannel.send(value);
  print("收到Native的消息回复:"+ response);
}

Android端

android端通过setMessageHandler设置消息处理器,处理来自Dart的消息,收到消息后通过reply进行回复

messageChannel.setMessageHandler(new BasicMessageChannel.MessageHandler<String>() {
    @Override
    public void onMessage(String message, BasicMessageChannel.Reply<String> reply) {
        //通过reply进行回复
        reply.reply("BasicMessageChannel收到:" + message);
    }
});

EventChannel通信

EventChannel用于从Native向Flutter发送通知事件,例如Flutter通过其监听Android的重力感应变化等。与MethodChannel不同,EventChannel是Native到Flutter的单向调用,调用是一对多的,类似Android的BrodcastReceiver

Android端

创建一个EventChannel,在StreamHandler#onLister回调中获取EventSink引用并保存,当重力感应发送变化时,通过eventSink.success向Flutter端发送消息

private EventChannel.EventSink eventSink;

void registerWith(BinaryMessenger messenger) {
    //1.创建Android端的EventChannel
    EventChannel eventChannel = new EventChannel(messenger, "com.geekholt.hybird/TestEventChannel");
    //2.在StreamHandler#onLister回调中获取EventSink引用并保存
    eventChannel.setStreamHandler(new EventChannel.StreamHandler() {
        @Override
        public void onListen(Object arguments, EventChannel.EventSink events) {
            eventSink = events;
        }

        @Override
        public void onCancel(Object arguments) {
            eventSink = null;
        }
    });
}

//3.调用eventSink.success向Flutter端发送消息
void send(Object params) {
    if (eventSink != null) {
        eventSink.success(params);
    }
}

Flutter端

Flutter端接收消息如下所示,要注意使用EventChannel时需要在页面销毁时取消监听,防止内存泄漏

//1.创建Flutter端EventChannel
EventChannel _eventChannelPlugin = EventChannel('com.geekholt.hybird/TestEventChannel');
//2.EventChannel#receiveBroadcastStream注册listener,建立监听
StreamSubscription _streamSubscription = _eventChannelPlugin
    .receiveBroadcastStream()
    .listen(_onEventSuccess, onError: _onEventError);

//3.成功和错误回调
void _onEventSuccess(message) {
  print(message);
}
void _onEventError(error) {
  print(error);
}

//4.注意:页面销毁时需要取消监听,防止内存泄漏
@override
void dispose() {
  if (_streamSubscription != null) {
    _streamSubscription.cancel();
    _streamSubscription = null;
  }
  super.dispose();
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335