1. 簡介
上次更新時間:2022 年 4 月 4 日
本程式碼研究室將逐步說明如何使用 Flutter,透過 Firebase 雲端通訊 (FCM) 開發跨平台應用程式。您只需撰寫一段應用程式實作程式碼,就能在 Android、iOS 和網頁這三個平台上順暢建構及執行。您也會瞭解如何在 Flutter 中整合 FCM,以及如何編寫程式碼來接收及傳送訊息。最後,本程式碼研究室會介紹 FCM HTTP v1 API 的平台專屬區塊功能,讓您傳送一則訊息,在不同平台上的行為卻有所不同。
必要條件
對 Flutter 有基本瞭解。
課程內容
- 如何設定及建立 Flutter 應用程式。
- 如何新增 FCM 依附元件。
- 如何將單一 FCM 訊息傳送至應用程式。
- 如何將主題 FCM 訊息傳送至應用程式。
軟硬體需求
- 已設定 Dart 和 Flutter 外掛程式的最新穩定版 Android Studio。
您可以使用下列任一裝置執行程式碼研究室:
- 連接至電腦的實體 Android 裝置。
- Android 模擬器 (請參閱「在 Android Emulator 上執行應用程式」)。
- 你選擇的瀏覽器,例如 Chrome。
如要使用 iOS 平台執行本程式碼研究室,您需要 iOS 裝置、Apple 開發人員帳戶,以及已安裝 XCode 的 macOS 裝置。
2. Flutter 設定
如果您已設定 Flutter 開發環境,請略過本節。
如要設定 Flutter 開發環境,請按照下列步驟操作:
- 為您的作業系統下載並安裝 Flutter:安裝 | Flutter
- 確認 Flutter 工具已新增至路徑。
- 按照「設定編輯器 | Flutter」一文的說明,設定 Flutter 編輯器。請務必為編輯器安裝 Flutter 和 Dart 外掛程式。在本程式碼研究室的其餘部分,您將使用 Android Studio。
- 在指令列中執行
flutter doctor
,掃描設定並列出需要修正的任何缺少的依附元件。請按照操作說明修正任何重要的遺漏依附元件。請注意,部分依附元件可能並非必要。舉例來說,如果您不打算開發 iOS 應用程式,缺少 CocoaPods 依附元件就不會造成阻礙。 - 執行這項指令,在
fcmflutter
目錄中建立 Flutter 應用程式flutter create --org com.flutter.fcm --project-name fcmflutter fcmflutter
,然後將目錄變更為fcmflutter
。
- 在 Android Studio 中,依序前往「File」->「Open」,找出 Flutter 應用程式的路徑,然後點選「Open」,在 Android Studio 中開啟專案。應用程式程式碼位於
lib/main.dart
檔案中。
在 Android Studio 工具列中,按一下向下箭頭選取 Android 裝置。如果目標選取器為空白,請安裝虛擬 Android 裝置,或Chrome 瀏覽器或 iOS 模擬器 (如要從網頁瀏覽器或 iOS 裝置啟動應用程式)。你可能需要手動啟動裝置,然後重新整理清單,才能找到目標裝置。
按一下「執行」 即可啟動應用程式。
恭喜!您已成功建立 Flutter 應用程式。
3. Firebase 和 FlutterFire 設定
如要使用 Flutter 開發與 Firebase 雲端通訊整合的應用程式,您需要:
- Firebase 專案。
- 可正常運作的 Firebase CLI。
- 安裝 FlutterFire。
- 使用
flutterfire configure
設定及產生的應用程式。
建立 Firebase 專案
如果您已有 Firebase 專案,可以略過這個步驟。
- 使用 Google 帳戶登入 Firebase 控制台。
- 按一下按鈕建立新專案,然後輸入專案名稱 (例如
fcm4flutter
)。
- 按一下「繼續」。
- 如果系統提示,請詳閱並接受 Firebase 條款,然後按一下「繼續」。
- (選用) 在 Firebase 控制台中啟用 AI 輔助功能 (稱為「Gemini in Firebase」)。
- 本程式碼研究室不需要 Google Analytics,因此請關閉 Google Analytics 選項。
- 按一下「建立專案」,等待專案佈建完成,然後按一下「繼續」。
恭喜!您已成功建立 Firebase 專案。
設定 Firebase CLI
如果已設定 Firebase CLI,可以略過這個步驟。
前往 Firebase CLI 參考資料,下載並安裝 Firebase CLI。使用下列指令,透過 Google 帳戶登入 Firebase:
firebase login
設定 FlutterFire
- 使用
flutter pub add firebase_core
指令安裝 FlutterFire 外掛程式。 - 安裝 FCM 外掛程式:
flutter pub add firebase_messaging
- 設定 FlutterFire CLI:
dart pub global activate flutterfire_cli
- 在 Flutter 中設定 Firebase 專案:
flutterfire configure --project=fcm4flutter.
使用方向鍵和空格鍵選取平台,或按下 Enter 鍵使用預設平台。
本程式碼研究室使用預設平台 (Android、iOS 和網頁),但您也可以只選取一或兩個平台。如果系統提示輸入 iOS 軟體包 ID,請輸入 com.flutter.fcm.fcmflutter
或自己的 iOS 軟體包 ID,格式為 [company domain name].[project name]
。指令執行完成後,請重新整理 Firebase 控制台頁面。您會看到系統已在 Firebase 專案中,為所選平台建立應用程式。
這個指令會在 lib
目錄下產生 firebase_options.dart
檔案,其中包含初始化所需的所有選項。
為 iOS 設定 Cloud Messaging
- 前往 Apple 開發人員頁面,然後按一下「金鑰」分頁中的「建立金鑰」。
- 輸入金鑰名稱,然後勾選「Apple 推播通知服務 (APNs)」。
- 下載副檔名為
.p8
的金鑰檔案。 - 在 Firebase 控制台中,前往專案的「專案設定」,然後選擇「Cloud Messaging」分頁標籤。
- 在「Cloud Messaging」分頁中,上傳 iOS 應用程式的 APNs 金鑰檔案。輸入「Cloud Messaging」分頁中的 APNs 金鑰 ID,以及 Apple 會員中心中的團隊 ID。
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());
}
接著在 Android Studio 中執行「Tools」->「Flutter」->「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)
,然後再次執行應用程式。
接著,Chrome 分頁會啟動,並顯示要求權限的彈出式視窗。如果您點選 Allow
,Android Studio 控制台會顯示記錄:Permission granted: AuthorizationStatus.authorized
。允許或封鎖權限要求後,瀏覽器會連同應用程式一併儲存您的回應,因此不會再次顯示彈出式視窗。請注意,在 Android Studio 再次執行網頁應用程式時,系統可能會再次提示您授予權限。
註冊
將這段程式碼複製到註解 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 專案的「Cloud Messaging」分頁,然後向下捲動至「Web configuration」(網頁設定) 區段,找出現有的金鑰配對,或產生新的金鑰配對。按一下醒目顯示的按鈕複製金鑰,即可做為 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
接著,在「專案設定」->「一般」分頁下方,向下捲動並找到「Web App」,複製 firebaseConfig
程式碼部分,然後貼到 firebase-messaging-sw.js
。
最後,在 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 上啟用「推播通知」和「背景模式」:
- 在 Android Studio 中,以滑鼠右鍵按一下專案名稱,然後依序選取「Flutter」->「Open iOS module in Xcode」。
- 啟動 Xcode 後,請在專案目標的「Signing & Capabilities」分頁中,啟用「Push Notifications」和「Background Modes」。詳情請參閱「設定應用程式」。
- 在 Android Studio 工具列中,於目標選取器選取 iOS 裝置,然後執行應用程式。授予通知權限後,註冊權杖會列印在 Android Studio 控制台中。
恭喜,您已成功向 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
。
接著,在 Android Studio 中執行「Tools」->「Flutter」->「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
檔案中的原始 State 小工具替換為下列程式碼,在 State 小工具中新增串流控制器訂閱者,並在小工具上顯示最後一則訊息。
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);
});
設定應用程式伺服器
- 在 Android Studio 中開啟 https://github.com/FirebaseExtended/firebase_fcm_flutter/tree/main/server 專案,匯入範例伺服器程式碼。伺服器是以 Gradle 為基礎的 Java 專案,並依附於 firebase-admin SDK,提供 FCM 訊息傳送功能。
- 設定 Firebase 服務帳戶,讓 Firebase Admin SDK 授權呼叫 FCM API。在 Firebase 控制台中開啟「專案設定」,然後選取「服務帳戶」分頁標籤。選擇「Java」,然後按一下
Generate new private key
下載設定程式碼片段。 - 將檔案重新命名為
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!!");
}
- 複製「註冊」部分中的 Android 註冊權杖,然後貼到
registrationToken
變數的值。 - 按一下「執行」
,執行主要函式並透過 FCM 將訊息傳送給使用者。
Android 應用程式在背景執行時,訊息會顯示在通知匣中。
Android 應用程式在前台執行時,Android Studio 控制台會顯示「Handling a foreground message」記錄。由於 UI 訂閱了新訊息的串流控制器,因此 UI 中也會顯示訊息內容。
如果您貼上註冊權杖,並從應用程式伺服器或其他受信任的伺服器環境傳送訊息,也會看到類似行為:
- 如果網頁應用程式在背景執行 (也就是說,網頁應用程式遭到其他視窗隱藏,或另一個分頁處於啟用狀態),您會看到網頁通知。
- 當網頁應用程式位於前景時,你可以對著網頁按一下滑鼠右鍵,然後選取
Inspect
,在 Chrome 控制台中查看記錄。UI 中也會顯示訊息內容。
6. 傳送主題訊息
FCM HTTP v1 API 的平台覆寫功能可讓訊息傳送要求在不同平台上有不同行為。這項功能可用於根據平台顯示不同的通知訊息內容。如果使用主題訊息指定多部裝置 (可能涵蓋多個平台),就能充分發揮這項功能的作用。本節將逐步說明如何讓應用程式接收針對各平台自訂的主題訊息。
訂閱用戶端的主題
如要訂閱主題,請在 Flutter 應用程式的 main.dart
檔案中,於 main 函式結尾呼叫 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());
}
開啟應用程式伺服器,然後按一下「執行」 ,在
FcmSubscriptionManager.java
檔案中執行主要函式:
將訊息連同平台覆寫內容傳送至主題
現在可以傳送主題平台覆寫訊息。在下列程式碼片段中:
- 您可以使用基本訊息和「
A new app is available
」標題建構傳送要求。 - 在 iOS 和網頁平台上,這則訊息會產生標題為「
A new app is available
」的顯示通知。 - 這則訊息會在 Android 裝置上產生顯示通知,標題為「
A new Android app is available
」。
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();
。按一下「執行」 即可傳送主題訊息。
7. 摘要與後續步驟
總而言之,您已瞭解如何使用 Flutter 和 FCM 開發多平台應用程式,包括設定環境、整合依附元件,以及接收和傳送訊息。如要深入瞭解,請參閱下列資料:
程式碼研究室
- 如要進一步瞭解 Flutter 如何與其他 Firebase 產品 (包括使用者驗證和資料同步) 搭配運作,請參閱「認識適用於 Flutter 的 Firebase」。
- 如要進一步瞭解 FCM,包括應用程式內訊息和主題,請參閱「使用 FCM 和 FIAM 傳送訊息給使用者」和「使用 FCM 主題傳送第一則多播推播訊息」。