---
# System prepended metadata

title: FCM ( Firebase Cloud Messaging ) w/ Flutter
tags: [flutter]

---

## 設定
:::info
[**參考 firebase 官方文件**](https://firebase.google.com/docs/cloud-messaging/flutter/client?hl=zh-tw)
:::
### iOS
#### 在 Xcode 開啟設定
:::info
[**參考教學**](https://medium.com/@prithvi2229/creating-push-notifications-in-swift-ios-beginners-guide-4a9095fe5f75)
:::
1. `Runner` > `Signing & Capabilities` > `+ Capability`
![image](https://hackmd.io/_uploads/BJypWgSYp.png)
2. 點擊 `Push Notifications` 加入
![截圖 2024-01-17 下午2.23.10](https://hackmd.io/_uploads/ryNFfeSYa.png =500x)
3. 點擊 `Backgroud Mode` 加入，然後點擊 `Remote Notifications`
![截圖 2024-01-17 下午2.27.46](https://hackmd.io/_uploads/S1T7NxBYp.png =500x)
![截圖 2024-01-17 下午2.28.09](https://hackmd.io/_uploads/ryZN4eSYa.png)
#### 上傳您的 APNs 驗證金鑰
:::info
[**參考教學**](https://docs.getui.com/getui/mobile/ios/apns/)
:::
1. 先跟著參考教學申請 APNs
2. 在 Firebase 控制台的項目內，選擇齒輪圖標，選擇項目設置，然後選擇雲端訊息傳遞選項卡。
![截圖 2024-01-17 下午4.03.52](https://hackmd.io/_uploads/HyYE5-SYp.png)
3. 為您的開發證書、生產證書或兩者選擇「上傳證書」按鈕。至少需要一個。對於每個證書，選擇 .p12 文件，並提供密碼（如果有）。確保此憑證的捆綁包 ID 與您的應用程式的捆綁包 ID 相符。選擇保存。![截圖 2024-01-17 下午4.06.05](https://hackmd.io/_uploads/SJpo9WSKp.png)

### android
不用設定

## 使用範例

```javascript
import 'package:firebase_messaging/firebase_messaging.dart';

Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  print('Handling a background message ${message.messageId}');
}

Future<void> initializeFirebase() async {
  // 初始化
  await Firebase.initializeApp();

  // iOS 請求通知權限許可
  if (Platform.isIOS) {
    await FirebaseMessaging.instance
        .requestPermission(sound: true, badge: true, alert: true);
  }

  // 前台
  FirebaseMessaging.onMessage.listen((RemoteMessage message) {
    print('Got a message whilst in the foreground!');
    print('Message data: ${message.data}');
    
    if (message.notification != null) {
      print('Message also contained a notification: ${message.notification}');
      
    }
  });

  // 後台點擊開啟
  FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
    print('A new onMessageOpenedApp event was published!');
    print('Message data: ${message.data}');
    if (message.notification != null) {
      print('Message also contained a notification: ${message.notification}');
    }
  });

  // 後台、離線
  FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
}

Future<void> main() async {
  // ...
    
  // 初始化前一定要加這句
  WidgetsFlutterBinding.ensureInitialized();
  await initializeFirebase();

  runApp(const ZcpApp());
}
```

但是 firebase 推送的通知在開啟 App 時，是不會顯示的，所以還要透過其他套件顯示：`flutter_local_notifications`

## `flutter_local_notifications`
:::info
[**參考教學**](https://hackmd.io/@yen2/SyeeSXntc/https%3A%2F%2Fhackmd.io%2FkfPTDa83RgO2ZtgZkLN9Xw)
:::
設定什麼的參考這篇：[**flutter_local_notifications**](/2h-QxN5VQZ2qjxBhYdTiRw)

### 使用範例
```javascript
class LocalNotifications {
  int notificationId = 0;

  // 創建 FlutterLocalNotificationsPlugin 實例，用於處理本地通知
  FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
      FlutterLocalNotificationsPlugin();

  // 初始化本地通知
  Future<void> initializeNotifications() async {
    flutterLocalNotificationsPlugin
        .resolvePlatformSpecificImplementation<
            AndroidFlutterLocalNotificationsPlugin>()
        ?.requestNotificationsPermission();

    // Android 平台的初始化設置
    const initializationSettingsAndroid = AndroidInitializationSettings('icon');
    // iOS 平台的初始化設置
    const DarwinInitializationSettings initializationSettingsIOS =
        DarwinInitializationSettings();
    // 整合所有平台的初始化設置
    const InitializationSettings initializationSettings =
        InitializationSettings(
      android: initializationSettingsAndroid,
      iOS: initializationSettingsIOS,
    );

    // 初始化本地通知插件
    await flutterLocalNotificationsPlugin.initialize(
      initializationSettings,
    );
  }

  // 顯示本地通知
  Future<void> showNotification(String title, String body) async {
    // 安卓平台的通知設置
    const AndroidNotificationDetails androidNotificationDetails =
        AndroidNotificationDetails('zcp', 'zcp',
            playSound: true,
            priority: Priority.high,
            importance: Importance.max);
    // iOS 平台的通知設置
    const DarwinNotificationDetails iOSPlatformChannelSpecifics =
        DarwinNotificationDetails();

    const NotificationDetails notificationDetails = NotificationDetails(
      android: androidNotificationDetails,
      iOS: iOSPlatformChannelSpecifics,
    );

    await flutterLocalNotificationsPlugin.show(
        notificationId, title, body, notificationDetails);
    notificationId++;
  }
}
```

### 遇到的一些問題

#### android 通知無法顯示
* 解決辦法：記得加上這段
    ```javascript
    flutterLocalNotificationsPlugin
        .resolvePlatformSpecificImplementation<
            AndroidFlutterLocalNotificationsPlugin>()
        ?.requestNotificationsPermission();
    ```