MethodChannel

  • 使用VS2019与fluter通过MethodChannel进行双向通信
    • VS端
    • flutter端

使用VS2019与fluter通过MethodChannel进行双向通信

flutter是一个比较新的框架,由谷歌于2018年推出,前期主要应用于移动端,目前也支持PC端开发,但是网上的资料多数都是移动端相关的,笔者也是刚接触flutter一周,在项目中需要使用flutter做一个windows的项目,需要使用flutter与windows进行交互,这里采用的是flutter插件的方式,部分代码是由插件模板自动创建,这里就直接贴出代码,并没有给出注释,如果有小伙伴感兴趣可以去看看官方的文档,这里不再赘述。言归正传,当笔者浏览了国内外网站后,发现关于windows端的资料甚少,不得已只能自己探索,由于是自己研究,所以难免有不对的地方,欢迎指正, 也希望能给初学者带来一点帮助!

VS端

这里笔者使用的是VS2019其他版本大同小异,首先是接收来自flutter端的函数调用代码:

std::unique_ptr<flutter::MethodChannel<flutter::EncodableValue>,std::default_delete<flutter::MethodChannel<flutter::EncodableValue>>>channel = nullptr;
// static
void IptunctrlPlugin::RegisterWithRegistrar(flutter::PluginRegistrarWindows *registrar)
{channel = std::make_unique<flutter::MethodChannel<flutter::EncodableValue>>(registrar->messenger(), "iptunctrl",&flutter::StandardMethodCodec::GetInstance());auto plugin = std::make_unique<IptunctrlPlugin>();channel->SetMethodCallHandler([plugin_pointer = plugin.get()](const auto &call, auto result) {plugin_pointer->HandleMethodCall(call, std::move(result));});registrar->AddPlugin(std::move(plugin));
}void IptunctrlPlugin::HandleMethodCall(const flutter::MethodCall<flutter::EncodableValue> &method_call,std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {if (method_call.method_name().compare("getPlatformVersion") == 0) {//模板自动生成的获取系统版本的方法std::ostringstream version_stream;version_stream << "Windows ";if (IsWindows10OrGreater()) {version_stream << "10+";}else if (IsWindows8OrGreater()) {version_stream << "8";}else if (IsWindows7OrGreater()) {version_stream << "7";}result->Success(version_stream.str());}else if (method_call.method_name().compare("Test") == 0)        {//自定义Test方法 无参数,返回字符串Test();    //调用自定义C++函数result->Success(flutter::EncodableValue("version_stream.str()"));}else if (method_call.method_name().compare("GetNum") == 0) {//自定义GetNum方法 无参数,返回整形int n = GetNum();    //调用自定义C++函数result->Success(flutter::EncodableValue(n));}else if (method_call.method_name().compare("GetAdd") == 0) {//自定义GetAdd方法 整形参数,返回整形const flutter::EncodableList* arguments = std::get_if<flutter::EncodableList>(method_call.arguments());if (!arguments){result->Error("arguments error");return;}//获取参数1 intint arg1 = std::get<int>(arguments->at(0));//获取参数2 doubledouble arg2 = std::get<double>(arguments->at(1));//获取参数3 char*char* p = const_cast<char*>(std::get<std::string>(arguments->at(2)).c_str());int n = GetAdd(arg1,arg2,p);//调用自定义C++函数带入参数 并获取返回值result->Success(n); //传入返回值}else if (!method_call.method_name().compare("RetList")) {//自定义RetList方法 无参,返回列表数据flutter::EncodableList r;RetList(r);//调用自定义C++函数 并填充listresult->Success(r);//直接传回list}else if (!method_call.method_name().compare("RetMap")) {//自定义RetMap方法 无参,返回mapflutter::EncodableMap r;RetMap(r);//调用自定义C++函数 并填充MAPresult->Success(r);//直接返回map}else {result->NotImplemented();   //返回未定义的方法}
}

接下来我们来看下PC端是如何调用flutter的,调用其实也不复杂,通过InvokeMethod就可以实现,我们先来看下这个方法的声明:

void InvokeMethod(const std::string& method,     //传入需要调用的方法名std::unique_ptr<T> arguments,         //传入参数,这个参数可以是单个参数也可以是list或mapstd::unique_ptr<MethodResult<T>> result = nullptr)//最后这个参数是获取调用返回值的,笔者也是卡在这个位置

这里笔者重载了几个调用方法:

void IptunctrlPlugin::Call(std::string _function,flutter::EncodableValue* result)
{//无参调用if (!result){//无返回值调用channel->InvokeMethod(_function, std::make_unique<flutter::EncodableValue>(nullptr));return;}//这里主要是同步等待返回结果auto res = std::make_unique<ResultValue<flutter::EncodableValue>>(result);HANDLE hEvent = res->GetHandle();//获取当前对象的event句柄channel->InvokeMethod(_function, nullptr, std::move(res));ResultValue<>::Wait(hEvent);    //等待调用结束
}void IptunctrlPlugin::Call(std::string _function, flutter::EncodableValue* argument, flutter::EncodableValue* result)
{//单个参数调用if (!result){//无返回值调用channel->InvokeMethod(_function, std::make_unique<flutter::EncodableValue>(*argument));return;}//这里主要是同步等待返回结果auto res = std::make_unique<ResultValue<flutter::EncodableValue>>(result);HANDLE hEvent = res->GetHandle();//获取当前对象的event句柄channel->InvokeMethod(_function, std::make_unique<flutter::EncodableValue>(*argument), std::move(res));ResultValue<>::Wait(hEvent);//等待调用结束
}void IptunctrlPlugin::Call(std::string _function, flutter::EncodableList* arguments, flutter::EncodableValue* result)
{//参数为list的调用if (!result){//无返回值调用channel->InvokeMethod(_function, std::make_unique<flutter::EncodableValue>(*arguments));return;}//这里主要是同步等待返回结果auto res = std::make_unique<ResultValue<flutter::EncodableValue>>(result);HANDLE hEvent = res->GetHandle();//获取当前对象的event句柄channel->InvokeMethod(_function, std::make_unique<flutter::EncodableValue>(*arguments), std::move(res));ResultValue<>::Wait(hEvent);//等待调用结束
}void IptunctrlPlugin::Call(std::string _function, flutter::EncodableMap* arguments, flutter::EncodableValue* result)
{//参数为map的调用if (!result){//无返回值调用channel->InvokeMethod(_function, std::make_unique<flutter::EncodableValue>(*arguments));return;}//这里主要是同步等待返回结果auto res = std::make_unique<ResultValue<flutter::EncodableValue>>(result);HANDLE hEvent = res->GetHandle();//获取当前对象的event句柄channel->InvokeMethod(_function, std::make_unique<flutter::EncodableValue>(*arguments), std::move(res));ResultValue<>::Wait(hEvent);//等待调用结束
}

重点来了,下面就是如何获取返回值,以及同步调用方法,这里为了方便,笔者使用的是list返回,这个部分资料极少,也可能是我搜索的方式不对,总之…

template <typename T = flutter::EncodableValue>
class ResultValue :public flutter::MethodResult<T> {HANDLE m_hEvent;//每个调用都使用一个event来控制同步flutter::EncodableValue* m_value;    //返回值指针
public:ResultValue(T* value) :m_value(value) {m_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); //构造对象的同时创建事件句柄}~ResultValue() {}       //不在析构的时候释放事件句柄HANDLE GetHandle() { return m_hEvent; }  //获取当前对象对应的事件句柄,同步时使用static void Wait(HANDLE hEvent) {   //静态函数,等待返回值//flutter采用的是异步,如果这里直接等待的话会导致线程卡死,后续也不会在接收到返回值,所以这里需要手动调用循环来保证返回值以及UI的正常运作::MSG msg;            while (::GetMessage(&msg, nullptr, 0, 0)) {::MSG msg;       //此处要考虑是在工作线程做没有消息循环的情况需要手动调用PeekMessage 开启线程消息循环PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);::TranslateMessage(&msg);::DispatchMessage(&msg);if (WAIT_OBJECT_0 == WaitForSingleObject(hEvent, 10)){//如果获取到返回值则跳出循环并且关闭事件句柄,一次调用接近尾声if (hEvent) CloseHandle(hEvent);break;}}}
protected:// 重写父类方法 调用成功 返回值解析方法void SuccessInternal(const T* result) override {const flutter::EncodableList* res = std::get_if<flutter::EncodableList>(result);flutter::EncodableList* value = reinterpret_cast <flutter::EncodableList*>(m_value);value->push_back(flutter::EncodableValue((int)0));value->push_back(std::move(*res));SetEvent(m_hEvent); //通知主业务同步调用结束PostThreadMessage(m_curThreadId, WM_NULL, NULL, NULL);     //一旦有返回 通过空消息来激活线程消息  UI线程中也没有影响}// 重写父类方法 调用失败,返回错误信息void ErrorInternal(const std::string& error_code,const std::string& error_message,const T* error_details) override {flutter::EncodableList* value = reinterpret_cast <flutter::EncodableList*>(m_value);value->push_back(flutter::EncodableValue((int)1));value->push_back(flutter::EncodableValue(error_code.c_str()));value->push_back(flutter::EncodableValue(error_message.c_str()));value->push_back(flutter::EncodableValue(error_details));SetEvent(m_hEvent);//通知主业务同步调用结束PostThreadMessage(m_curThreadId, WM_NULL, NULL, NULL);    //一旦有返回 通过空消息来激活线程消息  UI线程中也没有影响}// 重写父类方法 调用函数名未定义void NotImplementedInternal() override {flutter::EncodableList* value = reinterpret_cast <flutter::EncodableList*>(m_value);value->push_back(flutter::EncodableValue((int)2));SetEvent(m_hEvent);//通知主业务同步调用结束PostThreadMessage(m_curThreadId, WM_NULL, NULL, NULL);   //一旦有返回 通过空消息来激活线程消息  UI线程中也没有影响}
};

从上面的代码中可以看出,我们定义了一个MethodResult的派生类,实际上也是通过这个派生类来实现的消息接收,由于flutter采用的是异步,所以如果要等待每次调用的返回值需要手动实现消息循环,否则消息会永远阻塞在WaitForSingleObject,导致重写的三个返回值函数无法被回调!

flutter端

flutter端的资料就比较多了 这里就直接贴上代码:

 Future<void> NotImplemented() {throw MissingPluginException(null);        //抛出MissingPluginException异常,flutter将返回未定义的方法}@overrideFuture<dynamic> nativeMessageListener() async {methodChannel.setMethodCallHandler((call) {//处理原生 发送过来的消息switch (call.method) {case "TestFunction":{//单个参数则直接获取int arguments = call.arguments;print(arguments);//如果参数是map类型则:/*int code = call.arguments["id"];String message = call.arguments["message"];//可以直接刷新界面setState(() {recive += " code $code message $message and method $method ";print(recive);});*///如果参数是list类型则:/*int code = call.arguments[0];String message = call.arguments[1];*/String aaa = "333";return Future.value([1, '123', 5.0]);}case "RetValue":{//返回单个值:return Future.value("aaa");//return Future.value(123);//返回list://return Future.value([1, '123', 5.0]);//返回map//return Future.value({"id":1, "message":'123', "double":5.0});}default:{return NotImplemented();//这里也是一个坑 如果要返回未定义的方法 需要抛出一个异常}}});}

以上就是关于VS2019与Flutter 通过MethodChannel双向通信的全部内容,如有错误请指出

创作不易,转载请注明出处!

VS2019与fluter通过MethodChannel进行双向通信(原创)相关推荐

  1. Flutter通过MethodChannel实现Flutter 与Android iOS 的双向通信

    更多文章请查看 flutter从入门 到精通 本文章中的完整代码在这里 题记:不到最后时刻,千万别轻言放弃,无论结局成功与否,只要你拼博过,尽力过,一切问心无愧. Flutter 与 Android ...

  2. 基于VS2019 C++的跨平台(Linux)开发(1.5)——管道

    一.管道概述 1.1.管道概念 管道是Unix中最古老的进程间通信的形式.我们把从一个进程连接到另一个进程的一个数据流(文件IO流)称为一个"管道". 1.2.管道特点 管道是半双 ...

  3. 【原创】新手入门一篇就够:从零开发移动端IM

    一.前言 IM发展至今,已是非常重要的互联网应用形态之一,尤其移动互联网时代,它正以无与论比的优势降低了沟通成本和沟通代价,对各种应用形态产生了深远影响. 做为IM开发者或即将成为IM开发者的技术人员 ...

  4. flutter ios打包_Flutter通过BasicMessageChannel与Android iOS 的双向通信

    更多文章请查看 flutter从入门 到精通 本文章中的完整代码在这里 题记:不到最后时刻,千万别轻言放弃,无论结局成功与否,只要你拼博过,尽力过,一切问心无愧. 通过 Flutter 来进行移动应用 ...

  5. android蓝牙通信_Flutter通过BasicMessageChannel实现Flutter 与Android iOS 的双向通信

    题记: --不到最后时刻,千万别轻言放弃,无论结局成功与否,只要你拼博过,尽力过,一切问心无愧. 通过 Flutter 来进行移动应用开发,打包 Android .iOS 双平台应用程序,在调用如相机 ...

  6. VS2019配置opencv详细图文教程和测试代码

    摘要: vs2019新鲜出炉,配置opencv又有哪些不一样呢,这个教程将会一步一步的教你如何配置opencv和跑动opencv一个简单的项目. 测试代码请在原文找到,转发备注原文链接:https:/ ...

  7. Flutter通过BasicMessageChannel实现Flutter 与Android iOS 的双向通信

    更多文章请查看 flutter从入门 到精通 本文章中的完整代码在这里 题记: -- 不到最后时刻,千万别轻言放弃,无论结局成功与否,只要你拼博过,尽力过,一切问心无愧. Flutter 与 Andr ...

  8. Flutter 即学即用系列博客——09 MethodChannel 实现原生与 Flutter 通信(二)

    前言 上一篇我们讲解了如何通过 EventChannel 实现 Android -> Flutter 的通信. 并且也看到了 Flutter 内部 EventChannel 源码也是对 Meth ...

  9. 解决VS2019中.net core WPF 暂时无法使用 Designer 的临时方法

    目录 解决 VS2019 中.net core WPF 暂时无法使用 Designer 的临时方法 安装 vs 2019 professional/enterprise版本 在vs的设置里,勾选.NE ...

最新文章

  1. 笑出腹肌的注释,都是被代码耽误的诗人!
  2. [Tyvj 1729] 文艺平衡树
  3. App推广中如何寻找200个以上渠道
  4. js中父窗口获得模态窗口的返回值
  5. Java中的观察者设计模式
  6. lintcode-137-克隆图
  7. 超全、超详的Spring Boot配置讲解笔记
  8. 双榜首!华为云擎天架构刷新进化计算大赛新纪录!
  9. CTP Java 版(Swig)
  10. 多多客接入(拼多多)
  11. Linux系统重要日志文件
  12. Dev C++下载安装
  13. pdf在线浏览器pdf viewer
  14. 组态王通过TCP和MCGS触屏通讯
  15. docker镜像制作、数据管理
  16. 计算机类的本科学校有哪些专业考研,计算机专业考研学校推荐有哪些
  17. 智慧城市解决方案(智慧城市系统及相关技术)
  18. 最新!SPDK宣布在NVMe-oF Fabrics中支持TCP transport
  19. Flutter 淡入淡出效果
  20. c语言看门狗指令pic,PIC指令介绍

热门文章

  1. NOR 与 NAND的区别对比分析
  2. TAThermalSystem-车辆热管理系统库(一)
  3. 服务器常用状态码及其含义
  4. 简单计算器(Java实训)
  5. INFO zkclient.ZkEventThread - Starting ZkClient
  6. ajax的跨域和请求——详解
  7. 大数据分析软技能有哪些
  8. Hadoop 中的数据类型
  9. Ubuntu16.04调整屏幕分辨率至1920*1080
  10. Synergistic Saliency and Depth Prediction for RGB-D Saliency Detection