iT邦幫忙

2024 iThome 鐵人賽

DAY 25
0

在之前的章節中,我們大略的介紹了 Firebase,其中 Firebase Cloud Messaging(FCM) 是一個跨平台的訊息通知解決方案,可以說是幾乎所有的應用程式大概率都會需要的功能。能讓我們可以發送「推播通知」而不用花費簡訊費。

通過 FCM,我們可以通知客戶端例如有新訊息或者同步一些資訊。通過推播訊息可以令使用者重新使用我們的應用提高留存率。

建立範例專案

$ flutter create --org com.example fcm_demo

使用 --org 參數設定專案的組織資訊,可以幫助避免後續調整 iOS 的 Bundle ID 和 Android 的 Application ID。請注意參數的順序是會影響的。

安裝 Firebase Core

整合 Firebase 服務最簡單的方式是使用 FlutterFire CLI。首先,我們需要在 Firebase Console 建立一個專案,然後選擇「加入 Flutter 應用程式」。

在這之前,我們需要安裝 Firebase CLI。這裡展示 macOS 環境下的安裝步驟,其他作業系統的安裝方式可以參考官方教學

# 安裝 Firebase 指令
$ curl -sL https://firebase.tools | bash

# 登入
$ firebase login

# 列出專案
$ firebase projects:list

接著

# 啟動相關指令設定
$ dart pub global activate flutterfire_cli

# 設定專案
$ cd fcm_demo
$ flutterfire configure --project=fcm-demo
# 選擇要支援的平台,之後指令會協助自動設定

# 安裝 Firebase 核心庫
$ flutter pub add firebase_core

到此我們完成了基礎設定,可以通過 firebase_core 存取服務。

平台設定

發送推播通知的設定因平台而異。以下是針對 iOS 和 Android 的設定說明。

iOS

在我們發送訊息之前,我們需要針對個別的平台專案進行設定。首先 iOS 須啟用推播通知。使用 Xcode 開啟專案 ios/Runner.xcworkspace,選擇 Targets Runner 之後,點選上方頁籤「Signing & Capabilities」。第二排點擊「+Capability」選擇「Push Notification」,再次點擊「+Capability」選擇「Background Mode」勾選「Remote Notifications」。

接著在使用 FCM 之前還需要上傳 APN 憑證到 Firebase,到 Apple Developer 管理介面下載。

取得 APN 憑證之後,到 Firebase Console 介面,選擇專案設定,然後切換到 Cloud Messaging 即可上傳。

Android

FCM 客戶端需要 Android 4.4 以上,且須安裝 Google Play 服務。

在專案目錄的 android/build.gradle 檔案中,檢查是否有 google()

allprojects {
    repositories {
        google()
        mavenCentral()
    }
}

android/app/build.gradle 檔案中檢查 Google 服務插件:

plugins {
    ...
    id 'com.google.gms.google-services'
    ...
}

接著,安裝 Firebase Messaging 套件:

$ flutter pub add firebase_messaging

實作範例 & 測試發送

下面是簡單的 FCM 範例程式碼:

import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'firebase_options.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'FCM',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'FCM 範例'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String _token = 'None';
  String _message = 'No Message!';

  @override
  void initState() {
    super.initState();
    _initializeFCM();
  }

  void _initializeFCM() async {
    // 請求通知權限
    await FirebaseMessaging.instance.requestPermission(
      alert: true,
      announcement: false,
      badge: true,
      carPlay: false,
      criticalAlert: false,
      provisional: false,
      sound: true,
    );

    // 獲取 FCM token
    String? token = await FirebaseMessaging.instance.getToken();
    setState(() {
      _token = token ?? 'Token not available';
    });

    if (token != null) {
      print(token);
    }

    // 配置前台消息處理
    FirebaseMessaging.onMessage.listen((RemoteMessage message) {
      print("Received message: ${message.notification?.body}");
      setState(() {
        _message = message.notification?.body ?? 'Empty message body';
      });
    });

    // 配置後台消息處理
    FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text('FCM Token:'),
            Text(_token, style: TextStyle(fontWeight: FontWeight.bold)),
            const SizedBox(height: 20),
            const Text('Last Received Message:'),
            Text(_message, style: TextStyle(fontWeight: FontWeight.bold)),
          ],
        ),
      ),
    );
  }
}

// 處理後台消息的函數
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  await Firebase.initializeApp();
  print("Handling a background message: ${message.messageId}");
}

接著到 Firebase Console > Cloud Messaging 建立 Campaign。從開發編輯器取得 token 之後,可以測試發送訊息。到此我們快速的實作了簡單的範例。過程還有些具體細節會因為版本更新而有所差異,建議參考官方設定。

參考資料


上一篇
Day 24 使用 Google Map
下一篇
Day 26
系列文
Flutter 開發實戰 - 30 天逃離新手村26
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言