使用 Firebase 雲端通訊,為 Flutter 應用程式傳送通知

1. 簡介

上次更新時間:2022 年 4 月 4 日

本程式碼研究室將引導您使用 Flutter 使用 Firebase 雲端通訊 (FCM) 開發多平台應用程式。您會編寫應用程式的其中一項實作,然後在 Android、iOS 和網站這三個平台順利建構及執行。您也會學到如何在 Flutter 中整合 FCM,以及如何編寫用於接收和傳送訊息的程式碼。最後,程式碼研究室介紹了 FCM HTTP v1 API 的平台專屬區塊功能,可讓您傳送在不同平台上出現不同行為的訊息。

事前準備

對 Flutter 有基本瞭解。

課程內容

  • 如何設定及建立 Flutter 應用程式。
  • 如何新增 FCM 依附元件。
  • 如何將單一 FCM 訊息傳送至應用程式。
  • 如何將 FCM 主題訊息傳送至應用程式。

軟硬體需求

  • 使用 Dart 和 Flutter 外掛程式設定的 Android Studio 最新穩定版。

您可以使用下列任一裝置執行程式碼研究室:

如要使用 iOS 平台執行程式碼研究室,您必須擁有 iOS 裝置、Apple 開發人員帳戶,以及已安裝 XCode 的 macOS 裝置。

2. Flutter 設定

如果您已設定 Flutter 開發環境,請略過本節。

如要設定 Flutter 開發環境,請按照下列步驟操作:

  1. 依據您的作業系統下載並安裝 Flutter:安裝 |飄逸袖
  2. 確認 Flutter 工具已新增至路徑。
  3. 按照設定編輯器 | 所示,為 Flutter 設定編輯器 |Flutter:請務必為編輯器安裝 Flutter 和 Dart 外掛程式。在程式碼研究室的其餘部分,您將使用 Android Studio。
  4. 在指令列中執行 flutter doctor,以便掃描設定並列出所有需要修正的缺少依附元件。按照操作說明修正任何重要缺少的依附元件。請注意,您可能不需要某些依附元件。舉例來說,如果不打算開發 iOS 應用程式,即使缺少 CocoaPods 依附元件也不會造成阻斷。
  5. 執行下列指令,在 fcmflutter 目錄 flutter create --org com.flutter.fcm --project-name fcmflutter fcmflutter 中建立 Flutter 應用程式,然後將目錄變更為 fcmflutter
  1. 在 Android Studio 中,前往「File」(檔案) ->「開啟,找出 Flutter 應用程式的路徑,然後按一下開啟,即可在 Android Studio 中開啟專案。應用程式程式碼位於 lib/main.dart 檔案中。

在 Android Studio 工具列中,按一下向下箭頭,選取 Android 裝置。如果目標選取器空白,如果您想透過網路瀏覽器或 iOS 裝置啟動應用程式,請安裝虛擬 Android 裝置Chrome 瀏覽器或 iOS 模擬器。您可能需要手動啟動裝置並重新整理清單,才能找到目標裝置。

Android Studio 工具列,建構目標下拉式選單的下拉式選單箭頭醒目顯示。

按一下「Run」 Android Studio 中的執行按鈕 即可啟動應用程式。

已啟動 Flutter 試用版應用程式的 UI

恭喜!您已成功建立 Flutter 應用程式。

3. Firebase 和 FlutterFire 設定

如要使用 Flutter 開發與 Firebase 雲端通訊整合的應用程式,您需要:

  • Firebase 專案。
  • 正常運作的 Firebase CLI
  • 安裝 FlutterFire。
  • 使用 flutterfire configure 設定並產生的應用程式。

建立 Firebase 專案

如果您已有 Firebase 專案,可以略過這個步驟。

  1. 如果您有 Google 帳戶,請開啟 Firebase 並使用您的 Google 帳戶登入,然後按一下「前往主控台」
  2. 在 Firebase 控制台中,按一下「新增專案」。按照操作說明建立專案。請勿勾選 [為這項專案啟用 Google Analytics],因為您不會在這項專案中使用。
  3. 建立專案後,按一下「Project Overview」旁邊的齒輪圖示,前往專案的「專案設定」

Firebase 控制台裁剪螢幕截圖,醒目顯示專案設定選單和

「Project ID」是用來識別專案的專屬 ID,此 ID 可能與 Project name 不同。專案 ID 稍後會用來設定 FlutterFire。

Firebase 控制台裁剪的螢幕截圖,醒目顯示專案 ID

恭喜!您已成功建立 Firebase 專案。

設定 Firebase CLI

如果您已設定 Firebase CLI,可以略過這個步驟。

請前往 Firebase CLI 參考資料,下載並安裝 Firebase CLI。透過下列指令使用您的 Google 帳戶登入 Firebase:

firebase login

設定 FlutterFire

  1. 使用下列指令安裝 FlutterFire 外掛程式:flutter pub add firebase_core
  2. 安裝 FCM 外掛程式:flutter pub add firebase_messaging
  3. 設定 FlutterFire CLI:dart pub global activate flutterfire_cli
  4. 在 Flutter 上設定 Firebase 專案:flutterfire configure --project=fcm4flutter. 使用方向鍵和空格來選取平台,或按下 Enter 鍵來使用預設平台。

本程式碼研究室會使用預設平台 (Android、iOS 和網頁),但您只能選取一或兩個平台。如果系統提示您提供 iOS 軟體包 ID,請輸入 com.flutter.fcm.fcmflutter 或您的 iOS 軟體包 ID,格式為 [company domain name].[project name]。指令完成後,請重新整理 Firebase 控制台頁面。您會在 Firebase 專案下方看到該應用程式已建立適用於所選平台的應用程式。

Firebase 控制台裁剪的螢幕截圖,顯示已為所選平台建立的應用程式

這個指令會在 lib 目錄下產生 firebase_options.dart 檔案,其中包含初始化所需的所有選項。

設定 iOS 版雲端通訊

  1. 前往 Apple 開發人員頁面,然後按一下「Keys」分頁中的「Create a key」

Apple 開發人員頁面裁剪的螢幕截圖,凸顯用來建立金鑰的頁面元件

  1. 輸入金鑰名稱,然後勾選「Apple 推播通知服務 (APN)」Apple 開發人員頁面裁剪的螢幕截圖,醒目顯示新金鑰名稱的文字方塊
  2. 下載副檔名為 .p8 的金鑰檔案。Apple 開發人員頁面裁剪的螢幕截圖,醒目顯示下載金鑰的按鈕
  3. Firebase 控制台,前往專案的「專案設定」,然後選擇「雲端通訊」分頁標籤。

Firebase 控制台頁面裁剪的螢幕截圖,醒目顯示要更新專案設定的元件

Firebase 控制台頁面裁剪的螢幕截圖,醒目顯示「雲端通訊」分頁

  1. 在「雲端通訊」分頁中上傳 iOS 應用程式的 APN 金鑰檔案。輸入「雲端通訊」分頁中的 APN 金鑰 ID 和團隊 ID,如要查看,請前往 Apple 會員中心。Firebase 控制台頁面裁剪的螢幕截圖,醒目顯示用於上傳 APN 驗證金鑰的按鈕

4. FCM 準備工作

應用程式必須先符合以下條件,才能接收來自 FCM 的訊息:

  • 初始化 FlutterFire。
  • 要求通知權限。
  • 向 FCM 註冊即可取得註冊權杖。

初始化

如要初始化服務,請將主要函式 (lib/main.dart) 替換為下列程式碼:

// core Flutter primitives
import 'package:flutter/foundation.dart';
// core FlutterFire dependency
import 'package:firebase_core/firebase_core.dart';
// generated by 
flutterfire configure
import 'firebase_options.dart';
// FlutterFire's Firebase Cloud Messaging plugin
import 'package:firebase_messaging/firebase_messaging.dart';

// TODO: Add stream controller
// TODO: Define the background message handler

Future<void> main() async {
 WidgetsFlutterBinding.ensureInitialized();
 await Firebase.initializeApp(
   options: DefaultFirebaseOptions.currentPlatform,
 );

 // TODO: Request permission
 // TODO: Register with FCM
 // TODO: Set up foreground message handler
 // TODO: Set up background message handler

 runApp(MyApp());
}

然後執行「Tools」->。Flutter ->Android Studio 中的 Flutter Pub Get 載入在設定 FlutterFire 中新增的套件,並在 Android Studio 中以適當的 Intellisense 設定顯示程式碼。

這會針對目前平台 DefaultFirebaseOptions.currentPlatform 初始化 FlutterFire,該平台是從產生的 firebase_options.dart 檔案匯入。請注意,initializeApp 是非同步函式,而 await 關鍵字會確保初始化在執行應用程式前完成。

要求權限

應用程式必須取得使用者的權限,才能接收通知。firebase_messaging 提供的 requestPermission 方法會顯示對話方塊或彈出式視窗,提示使用者允許或拒絕授予權限。

首先,請將這段程式碼複製到註解 TODO: Request permission 下方的主要函式。傳回的 settings 會指出使用者是否已授予權限。建議您只在使用者需要使用需要存取權的功能時才要求權限 (例如,使用者在應用程式設定中開啟通知)。在本程式碼研究室中,為簡化應用程式啟動程序,我們會要求權限。

final messaging = FirebaseMessaging.instance;

final settings = await messaging.requestPermission(
 alert: true,
 announcement: false,
 badge: true,
 carPlay: false,
 criticalAlert: false,
 provisional: false,
 sound: true,
);

 if (kDebugMode) {
   print('Permission granted: ${settings.authorizationStatus}');
 }

接著,在 Android Studio 工具列的目標選取器中選取 Chrome (web),然後再次執行應用程式。

Android Studio 工具列的裁剪螢幕截圖,內含目標選取器和「Run」按鈕

接著,Chrome 分頁會開啟彈出式視窗,要求您授予權限。按一下 Allow,就會在 Android Studio 主控台看到記錄:Permission granted: AuthorizationStatus.authorized。允許或封鎖權限要求後,您的回應就會與應用程式儲存在瀏覽器中,且不會再顯示彈出式視窗。請注意,在 Android Studio 中再次執行網頁應用程式時,系統可能會再次提示您授予權限。Chrome 分頁的螢幕截圖,顯示要求存取的彈出式視窗

註冊

將這個程式碼複製到註解 TODO: Register with FCM 下方的主要函式,以便向 FCM 註冊。getToken 呼叫會傳回註冊權杖,可供應用程式伺服器或受信任的伺服器環境用來傳送訊息給使用者。

// It requests a registration token for sending messages to users from your App server or other trusted server environment.
String? token = await messaging.getToken();

if (kDebugMode) {
  print('Registration Token=$token');
}

在 Android Studio 工具列中,選取 Android 裝置並執行應用程式。在 Android Studio 控制台中,註冊權杖的顯示方式如下:

I/flutter ( 3717): Permission granted: AuthorizationStatus.authorized
I/flutter ( 3717): Registration Token=dch. . . D2P:APA9. . .kbb4

請將該檔案複製到文字編輯器,以便稍後用來傳送訊息。

uses-sdk:minSdkVersion 16 cannot be smaller than version 19 declared in library [:firebase_messaging]

透過網頁版接收訊息的額外步驟

網頁應用程式需要兩個額外步驟才能取得註冊權杖,並監聽傳入訊息。網站必須將 VAPID 金鑰傳送至 getToken,才能授權向支援的網路推送服務傳送要求。

首先,請在 Firebase 控制台中開啟 Firebase 專案的「雲端通訊」分頁,然後向下捲動至「網頁設定」部分,尋找現有的金鑰組或產生新的金鑰組。點選醒目顯示的按鈕複製金鑰,以便做為 vapidKey 使用。

「網路設定頁面」中醒目顯示金鑰組的網路推送憑證元件螢幕截圖 (經過裁剪)

接著,將「Registration」部分中的註冊代碼換成這段程式碼,然後更新 vapidKey:

// TODO: replace with your own VAPID key
 const vapidKey = "<YOUR_PUBLIC_VAPID_KEY_HERE>";

 // use the registration token to send messages to users from your trusted server environment
 String? token;

 if (DefaultFirebaseOptions.currentPlatform == DefaultFirebaseOptions.web) {
   token = await messaging.getToken(
     vapidKey: vapidKey,
   );
 } else {
   token = await messaging.getToken();
 }

 if (kDebugMode) {
   print('Registration Token=$token');
 }

接著,在專案根目錄的 web/ 目錄下建立 firebase-messaging-sw.js 檔案。將下列內容複製到 firebase-messaging-sw.js,允許網頁應用程式接收 onMessage 事件。詳情請參閱「在 Service Worker 中設定通知選項」。

importScripts("https://www.gstatic.com/firebasejs/9.6.10/firebase-app-compat.js");
importScripts("https://www.gstatic.com/firebasejs/9.6.10/firebase-messaging-compat.js");

// todo Copy/paste firebaseConfig from Firebase Console
const firebaseConfig = {
 apiKey: "...",
 authDomain: "...",
 databaseURL: "...",
 projectId: "...",
 storageBucket: "...",
 messagingSenderId: "...",
 appId: "...",
};

firebase.initializeApp(firebaseConfig);
const messaging = firebase.messaging();

// todo Set up background message handler

隨後,依序前往「Project Settings」 ->在「General」分頁中,向下捲動並找到「Web App」,然後複製 firebaseConfig 程式碼區段並貼到 firebase-messaging-sw.jsFirebase 設定頁面中網頁應用程式元件的裁剪螢幕截圖

最後,在 Android Studio 工具列的目標選取器中選取 Chrome (web),然後執行應用程式。在 Android Studio 控制台中,註冊權杖的顯示方式如下:

Debug service listening on ws://127.0.0.1:61538/BLQQ3Fg-h7I=/ws
Permission granted: AuthorizationStatus.authorized
Registration Token=fH. . .ue:APA91. . .qwt3chpv

將註冊權杖複製到文字編輯器,以便稍後用來傳送訊息。

在 iOS 裝置上接收訊息的額外步驟

如要接收 FCM 的訊息,iOS 裝置需啟用 Xcode 的推播通知背景模式,步驟如下:

  1. 在 Android Studio 中,以滑鼠右鍵按一下專案名稱,然後選取「Flutter」->在 Xcode 中開啟 iOS 模組裁剪者的螢幕截圖
  2. Xcode 啟動後,在「Signing &專案目標的功能分頁。詳情請參閱「設定應用程式」。
  3. 在 Android Studio 工具列的目標選取器中選取 iOS 裝置,然後執行應用程式。授予通知權限後,註冊權杖會顯示在 Android Studio 控制台中。

iOS 應用程式要求傳送通知的權限 (螢幕截圖)

恭喜!您已成功向 FCM 註冊應用程式。您已準備好接收訊息,如下一節所述。

5. 接收來自 FCM 的訊息

設定訊息處理常式

應用程式在應用程式處於前景模式時,需要處理 onMessage 事件,並在應用程式於背景運作時處理 onBackgroundMessage 事件。

前景訊息處理常式

首先,請在檔案 main.dart 的註解 TODO: Add stream controller 後方新增串流控制器,以便將訊息從事件處理常式傳遞至 UI。

import 'package:rxdart/rxdart.dart';
// used to pass messages from event handler to the UI
final _messageStreamController = BehaviorSubject<RemoteMessage>();

如要新增依附元件 rxdart,請從專案目錄執行下列指令:flutter pub add rxdart

接著,執行工具 ->Flutter ->Android Studio 中的 Flutter Pub Get 載入 rxdart.dart 套件,並在 Android Studio 中以適當的 Intellisense 設定顯示程式碼。

然後,新增事件處理常式,在註解 TODO: Set up foreground message handler 之後監聽前景訊息。它會列印記錄並將訊息發布至串流控制器。

 FirebaseMessaging.onMessage.listen((RemoteMessage message) {
   if (kDebugMode) {
     print('Handling a foreground message: ${message.messageId}');
     print('Message data: ${message.data}');
     print('Message notification: ${message.notification?.title}');
     print('Message notification: ${message.notification?.body}');
   }

   _messageStreamController.sink.add(message);
 });

之後,用這段程式碼取代檔案 main.dart 中的原始狀態小工具,這樣就能在狀態小工具中將訂閱者新增至串流控制器,並在小工具上顯示最後一則訊息。

class _MyHomePageState extends State<MyHomePage> {
 String _lastMessage = "";

 _MyHomePageState() {
   _messageStreamController.listen((message) {
     setState(() {
       if (message.notification != null) {
         _lastMessage = 'Received a notification message:'
             '\nTitle=${message.notification?.title},'
             '\nBody=${message.notification?.body},'
             '\nData=${message.data}';
       } else {
         _lastMessage = 'Received a data message: ${message.data}';
       }
     });
   });
 }

 @override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(
       title: Text(widget.title),
     ),
     body: Center(
       child: Column(
         mainAxisAlignment: MainAxisAlignment.center,
         children: <Widget>[
           Text('Last message from Firebase Messaging:',
               style: Theme.of(context).textTheme.titleLarge),
           Text(_lastMessage, style: Theme.of(context).textTheme.bodyLarge),
         ],
       ),
     ),
   );
 }
}

Android/iOS 適用的背景訊息處理常式

當應用程式在背景執行時,訊息會由 onBackgroundMessage 處理常式處理。處理常式應為頂層函式。當應用程式進入前景時,您可以處理訊息 (請參閱「處理互動」) 或與應用程式伺服器同步處理,藉此更新 UI。

在主函式以外的註解 TODO: Define the background message handler 後方建立處理常式函式,然後在註解 TODO: Set up background message handler 之後呼叫主函式。

// TODO: Define the background message handler
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
 await Firebase.initializeApp();

 if (kDebugMode) {
   print("Handling a background message: ${message.messageId}");
   print('Message data: ${message.data}');
   print('Message notification: ${message.notification?.title}');
   print('Message notification: ${message.notification?.body}');
 }
}

void main() {
 ...

 // TODO: Set up background message handler
 FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

 runApp(MyApp());
}

網頁版背景訊息處理常式

自 FlutterFire firebase_messaging 11.2.8 版起,處理網路平台的背景訊息將採用不同的流程。因此,您需要在 Service Worker web/firebase-messaging-sw.js 中新增獨立的訊息處理常式。

messaging.onBackgroundMessage((message) => {
 console.log("onBackgroundMessage", message);
});

設定應用程式伺服器

  1. 在 Android Studio 中開啟 https://github.com/FirebaseExtended/firebase_fcm_flutter/tree/main/server 專案,即可匯入範例程式碼。伺服器是以 Gradle 為基礎的 Java 專案,而 firebase-admin SDK 的依附元件是提供 FCM 訊息傳送功能。
  2. 設定 Firebase 服務帳戶,讓 Firebase Admin SDK 授權呼叫 FCM API。在 Firebase 控制台中開啟「專案設定」,然後選取「服務帳戶」分頁標籤。選擇「Java」並按一下 Generate new private key,下載設定程式碼片段。「專案設定」頁面中,醒目顯示「Admin SDK 設定」部分服務帳戶元件的螢幕截圖。經過裁剪的螢幕截圖
  3. 將檔案重新命名為 service-account.json,並複製到伺服器專案的 src/main/resources 路徑。

傳送測試訊息

FcmSender.java 檔案中,sendMessageToFcmRegistrationToken 撰寫含有資料酬載的通知訊息。註冊權杖可指定訊息要接收的應用程式執行個體。

private static void sendMessageToFcmRegistrationToken() throws Exception {
   String registrationToken = "REPLACE_WITH_FCM_REGISTRATION_TOKEN";
   Message message =
       Message.builder()
           .putData("FCM", "https://firebase.google.com/docs/cloud-messaging")
           .putData("flutter", "https://flutter.dev/")
           .setNotification(
               Notification.builder()
                   .setTitle("Try this new app")
                   .setBody("Learn how FCM works with Flutter")
                   .build())
           .setToken(registrationToken)
           .build();

   FirebaseMessaging.getInstance().send(message);

   System.out.println("Message to FCM Registration Token sent successfully!!");
 }
  1. 複製從「Registration」部分複製的 Android 註冊權杖,並貼到變數 registrationToken 的值中。
  2. 按一下「Run」 圖示 Android Studio 中的執行按鈕 執行主要函式,並透過 FCM 傳送訊息給使用者。Android Studio 中 FcmSender.java 主函式旁邊的「Run」圖示經過裁剪的螢幕截圖

當 Android 應用程式在背景執行時,訊息會顯示在通知匣中。

Android 通知匣中顯示訊息的裁剪螢幕截圖

當 Android 應用程式在前景運作時,Android Studio 主控台會顯示記錄:「處理前景訊息」。因為 UI 已訂閱串流控制器接收新訊息,因此訊息內容也會顯示在 UI 中。

Android 應用程式顯示的訊息內容螢幕截圖 (經過裁剪)

如果您貼上註冊權杖,並從應用程式伺服器或其他受信任的伺服器環境傳送訊息,就會看到類似的行為:

  • 當網頁應用程式在背景執行時 (也就是由其他視窗隱藏,或其他分頁正在執行時),系統會顯示網路通知。

Chrome 瀏覽器顯示網路通知裁剪的螢幕截圖

  • 當網頁應用程式在前景運作時,只要在網路上按一下滑鼠右鍵並選取「Inspect」,即可在 Chrome 控制台中查看記錄。訊息內容也會顯示在 UI 中。Chrome 控制台螢幕截圖 (內含偵錯記錄) 螢幕截圖

6. 傳送主題訊息

FCM HTTP v1 API 的平台覆寫功能可讓訊息傳送要求在不同平台上具有不同行為。這項功能的其中一個用途是根據平台顯示不同的通知訊息內容。這項功能最常用在主題訊息指定多部裝置 (可能跨多個平台) 的情況下使用。本節將逐步引導您讓應用程式能收到各平台的專屬主題訊息。

從客戶訂閱主題

如要訂閱主題,請在 Flutter 應用程式的 main.dart 檔案主函式結尾呼叫 messaging.subscribeToTopic 方法。

// subscribe to a topic.
const topic = 'app_promotion';
await messaging.subscribeToTopic(topic);

[選用] 從伺服器網頁版訂閱主題

如果您並未在網路平台上開發應用程式,可以略過這一節。

FCM JS SDK 目前不支援用戶端主題訂閱。您可以改為使用 Admin SDK 的伺服器端主題管理 API 訂閱。這個程式碼說明使用 Java Admin SDK 的伺服器端主題訂閱。

 private static void subscribeFcmRegistrationTokensToTopic() throws Exception {
   List<String> registrationTokens =
       Arrays.asList(
           "REPLACE_WITH_FCM_REGISTRATION_TOKEN"); // TODO: add FCM Registration Tokens to
   // subscribe
   String topicName = "app_promotion";

   TopicManagementResponse response =     FirebaseMessaging.getInstance().subscribeToTopic(registrationTokens, topicName);
   System.out.printf("Num tokens successfully subscribed %d", response.getSuccessCount());
 }

開啟應用程式伺服器,然後按一下「Run」 圖示 Android Studio 中的執行按鈕,在 FcmSubscriptionManager.java 檔案中執行主函式:

Android Studio 中 FcmSubscriptionManager.java 主要函式旁顯示的「Run」圖示裁剪螢幕截圖

將含有平台覆寫值的訊息傳送至主題

現在,您已準備好傳送主題平台覆寫訊息。在以下程式碼片段中:

  • 您會使用基本訊息和標題「A new app is available」建構傳送要求。
  • 訊息會產生標題為「A new app is available」的通知iOS 和網路平台
  • 訊息會產生標題為「A new Android app is available」的通知在 Android 裝置上
private static void sendMessageToFcmTopic() throws Exception {
   String topicName = "app_promotion";

   Message message =
       Message.builder()
           .setNotification(
               Notification.builder()
                   .setTitle("A new app is available")
                   .setBody("Check out our latest app in the app store.")
                   .build())
           .setAndroidConfig(
               AndroidConfig.builder()
                   .setNotification(
                       AndroidNotification.builder()
                           .setTitle("A new Android app is available")
                           .setBody("Our latest app is available on Google Play store")
                           .build())
                   .build())
           .setTopic("app_promotion")
           .build();

   FirebaseMessaging.getInstance().send(message);

   System.out.println("Message to topic sent successfully!!");
 }

FcmSender.java 檔案的主要函式中,取消註解 sendMessageToFcmTopic();。按一下「執行」 Android Studio 中的執行按鈕 即可傳送主題訊息。

7. 總結與後續行動

簡而言之,您已瞭解如何使用 Flutter 和 FCM 開發多平台應用程式開發流程,包括環境設定、依附元件整合,以及訊息接收與傳送。如要深入瞭解,請參閱下列資料:

程式碼研究室

參考資料