Flutter桌面端開發——發送本地懸浮通知🔔


注意:查看本文章前請先查看更新日志,以至於該文章適合插件的最新版本

更新日志
詳情 日期
更新了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();
}

現在我們就能愉快地發送一條自定義的通知了🎉

image

其中只有title參數是必傳的,我們就試一下只傳入這個參數:

final notification = LocalNotification(
  identifier: '12345',
  title: '古詩鑒賞從',
);
notification.show();

image

我們發現,只傳 title 參數,它會自動將 title 的參數值賦值給 subtitle,而 body 參數會以“新通知”代替。而且onCloseonClick兩個方法都會觸發關閉通知的功能,但是不會同時調用。這兩個操作其實是有區別的。

image

由以上試驗可得,onClick才會真正一次性把通知刪除,而onClose只會把通知收起來,需要再次調用onClose才能關閉通知。

接下來來看看LocalNotificationAction對象,它有2個可選參數:

  • String type:通知中顯示動作的類型,值為button
  • String? text:按鈕中顯示的文本。雖然是可選,但是必填,否則會出錯
final notification = LocalNotification(
  ...
  actions: [
    LocalNotificationAction(text: '學廢了'),
    LocalNotificationAction(text: '沒學廢'),
  ],
);

image

我們可以發現,點擊的按鈕可以通過onClickAction獲取到,然后就可以愉快地編寫按鈕點擊后的操作了。😁

win_toast

該插件0.2.0以后用法有較大差距,通過xml文件來自定義通知樣式,需要的可以自行查看官方文檔和案例。這里只記錄到0.1.1的用法。

安裝🛠

點擊win_toast獲取最新版本。以下是在編寫本文章時的最新版本:

win_toast: ^0.1.0

使用🍖

在全局使用該插件,需要在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 參數。

image

再來看看只傳入文字的 text02 類型:

toast = await WinToast.instance().showToast(
  type: ToastType.text02,
  title: _title,
  subtitle: _subtitle,
  actions: _actione,
);

image

用了一下 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,
);

image

😲嗯?我們傳入的圖片怎么沒顯示?換個網絡圖片的鏈接試試:

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');

image

成功🎉🎉🎉🎉🎉

接下來使用 imageAndText02 類型來看看:

toast = await WinToast.instance().showToast(
  type: ToastType.imageAndText02,
  title: _titles,
  subtitle: _subtitle,
  imagePath: _imagePath,
  actions: _action,
);

image

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!]}');

image

知道了用戶點擊的是哪個按鈕,接下來編寫事件的代碼就容易了。

🛫OK,以上就是這篇文章的全部內容,僅針對插件的當前版本,並不能保證適用於以后插件用法的更新迭代。本人只處於對代碼的實踐部分,如某些內容的概念或叫法出錯還請指正🙏。

最后,感謝 lijy91boyan01 對以上插件的維護和開發😁。本應用代碼已上傳至 githubgitee,有需要的可以下載下來查看學習。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM