Flutter桌面开发windows插件开发

目录
  • 前言
  • 插件介绍
  • windows插件编写
  • Windows插件的一些坑

前言

通过此篇文章,你将了解到:

Flutter插件的基本介绍;

windows插件开发的真实踩坑经验。

我们都知道,Flutter的定位更多是作为一个跨平台的UI框架,对于原生平台的功能,开发过程中经常需要插件来提供。不幸的是Windows的生态又极其不完整,插件开发必不可少。但网上windows的文章少之又少,所以本篇文章,我们一起来聊聊插件开发的一些技巧。

插件介绍

Flutter的插件主要分两种:package和plugin。

  • Package是纯dart代码的库,不涉及原生平台的代码;
  • Plugin是原生插件库,是一种特殊的Package。Plugin需要开发者分别在各原生平台实现对应的能力。

其中Plugin是我们要着重讲的,既然是原生平台实现,那跟dart层就势必需要通讯。Flutter Plugin的通讯主要有:methodChannel、eventChannel、basicMessageChannel。

  • MethodChannel:同步调用的通道,调用后可以通过result返回结果。可以 Native 端主动调用,也可以Flutter主动调用,属于双向通信。这种通信方式是我们日常开发中为最常用的方式, 关键点是Native 端的调用需要在主线程中执行。
  • EventChannel:异步事件通知的通道,一般是Native端主动发出通知,Flutter接收通信信息。
  • BasicMessageChannel:长链接的通道,双端可以随时发出消息,对方收到消息后可以使用reply进行回复。一般常用于需要双向通信可不知道何时需要发送的场景。

windows插件编写

Flutter Android的生态算是比较完整的,而且网上95%的插件文章,都是以移动端为主,对于不熟悉Windows开发的同学极度不友好。因此本篇文章我们不讲Android端的实现,重点讲Windows端的实践,不过我也不是C++技术栈的,只能浅浅分享我踩过的坑。

  • 如何创建通信通道?
// MethodChannel
void XXXPlugin::RegisterWithRegistrar(
	flutter::PluginRegistrarWindows* registrar) {
        // 创建一个MethodChannel
	auto channel =
		std::make_unique<flutter::MethodChannel<flutter::EncodableValue>>(
			registrar->messenger(), "usb_tool",
			&flutter::StandardMethodCodec::GetInstance());
        // 创建插件对象
	auto plugin = std::make_unique<XXXPlugin>();
        // 把通道设置给插件,同时传入消息的处理入口
	channel->SetMethodCallHandler(
		[plugin_pointer = plugin.get()](const auto& call, auto result) {
		plugin_pointer->HandleMethodCall(call, std::move(result));
	});
}
// EventChannel
// 创建事件流处理对象
auto eventHandler = std::make_unique<
StreamHandlerFunctions<EncodableValue>>(
	[plugin_pointer = plugin.get()](
		const EncodableValue* arguments,
		std::unique_ptr<EventSink<EncodableValue>>&& events)
		-> std::unique_ptr<StreamHandlerError<EncodableValue>> {
			return plugin_pointer->OnListen(arguments, std::move(events));
	},
	[plugin_pointer = plugin.get()](const EncodableValue* arguments)
		-> std::unique_ptr<StreamHandlerError<EncodableValue>> {
			return plugin_pointer->OnCancel(arguments);
	});
// 创建EventChannel对象
auto eventChannel = std::make_unique<flutter::EventChannel<flutter::EncodableValue>>(
	registrar->messenger(), eventChannelName,
	&flutter::StandardMethodCodec::GetInstance());
// 把通道设置给插件
eventChannel->SetStreamHandler(std::move(eventHandler));

最后我们还需要把插件注册进项目中

registrar->AddPlugin(std::move(plugin));
  • 如何处理消息? 在上面创建的过程中,其实已经把处理方法的传递给插件了。
// MethodChannel的处理
// result即通信的对象
void XXXPlugin::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->Succes回复消息
		result->Success(flutter::EncodableValue(version_stream.str()));
	} else {
		result->NotImplemented();
	}
}
// 主动向Flutter端发送消息
std::unique_ptr < flutter::StreamHandlerError<flutter::EncodableValue>> XXXPlugin::OnListen(const flutter::EncodableValue* arguments,
	std::unique_ptr<flutter::EventSink<flutter::EncodableValue>>&& events) {
	// 主动发送
	events_.reset(events.release());
	return nullptr;
}
// Flutter取消监听时触发
std::unique_ptr < flutter::StreamHandlerError<flutter::EncodableValue>> UsbToolPlugin::OnCancel(const flutter::EncodableValue* arguments) {
	return nullptr;
}

BasicMessageChannel我暂时还没有用过,这里就不做记录了。但是看C++的api,还是很简单就能找到的。至于Flutter端的,无需多言。只要通信层连通了,其他想怎么玩都可以。

Windows插件的一些坑

这是本篇文章的重点。我们都知道Flutter是单线程的机制,来到原生平台也一样,Platform是运行在Flutter的主线程的,自然是不能做任何耗时的,不然会卡住主线程,系统会把我们认为无响应的应用,从而杀死应用。

我们经常会在使用windows插件时,感觉点击卡顿,其实就是很多插件没有做这个处理,导致事件队列等待调度。这主要是因为在windows的开发习惯上,耗时操作会丢到子线程异步执行,然后主线程如何等待执行结果?使用while一直去查询是否执行完成,这在windows上成为挂起。

不过一个有趣的现象是:当有耗时操作的时候,Flutter的动画是可以流程播放的,但是点击事件却卡住了,这时候C++的同学就会扯,你看动画都是流程的,问题肯定出在Flutter上?其实是因为动画在Flutter中属于微任务,它的优先级是高于事件队列的。而while也是分配到事件队列中,所以动画优先执行,点击却需要一直等到while结束。

在Android中,为了避免这个问题,我们一般会使用协程,把耗时操作丢给协程,让系统帮我们进行任务调度,通过await拿到执行完之后的结果,再把结果返回给dart层。整个机制其实还是保留了flutter的单线程机制,从而避免了卡顿问题。

在Windows端,其实也有协程这个概念,比如WinRT、C++都有提供协程的能力。但问题在于协程这个东西,对于C++来说太新了,同时C++的历史包袱实在太重,到现在还是用着很老版本的库。这就导致很多C++的库没办法迁移到协程这种方式,至少在我现在的业务中,切换成本极高,几乎没办法完成。

但问题总得解决,目前我们主要使用异步通知的方式,来解决这个问题。此异步是真异步,非flutter单线程任务调度的异步。我们会把耗时的操作丢给子线程,但是我们不再通过while进行异步转同步,而是在子线程中,主动通过channel去通知会Dart层。

if (*method == "getAsync") {
            async_pipe_stream_->Get(request, std::bind(&XXXPlugin::OnResponse, this, std::placeholders::_1, *uuid));
            // 直接返回true,但真正的执行结果再OnResponse中主动返回
            result->Success(EncodableValue(true));
            return;
        }

在插件的dart代码中,我们需要主动创建一个MethodChannel的接收器,异步接收到后,通过执行业务端传入的回调通知回去。

class NativePlugin {
  static const MethodChannel _channel =
      MethodChannel('com.open.flutter/xxx/xxx');
  static NativePlugin? _instance;
  // 获取实例,单例
  static NativePlugin getInstance({String defaultToken = _token}) {
    _instance ??= NativePlugin._internal(defaultToken);
    return _instance!;
  }
  // 私有命名构造函数,做一次初始化
  NativePlugin._internal(String defaultToken) {
    _defaultToken = defaultToken;
    _channel.setMethodCallHandler((MethodCall call) async {
      if (call.method == 'onResponse') {
        final arguments = Map<String, dynamic>.from(call.arguments);
        // 执行业务端传入的回调
        await _onResponse(arguments);
      }
    });
  }

插件的Flutter层需要接收/维护回调列表,不过此方式有隐患,传入的回调容易造成闭包问题,增加一些内存泄露的风险;

但是对于没办法使用协程的C++插件来说,此方案确实可以解决不少问题。

以上就是Flutter桌面开发windows插件开发的详细内容,更多关于Flutter windows插件开发的资料请关注我们其它相关文章!

(0)

相关推荐

  • Android使用Flutter实现录音插件

    目录 安卓部分 手动注册 Android和Dart的通讯 安卓录音 Dart module部分 iOS部分 手动注册插件 iOS插件 Dart调用部分 原生提供功能,Dart module 通过 method channel 异步调用 安卓部分 手动注册 Flutter 官方的做法,就是自动注册插件, 很方便 手动注册,体现本文的不同 插件是 AudioRecorderPlugin class MainActivity: FlutterActivity() { override fun onCr

  • 基于flutter sound插件实现录音与播放功能

    目录 插件介绍: 插件信息: 插件使用前的准备工作 设置麦克风权限描述 权限管理插件 permission_handler 音频硬件配置插件 audio_session 动画插件 常用的方法 录音常见的方法 初始化录音对象 开启录音 麦克风权限 开始录音 结束录音 播放常见的方法 初始化播放器 初始化操作 开始播放 结束播放 动画实现 加载GIF动画 加载动画文件 上传文件 上传音频文件 总结 插件介绍: flutter_sound这个插件可以实现iOS和Android平台的录音和播放功能.即可

  • 使用PlatformView将 Android 控件view制作成Flutter插件

    目录 引言 1. FlutterPlugin 创建 2. 创建 Android 控件 3. 注册 Android 控件 4. 封装 Android 层通信交互 ‘CustomViewController’ 代码说明 5. 在 flutter 中如何使用已注册的 Android 控件(view) 代码说明 如何使用这个View 6. 附上 example 完整代码 引言 小编最近在项目中实现相机识别人脸的功能,将 Android 封装的控件 view 进行中转,制作成 FlutterPlugin

  • 详解Flutter中视频播放器插件的使用教程

    目录 创建一个新的视频播放器 添加播放和暂停按钮 创建一个快进 添加一个视频进度指示器 应用视频的字幕 结论 您已经看到很多包含视频内容的应用程序,比如带有视频教程的食谱应用程序.电影应用程序和体育相关的应用程序.您是否想知道如何将视频内容添加到您的下一个Flutter应用程序中? 从头开始实现视频功能将是一项繁重的任务.但有几个插件可以让开发者的生活变得轻松.视频播放器插件是可用于 Flutter 的最佳插件之一,可满足这一要求. 在这篇文章中,您将学习如何应用视频播放器插件以及控制视频播放器

  • Flutter插件开发之HmsScanKit实现示例详解

    目录 前沿 效果图 相关知识点 1. Flutter Packages 2. Package类别 3. 原生插件开发步骤 HmsScan插件的实现 1. 定义 package API: 2. Android代码实现: 3. ios部分的实现 4. 需要注意的点 总结 前沿 从事Flutter开发以来,一直都是使用已有的插件,没有自己开发过.最近同事推荐让我使用华为的扫码SDK(hms_scan_kit),正好借此机会来开发一个Flutter的原生插件.算是对最近的插件学习做一个简单的总结. 效果

  • Flutter自动路由插件auto_route使用详解

    目录 一.简介 二.基本使用 2.1 安装插件 2.2 定义路由表 2.3 生成路由 2.4 路由跳转 2.5 处理返回结果 三.路由导航 3.1 嵌套导航 3.2 Tab 导航 3.3 PageView 3.4 声明式导航 四.高级用法 4.1 路由控制器 4.2 Paths 4.2.1 Path Parameters 4.2.2 Inherited Path Parameters 4.2.3 Query Parameters 4.2.4 Redirecting Paths 4.3 路由守护

  • Flutter桌面开发windows插件开发

    目录 前言 插件介绍 windows插件编写 Windows插件的一些坑 前言 通过此篇文章,你将了解到: Flutter插件的基本介绍: windows插件开发的真实踩坑经验. 我们都知道,Flutter的定位更多是作为一个跨平台的UI框架,对于原生平台的功能,开发过程中经常需要插件来提供.不幸的是Windows的生态又极其不完整,插件开发必不可少.但网上windows的文章少之又少,所以本篇文章,我们一起来聊聊插件开发的一些技巧. 插件介绍 Flutter的插件主要分两种:package和p

  • Android开发Flutter 桌面应用窗口化实战示例

    目录 前言 一.应用窗口的常规配置 应用窗口化 自定义窗口导航栏 美化应用窗口 二.windows平台特定交互 注册表操作 执行控制台指令 实现应用单例 三.桌面应用的交互习惯 按钮点击态 获取应用启动参数 四.写在最后 前言 通过此篇文章,你可以编写出一个完整桌面应用的窗口框架. 你将了解到: Flutter在开发windows和Android桌面应用初始阶段,应用窗口的常规配置: windows平台特定交互的实现,如:执行控制台指令,windows注册表,应用单例等: 桌面应用的交互习惯,如

  • vue.js样式布局Flutter业务开发常用技巧

    阴影样式中flutter和css对应关系 UI给出的css样式 width: 75px; height: 75px; background-color: rgba(255, 255, 255, 1); border-radius: 4px; box-shadow: 0px 0.5px 5px 0px rgba(0, 0, 0, 0.08); flutter样式布局 Container( constraints: BoxConstraints.tightFor(width: 75, height:

  • C#开发Windows服务实例之实现禁止QQ运行

    本实例主要实现下面三个基本功能 1.C#开发windows服务 2.禁止QQ等程序运行 3.为windows服务创建自动安装程序 下面针对这三个基本功能进行实现 一.C#开发windows服务 Windows服务在VS以前的版本中叫NT服务,在VS.NET启用了新的名称.用C#创建windows服务不是一件困难的事,下页针对服务创建.启动.停止做详细介绍 1.首先在vs中添加一winform程序KillService 2.在解决方案添加新项中添加Windows服务 3.打开服务页面,切换至代码页

  • Flutter混合开发详解

    混合开发简介 使用Flutter从零开始开发App是一件轻松惬意的事情,但对于一些成熟的产品来说,完全摒弃原有App的历史沉淀,全面转向Flutter是不现实的.因此使用Flutter去统一Android.iOS技术栈,把它作为已有原生App的扩展能力,通过有序推进来提升移动终端的开发效率. 目前,想要在已有的原生App里嵌入一些Flutter页面主要有两种方案.一种是将原生工程作为Flutter工程的子工程,由Flutter进行统一管理,这种模式称为统一管理模式.另一种是将Flutter工程作

  • Flutter iOS开发OC混编Swift动态库和静态库问题填坑

    目录 引言 OC接入Swift 插件 静态库和 Framework 区别 新的问题: non-modular heade 不能在Framework Module中使用非Modular 的 Header 引言 Flutter 在 iOS 上的编译问题相信大家多多少少遇到过,不知道大家在搜索这方便的问题时,得到的答案是不是让你 clean 或者 install 多几次,很多时候就算解决完问题,也是处于薛定谔的状态,所以本篇也简单记录下 Flutter 开发中,OC 混编 Swift 遭遇动态库和静态

  • Flutter Widget开发Shortcuts快捷键实例

    目录 正文 ShortcutActivators到Intents的映射 想要捕获Control + C ? 正文 Flutter所提供的键盘快捷键系统直接用就很棒了,而且还提供了大量的空间可根据自己的喜好配置操作,之前那一篇博客介绍了小部件Focus 它会指示Flutter以你的应用来包裹键盘事件,以寻找匹配的Shortcuts小部件,这便会带入Shortcuts小部件. ShortcutActivators到Intents的映射 上一篇博客,我们以Accordion属性所假想的小部件树,挑个你

  • Flutter 图片开发核心技能快速掌握教程

    目录 正文 使用网络图片 把网络图片缓存到磁盘 使用 assets 图片 适配浅色与深色模式 在不同的设备使用不同分辨率的图片 关于设备 dpr 不完全匹配的处理 忽略 dpr 信息 使用相册图片 使用相机拍摄的图片 使用内存图片 图片用做装饰 图片预加载 centerSlice centerSlice 只能放大,不能缩小. 全局缓存 ImageCache 的设置 图片类之间的关系 ImageProvider obtainKey(ImageConfiguration) 方法 resolve(Im

  • 详解使用webpack+electron+reactJs开发windows桌面应用

    electron是一两年前挺火的一个框架 本质上是一个浏览器,但是集成了很多windows系统的功能,让前端开发也可以直接操作windows的窗体,做成一个实打实的桌面软件 (当然听说mac上也可以用electron,不过没试过) (没错我还在用windows,不是mac也不是linux,我是个lowB) 团队主要的技术栈是react,所以考虑用react开发,方便维护. PS.由于项目是大半年前做的,所以一些细节可能记忆有误请见谅 几个重点: 1.想要能调试必须使用webpack打包,不能用r

  • 用node-webkit把web应用打包成桌面应用(windows环境)

    node-webkit是一个Chromium和node.js上的结合体,通过它我们可以把建立在chrome浏览器和node.js上的web应用打包成桌面应用,而且还可以跨平台的哦.很显然比起传统的桌面应用,在某些特定领域用html5+css3+js开发的web应用更加简单和高效,而且还可以使用node.js的功能,所以node-webkit还是很有用处的. 下面我通过一个简单的demo来介绍怎么样把一个web应用打包成一个可执行文件(这里只介绍windows环境) 首先新建一个index.htm

随机推荐