注意:查看本文章前请先查看更新日志,以至于该文章适合插件的最新版本
更新日志
详情 | 日期 |
---|---|
更新了win_toast版本 | 2022-12-10 |
更新了local_notifier在0.1.5版本的用法 | 2022-06-13 |
在我用的大部分桌面端中,发送本地悬浮通知的软件可以说是屈指可数。但是,这不妨碍到我们学习✊,奋斗说不定以后就能用到呢!
在选择该使用哪些插件开发桌面端的时候,由 lijy91 主导的 LeanFlutter 可以说是帮了很大的忙,有需要的可以自己去看看。
接下来要介绍的两个发送通知的插件,也是从 LeanFlutter 下的 awesome-flutter-desktop 仓库中找的。
local_notifier
安装🛠
点击local_notifier获取最新版本。以下是在编写本文章时的最新版本:
local_notifier: ^0.1.5
👻注意:在开发 Linux 端的程序时,还需要额外的操作,具体可以查看这里
使用🍖
要想实现发送通知的功能,需要用到一个实例化的 LocalNotifier 对象,并调用setAppName方法:
void main() async{
WidgetsFlutterBinding.ensureInitialized();
await localNotifier.setup(
appName: 'Flutter桌面应用',
// 仅 Windows
shortcutPolicy: ShortcutPolicy.requireCreate,
);
runApp(const MyApp());
}
setup
方法有两个参数可以传入:
String appName
:应用程序的名称shortcutPolicy shortcutPolicy
:该属性一共有3个值:ignore
:不检查、创建或修改快捷方式requireNoCreate
:需要与 AUMI 匹配的快捷方式,不要创建或修改现有的快捷方式requireNoCreate
:默认值。需要具有匹配 AUMI 的快捷方式,如果缺少则创建,如果不匹配则修改
要想编辑想发送的内容,需要用到 LocalNotification 类。实例化该类可以传入6个参数:
String? identifier
:用来当做通用唯一识别码required String title
:发送通知的标题,一般是软件名称String? subtitle
:发送的通知内容的标题String? body
:发送的内容的主体bool silent = false
:在发送通知时是否静音List<LocalNotificationAction>? actions
:通知中显示的按钮
实例化后的对象有5个方法:
onShow
:通知显示时调用onClose
:通知关闭时调用onClick
:通知点击时调用onClickAction
:通知中的按钮被点击时调用show
:显示通知
void _localNot() {
final notification = LocalNotification(
// 用来生成通用唯一识别码
identifier: '12345',
title: '古诗鉴赏从',
subtitle: '桃夭 - 佚名〔先秦〕',
body: '桃之夭夭,灼灼其华。之子于归,宜其室家。\n桃之夭夭,有蕡其实。之子于归,宜其家室。\n桃之夭夭,其叶蓁蓁。之子于归,宜其家人。',
// 用来设置是否静音
silent: true,
);
notification.onShow = () {
BotToast.showText(text: '显示了一条通知');
};
notification.onClose = () {
BotToast.showText(text: '通知已经关闭');
};
notification.onClick = () {
BotToast.showText(text: '通知被点击了');
};
notification.onClickAction = (index) {
BotToast.showText(text: '你点击了通知的第$index个选项');
};
notification.show();
}
现在我们就能愉快地发送一条自定义的通知了🎉
其中只有title参数是必传的,我们就试一下只传入这个参数:
final notification = LocalNotification(
identifier: '12345',
title: '古诗鉴赏从',
);
notification.show();
我们发现,只传 title 参数,它会自动将 title 的参数值赋值给 subtitle,而 body 参数会以“新通知”代替。而且onClose和onClick两个方法都会触发关闭通知的功能,但是不会同时调用。这两个操作其实是有区别的。
由以上试验可得,onClick才会真正一次性把通知删除,而onClose只会把通知收起来,需要再次调用onClose才能关闭通知。
接下来来看看LocalNotificationAction对象,它有2个可选参数:
String type
:通知中显示动作的类型,值为buttonString? text
:按钮中显示的文本。虽然是可选,但是必填,否则会出错
final notification = LocalNotification(
...
actions: [
LocalNotificationAction(text: '学废了'),
LocalNotificationAction(text: '没学废'),
],
);
我们可以发现,点击的按钮可以通过onClickAction获取到,然后就可以愉快地编写按钮点击后的操作了。😁
win_toast
该插件0.2.0以后用法有较大差距,通过xml文件来自定义通知样式,需要的可以自行查看官方文档和案例。这里只记录到0.1.1的用法。
安装🛠
点击win_toast获取最新版本。以下是在编写本文章时的最新版本:
win_toast: ^0.1.1
使用🍖
在全局使用该插件,需要在app初始化时初始化。在某个页面使用,只要在页面初始化时初始化就行。
初始化时需要传递3个参数:
required String appName
:程序名称required String productName
:产品名称required String companyName
:公司名称
await WinToast.instance().initialize(
appName: '第一个Desktop应用',
productName: '第一个Desktop应用',
companyName: 'Hiden Intelligence',
);
没写过原生,插件作者贴出Pick a unique AUMID that will identify your Win32 app告诉我们为什么要填这些内容👀,想了解的可以看一下。
要想发送一条通知,需要使用 showToast 方法,该方法有5个参数可以传:
-
required ToastType type
:传入toast显示的类型,一共有8种:- imageAndText01至imageAndText04
- text01至text04
至于这些类型的异同,可以点这里👀
-
required String title
:通知显示的标题 -
String subtitle = ''
:通知显示的主要内容 -
String imagePath = ''
:选择 imageAndText 类型时,要显示的图片 -
List actions = const []
:显示通知中的按钮
使用text类型
先定义几个变量和常量:
Toast? toast;
final List<String> _title = 'Shining For One Thing(《一闪一闪亮星星》影视剧歌曲) - 赵贝尔';
final List<String> _subtitle = 'I fall in love\nI see your love\n遇见你才发现\n我在等你到来';
final List<String> _actione = ['上一首', '播放/暂停', '下一首'];
先来看看只传入文字的 text01 类型:
toast = await WinToast.instance().showToast(
type: ToastType.text01,
title: _title,
actions: _actione,
);
👻注意:当使用 ToastType.text01 或 ToastType.imageAndText01 时不能传入 subtitle 参数。
再来看看只传入文字的 text02 类型:
toast = await WinToast.instance().showToast(
type: ToastType.text02,
title: _title,
subtitle: _subtitle,
actions: _actione,
);
用了一下 ToastType.text03 和 ToastType.text04,发现显示的效果和 ToastType.text02 没有差别。大家可以自己试试。
使用imageAndText类型
修改一下常量的值(非必要):
Toast? toast;
final List<String> _title = '又下雨了,你的心情怎么样?';
final List<String> _subtitle = '偷偷告诉你,明天就天晴了😏\n好雨知时节,当春乃发生。随风潜入夜,润物细无声。野径云俱黑,江船火独明。晓看红湿处,花重锦官城。';
final List<String> _actione = ['不开森😭', '只想睡觉🥱', '非常高兴😃'];
还需要传入一张图片,目前无法得知应该传入图片的路径怎么填,所以先准备一张资源图片传入它的相对路径:
final String _imagePath = 'assets/images/pdx.jpg';
来看看 imageAndText01 类型:
toast = await WinToast.instance().showToast(
type: ToastType.imageAndText01,
title: _titles * 3,
imagePath: _imagePath,
actions: _action,
);
😲嗯?我们传入的图片怎么没显示?换个网络图片的链接试试:
final String _imagePath = 'https://gitee.com/ilgnefz/image-house/raw/master/images/pdx.jpg';
发现效果还是一样的。通过查看文档里的第一个链接中的例子,可以发现,这里需要传入图片的绝对路径。
那在 Flutter 中怎么获取文件的绝对路径呢🤔?当然,可以直接在 Android Studio 中选中图片点右键的 Copy Path,但是程序被打包安装后就不一定在这个位置了。学过Node.js,在里面获取文件的绝对路径要用到 Path 模块,那么 Flutter 是否也用同样的插件。打开 pub.dev 搜索,还真有。复制到 pubspec.yaml 进行安装,报错,告诉我们 Flutter Desktop 中已经集成了该插件,但是版本不一样。😀那不就好办了,第一步导入:
import 'package:path/path.dart' as path;
path 中没有 __dirname
方法,可以通过path.
查看提示,发现有一个 current
的方法。虽然我们不知道这个方法是干什么的,但也不妨试试。修改 imagePath 为如下代码:
final String _imagePath = path.join(path.current, 'assets/images/pdx.jpg');
成功🎉🎉🎉🎉🎉
接下来使用 imageAndText02 类型来看看:
toast = await WinToast.instance().showToast(
type: ToastType.imageAndText02,
title: _titles,
subtitle: _subtitle,
imagePath: _imagePath,
actions: _action,
);
imageAndText03 和 imageAndText04 显示的效果也和 imageAndText02 无差别,这里就不放图了。
大家可能已经发现,通知中的3个按钮是由 actions 参数决定的,但是这个参数传入的是 String 类型,那我们要怎么才能获取到用户对这些按钮的点击事件呢?
前期我们定义了一个toast
对象用来赋值,接下来就要用到这个参数:
if (toast != null) {
toast.eventStream.listen((event) {
if (event is ActivatedEvent) {
print(event);
}
});
}
在这里我们会获得一个 event 对象,通过打印会发现该对象下面只有一个属性actionIndex
,返回的是 int? 类型。通过该属性,我们就可以获取到用户点击的是第几个按钮:
WinToast.instance().bringWindowToFront(); // 用户点击后关闭弹窗通知
BotToast.showText(text: '你当前的状态是${_action[event.actionIndex!]}');
知道了用户点击的是哪个按钮,接下来编写事件的代码就容易了。
🛫OK,以上就是这篇文章的全部内容,仅针对插件的当前版本,并不能保证适用于以后插件用法的更新迭代。本人只处于对代码的实践部分,如某些内容的概念或叫法出错还请指正🙏。
最后,感谢 lijy91 和 boyan01 对以上插件的维护和开发😁。本程序相关代码已上传至 github 和 gitee,有需要的可以下载下来查看学习。