--- tags: Flutter --- # Flutter 導入 Firebase Cloud Message (FCM) 以下會簡介Flutter導入FCM的做法: 1. 導入FCM SDK 2. 撰寫接收push message 程式碼 3. 測試data message 方法 ## 導入FCM SDK Flutter dependencies設定如下: ```yaml dependencies: flutter: sdk: flutter # 以下新增firebase message相關dependencies firebase_core: ^1.19.1 firebase_messaging: ^11.4.2 ``` ### Android 相關設定 **Firebase console** 要使用Firebase的功能,需要現在Firebase上建立專案,並在專案中新增Android應用程式。並再根據表單中的需求填入資料。 ![](https://i.imgur.com/FBrWj2I.png) 註冊應用程式後,再將google-service.json檔下載到Flutter中的Android專案內。 ![](https://i.imgur.com/kgokrt5.png) 或是你也可以在專案的一般設定的頁面中找到下載json檔的下載按鈕。 ![](https://i.imgur.com/2oR7q6R.png) **android gradle** 請確認Flutter之下的Android專案中是否已具備以下設定。 在專案目錄下的gradle增加以下設定: ```groovy dependencies { classpath 'com.android.tools.build:gradle:4.1.0' //新增google-service classpath 'com.google.gms:google-services:4.3.8' } ``` 在app層之下的gradle新增以下設定: ```groovy apply plugin: 'com.google.gms.google-services' ``` ### iOS 相關設定 因為iOS推播需要在Apple開發帳號中進行APNs相關設定,而我目前沒有Apple的開發帳號,故而如果需要進行iOS推播設定可以參考以下網址: https://firebase.flutter.dev/docs/messaging/apple-integration ## push message 接收方法 在接收push message時可以分文以下三種狀態下接收。 1. 前景 2. 背景 3. APP關閉 而不同狀態下接受的push message,則是透過不同的founction來處理。 首先,在main之下新增firebase初始化程式。 ```dart void main() async { //firebase初始化。 WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); runApp(const MyApp()); } ``` 接著對firebase message元件進行初始化設定。 ```dart void _initFirebaseMessage()async{ FirebaseMessaging messaging = FirebaseMessaging.instance; //for iOS 的權限設定 NotificationSettings settings = await messaging.requestPermission( alert: true, announcement: false, badge: true, carPlay: false, criticalAlert: false, provisional: false, sound: true ); if(settings.authorizationStatus != AuthorizationStatus.authorized){ //顯示提示Dialog DialogUtil.showMessageDialog(context, "如果不授予權限,將無法收到推播訊息進行驗證。"); }else{ FirebaseMessaging.instance.getInitialMessage().then((RemoteMessage? message) { //APP關閉時,透過原生Notification點進APP時的觸發點 print('Got a message whilst in the getInitialMessage!'); StringBuffer stringBuffer = StringBuffer(); stringBuffer.write("Got a message whilst in the getInitialMessage! \n"); if(message != null){ print("data: ${message.data}"); message.data.forEach((key, value) { stringBuffer.write("key: $key, value: $value \n"); }); setState((){ _push_messsage = stringBuffer.toString(); }); } }); FirebaseMessaging.onMessage.listen((RemoteMessage message){ //前景接message print('Got a message whilst in the onMessage!'); StringBuffer stringBuffer = StringBuffer(); stringBuffer.write("Got a message whilst in the onMessage! \n"); if(message != null){ print("data: ${message.data}"); message.data.forEach((key, value) { stringBuffer.write("key: $key, value: $value \n"); }); setState((){ _push_messsage = stringBuffer.toString(); }); } }); FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message){ //APP在背景時,點Notification進入APP時的觸發點。 print('Got a message whilst in the onMessageOpenedApp!'); StringBuffer stringBuffer = StringBuffer(); stringBuffer.write("Got a message whilst in the onMessageOpenedApp! \n"); if(message != null){ print("data: ${message.data}"); message.data.forEach((key, value) { stringBuffer.write("key: $key, value: $value \n"); }); setState((){ _push_messsage = stringBuffer.toString(); }); } }); } } ``` 面下則是取得token的方法: ```dart= void _getToken() async{ FirebaseMessaging messaging = FirebaseMessaging.instance; late String? token; token = await messaging.getToken(); if(token != null){ print("token: $token"); setState(() { _push_token = token!; }); } } ``` ## Data Message 測試方法。 我們都知道FCM可以分為兩種訊息: 1. Notification 2. Data Message 其中Data Message才可以夾帶payload,而想要對其進行測試的話,因為Firebase console只提供Notification訊息的推送測試,所以要測試的話只能依靠firebase提供的API進行推送。以下我會根據舊版的API透過postmae進行Data Message的推送觸發。 在專案設定的雲端通訊頁面中啟用舊版的API,啟用完成後可以拿到server key。 ![](https://i.imgur.com/jyl8fza.png) 發送Data Message的URL如下 ``` https://fcm.googleapis.com/fcm/send ``` Header 新增以下兩個參數: 1. Content-Type = application/json 2. Authorization = key=你專案的server key ![](https://i.imgur.com/2e67hsr.png) request body 內容如下:(選擇raw以及JSON) ![](https://i.imgur.com/FDn4ceF.png) ```json { "to" : "your token", "notification" : { "body" : "Body of Your Notification", "title": "Title of Your Notification" }, "data" : { "body" : "Body of Your Notification in Data", "title": "Title of Your Notification in Title", "key_1" : "Value for key_1", "key_2" : "Value for key_2" } } ``` 發送成功後的response ![](https://i.imgur.com/YJkuwRl.png) ``` void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp().whenComplete((){ FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler); SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]) .then((_) { runApp(new MyApp()); // FirebaseMessagingManager.initFirebaseMessage(); encryptKeyAndIv(); }); }); } ``` ```dart= Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async { await Firebase.initializeApp(); }); ``` ## 參考資料 https://firebase.flutter.dev/docs/messaging/overview https://blog.kevinyang.net/2021/01/13/flutter-firebase-message-setup/ https://medium.com/android-school/test-fcm-notification-with-postman-f91ba08aacc3