Flutter桌面开发 - windows插件开发_flutter windows开发(1)

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新HarmonyOS鸿蒙全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img

img
img
htt

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注鸿蒙)
img

正文

});
}

// EventChannel

// 创建事件流处理对象
auto eventHandler = std::make_unique<
StreamHandlerFunctions>(
[plugin_pointer = plugin.get()](
const EncodableValue* arguments,
std::unique_ptr<EventSink>&& events)
-> std::unique_ptr<StreamHandlerError> {
return plugin_pointer->OnListen(arguments, std::move(events));
},
[plugin_pointer = plugin.get()](const EncodableValue* arguments)
-> std::unique_ptr<StreamHandlerError> {
return plugin_pointer->OnCancel(arguments);
});
// 创建EventChannel对象
auto eventChannel = std::make_unique<flutter::EventChannelflutter::EncodableValue>(
registrar->messenger(), eventChannelName,
&flutter::StandardMethodCodec::GetInstance());
// 把通道设置给插件
eventChannel->SetStreamHandler(std::move(eventHandler));

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

registrar->AddPlugin(std::move(plugin));

  1. 如何处理消息? 在上面创建的过程中,其实已经把处理方法的传递给插件了。

// MethodChannel的处理
// result即通信的对象
void XXXPlugin::HandleMethodCall(
const flutter::MethodCallflutter::EncodableValue& method_call,
std::unique_ptr<flutter::MethodResultflutter::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::StreamHandlerErrorflutter::EncodableValue> XXXPlugin::OnListen(const flutter::EncodableValue* arguments,
std::unique_ptr<flutter::EventSinkflutter::EncodableValue>&& events) {
// 主动发送
events_.reset(events.release());
return nullptr;
}

// Flutter取消监听时触发
std::unique_ptr < flutter::StreamHandlerErrorflutter::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插件开发,但是想接触C++的同学学习讨论。
此专栏从窗口管理、分辨率适配、桌面小工具、项目框架、插件编写;下次我们讲讲如何进行打包!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注鸿蒙)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注鸿蒙)
[外链图片转存中…(img-XS1MUqK5-1713125705582)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 18
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值