Catch up on everything announced at Firebase Summit, and learn how Firebase can help you accelerate app development and run your app with confidence. Learn More

รับข้อความในแอป Flutter

จัดทุกอย่างให้เป็นระเบียบอยู่เสมอด้วยคอลเล็กชัน บันทึกและจัดหมวดหมู่เนื้อหาตามค่ากำหนดของคุณ

ข้อความขาเข้าจะได้รับการจัดการแตกต่างกันไปขึ้นอยู่กับสถานะของอุปกรณ์ เพื่อให้เข้าใจสถานการณ์เหล่านี้และวิธีรวม FCM เข้ากับแอปพลิเคชันของคุณเอง สิ่งสำคัญอันดับแรกคือต้องกำหนดสถานะต่างๆ ที่อุปกรณ์สามารถเป็นได้:

สถานะ คำอธิบาย
เบื้องหน้า เมื่อแอปพลิเคชันเปิดอยู่ในมุมมองและใช้งานอยู่
พื้นหลัง เมื่อแอปพลิเคชันเปิดอยู่ แต่อยู่ในพื้นหลัง (ย่อเล็กสุด) กรณีนี้มักเกิดขึ้นเมื่อผู้ใช้กดปุ่ม "หน้าแรก" บนอุปกรณ์ เปลี่ยนไปใช้แอปอื่นโดยใช้ตัวสลับแอป หรือเปิดแอปพลิเคชันในแท็บอื่น (เว็บ)
สิ้นสุด เมื่ออุปกรณ์ถูกล็อกหรือแอปพลิเคชันไม่ทำงาน

มีเงื่อนไขเบื้องต้นบางประการที่ต้องปฏิบัติตามก่อนที่แอปพลิเคชันจะสามารถรับเพย์โหลดข้อความผ่าน FCM:

  • ต้องเปิดแอปพลิเคชันอย่างน้อยหนึ่งครั้ง (เพื่อให้สามารถลงทะเบียนกับ FCM)
  • บน iOS หากผู้ใช้ปัดแอปพลิเคชันออกจากตัวสลับแอป จะต้องเปิดแอปนั้นใหม่ด้วยตนเองเพื่อให้ข้อความพื้นหลังเริ่มทำงานอีกครั้ง
  • ใน Android หากผู้ใช้บังคับปิดแอปจากการตั้งค่าอุปกรณ์ จะต้องเปิดแอปอีกครั้งด้วยตนเองเพื่อให้ข้อความเริ่มทำงาน
  • บนเว็บ คุณต้องขอโทเค็น (โดยใช้ getToken() ) กับใบรับรองการพุชเว็บของคุณ

ขออนุญาตรับข้อความ (Apple และ Web)

บน iOS, macOS และเว็บ ก่อนที่จะสามารถรับเพย์โหลด FCM บนอุปกรณ์ของคุณได้ คุณต้องขออนุญาตจากผู้ใช้ก่อน

แพ็คเกจ firebase_messaging มี API อย่างง่ายสำหรับการขออนุญาตผ่านเมธอด requestPermission API นี้ยอมรับอาร์กิวเมนต์ที่มีชื่อจำนวนหนึ่งซึ่งกำหนดประเภทของการอนุญาตที่คุณต้องการขอ เช่น การส่งข้อความที่มีเพย์โหลดการแจ้งเตือนสามารถเรียกเสียงหรืออ่านข้อความผ่าน Siri ได้หรือไม่ โดยค่าเริ่มต้น เมธอดจะร้องขอสิทธิ์เริ่มต้นที่เหมาะสม API อ้างอิงมีเอกสารฉบับเต็มเกี่ยวกับการอนุญาตแต่ละรายการ

ในการเริ่มต้น ให้เรียกใช้เมธอดจากแอปพลิเคชันของคุณ (บน iOS จะแสดงโมดอลแบบเนทีฟ และบนเว็บ โฟลว์ API แบบเนทีฟของเบราว์เซอร์จะถูกทริกเกอร์):

FirebaseMessaging messaging = FirebaseMessaging.instance;

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

print('User granted permission: ${settings.authorizationStatus}');

สามารถใช้คุณสมบัติ authorizationStatus ของอ็อบเจกต์ NotificationSettings ที่ส่งกลับจากคำขอเพื่อพิจารณาการตัดสินใจโดยรวมของผู้ใช้:

  • authorized : ผู้ใช้ได้รับอนุญาต
  • denied : ผู้ใช้ปฏิเสธการอนุญาต
  • notDetermined : ผู้ใช้ยังไม่ได้เลือกว่าจะอนุญาตหรือไม่
  • provisional : ผู้ใช้ได้รับอนุญาตชั่วคราว

คุณสมบัติอื่น ๆ ในการตั้งค่า NotificationSettings จะส่งคืนว่ามีการเปิดใช้งาน ปิดใช้งาน หรือไม่รองรับการอนุญาตเฉพาะในอุปกรณ์ปัจจุบัน

เมื่อได้รับอนุญาตและเข้าใจสถานะอุปกรณ์ประเภทต่างๆ แล้ว แอปพลิเคชันของคุณสามารถเริ่มจัดการกับเพย์โหลด FCM ที่เข้ามาได้แล้ว

การจัดการข้อความ

ขึ้นอยู่กับสถานะปัจจุบันของแอปพลิเคชันของคุณ เพย์โหลดขาเข้าของ ข้อความประเภทต่างๆ จำเป็นต้องมีการใช้งานที่แตกต่างกันเพื่อจัดการ:

ข้อความเบื้องหน้า

หากต้องการจัดการข้อความขณะที่แอปพลิเคชันของคุณอยู่เบื้องหน้า ให้ฟังสตรีม onMessage

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}');
  }
});

สตรีมประกอบด้วย RemoteMessage ซึ่งให้รายละเอียดข้อมูลต่างๆ เกี่ยวกับเพย์โหลด เช่น แหล่งที่มา ID เฉพาะ เวลาที่ส่ง มีการแจ้งเตือนหรือไม่ และอื่นๆ เนื่องจากมีการดึงข้อความในขณะที่แอปพลิเคชันของคุณอยู่เบื้องหน้า คุณจึงสามารถเข้าถึงสถานะและบริบทของแอปพลิเคชัน Flutter ได้โดยตรง

ข้อความเบื้องหน้าและการแจ้งเตือน

ข้อความแจ้งเตือนที่มาถึงในขณะที่แอปพลิเคชันอยู่เบื้องหน้าจะไม่แสดงการแจ้งเตือนที่มองเห็นได้ตามค่าเริ่มต้น ทั้งบน Android และ iOS อย่างไรก็ตาม เป็นไปได้ที่จะแทนที่พฤติกรรมนี้:

  • บน Android คุณต้องสร้างช่องทางการแจ้งเตือน "ลำดับความสำคัญสูง"
  • บน iOS คุณสามารถอัปเดตตัวเลือกการนำเสนอสำหรับแอปพลิเคชันได้

ข้อความพื้นหลัง

กระบวนการจัดการข้อความพื้นหลังจะแตกต่างกันในแพลตฟอร์มเนทีฟ (Android และ Apple) และบนเว็บ

แพลตฟอร์ม Apple และ Android

จัดการข้อความพื้นหลังโดยลงทะเบียนตัวจัดการ onBackgroundMessage เมื่อได้รับข้อความ การแยกจะถูกสร้างขึ้น (เฉพาะ Android, iOS/macOS ไม่ต้องการการแยกแยกต่างหาก) ช่วยให้คุณจัดการข้อความได้แม้ในขณะที่แอปพลิเคชันของคุณไม่ได้ทำงานอยู่

มีบางสิ่งที่ควรทราบเกี่ยวกับตัวจัดการข้อความพื้นหลังของคุณ:

  1. จะต้องไม่เป็นฟังก์ชันนิรนาม
  2. ต้องเป็นฟังก์ชันระดับบนสุด (เช่น ไม่ใช่เมธอดคลาสที่ต้องเตรียมใช้งาน)
  3. ต้องมีคำอธิบายประกอบด้วย @pragma('vm:entry-point') เหนือการประกาศฟังก์ชัน (มิฉะนั้นอาจถูกลบออกระหว่างการเขย่าต้นไม้สำหรับโหมดรีลีส)
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  // If you're going to use other Firebase services in the background, such as Firestore,
  // make sure you call `initializeApp` before using other Firebase services.
  await Firebase.initializeApp();

  print("Handling a background message: ${message.messageId}");
}

void main() {
  FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
  runApp(MyApp());
}

เนื่องจากตัวจัดการทำงานในแยกของตัวเองนอกบริบทแอปพลิเคชันของคุณ จึงไม่สามารถอัปเดตสถานะแอปพลิเคชันหรือดำเนินการ UI ที่ส่งผลกระทบต่อลอจิกได้ อย่างไรก็ตาม คุณสามารถดำเนินการตรรกะ เช่น คำขอ HTTP, ดำเนินการ IO (เช่น อัปเดตที่เก็บข้อมูลในเครื่อง), สื่อสารกับปลั๊กอินอื่น ๆ เป็นต้น

ขอแนะนำให้กรอกตรรกะของคุณโดยเร็วที่สุด การทำงานที่ยาวนานและเข้มข้นส่งผลกระทบต่อประสิทธิภาพของอุปกรณ์และอาจทำให้ระบบปฏิบัติการยุติกระบวนการ หากทำงานนานกว่า 30 วินาที อุปกรณ์อาจหยุดกระบวนการโดยอัตโนมัติ

เว็บ

บนเว็บ ให้เขียน JavaScript Service Worker ซึ่งทำงานในพื้นหลัง ใช้พนักงานบริการเพื่อจัดการข้อความพื้นหลัง

ในการเริ่มต้น ให้สร้างไฟล์ใหม่ในไดเร็กทอรี web ของคุณ และเรียกมันว่า firebase-messaging-sw.js :

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

firebase.initializeApp({
  apiKey: "...",
  authDomain: "...",
  databaseURL: "...",
  projectId: "...",
  storageBucket: "...",
  messagingSenderId: "...",
  appId: "...",
});

const messaging = firebase.messaging();

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

ไฟล์ต้องนำเข้าทั้งแอปและ SDK การส่งข้อความ เริ่มต้น Firebase และเปิดเผยตัวแปร messaging

ถัดไปจะต้องลงทะเบียนคนงาน ภายในไฟล์รายการ หลังจาก โหลดไฟล์ main.dart.js แล้ว ให้ลงทะเบียนผู้ปฏิบัติงานของคุณ:

<html>
<body>
  ...
  <script src="main.dart.js" type="application/javascript"></script>
  <script>
       if ('serviceWorker' in navigator) {
          // Service workers are supported. Use them.
          window.addEventListener('load', function () {
            // ADD THIS LINE
            navigator.serviceWorker.register('/firebase-messaging-sw.js');

            // Wait for registration to finish before dropping the <script> tag.
            // Otherwise, the browser will load the script multiple times,
            // potentially different versions.
            var serviceWorkerUrl = 'flutter_service_worker.js?v=' + serviceWorkerVersion;

            //  ...
          });
      }
  </script>

ถัดไปรีสตาร์ทแอปพลิเคชัน Flutter ของคุณ ผู้ปฏิบัติงานจะได้รับการลงทะเบียนและข้อความเบื้องหลังจะถูกจัดการผ่านไฟล์นี้

ปฏิสัมพันธ์การจัดการ

เนื่องจากการแจ้งเตือนเป็นสิ่งที่มองเห็นได้ จึงเป็นเรื่องปกติที่ผู้ใช้จะโต้ตอบกับพวกเขา (โดยการกด) ลักษณะการทำงานเริ่มต้นทั้งบน Android และ iOS คือเปิดแอปพลิเคชัน หากแอปพลิเคชันถูกยกเลิก แอปพลิเคชันจะเริ่มทำงาน หากอยู่ในพื้นหลังก็จะถูกนำไปที่เบื้องหน้า

คุณอาจต้องการจัดการการโต้ตอบของผู้ใช้เมื่อแอปพลิเคชันเปิดขึ้น ทั้งนี้ขึ้นอยู่กับเนื้อหาของการแจ้งเตือน ตัวอย่างเช่น หากข้อความแชทใหม่ถูกส่งผ่านการแจ้งเตือนและผู้ใช้กดข้อความนั้น คุณอาจต้องการเปิดการสนทนาที่ต้องการเมื่อแอปพลิเคชันเปิดขึ้น

แพ็คเกจ firebase-messaging มีสองวิธีในการจัดการการโต้ตอบนี้:

  • getInitialMessage() : หากแอปพลิเคชันถูกเปิดจากสถานะสิ้นสุด Future ที่มี RemoteMessage จะถูกส่งคืน เมื่อใช้แล้ว RemoteMessage จะถูกลบออก
  • onMessageOpenedApp : Stream ที่โพสต์ RemoteMessage เมื่อเปิดแอปพลิเคชันจากสถานะเบื้องหลัง

ขอแนะนำให้จัดการทั้งสองสถานการณ์เพื่อให้แน่ใจว่า UX ที่ราบรื่นสำหรับผู้ใช้ของคุณ ตัวอย่างโค้ดด้านล่างแสดงวิธีการบรรลุผลสำเร็จ:

class Application extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _Application();
}

class _Application extends State<Application> {
  // It is assumed that all messages contain a data field with the key 'type'
  Future<void> setupInteractedMessage() async {
    // Get any messages which caused the application to open from
    // a terminated state.
    RemoteMessage? initialMessage =
        await FirebaseMessaging.instance.getInitialMessage();

    // If the message also contains a data property with a "type" of "chat",
    // navigate to a chat screen
    if (initialMessage != null) {
      _handleMessage(initialMessage);
    }

    // Also handle any interaction when the app is in the background via a
    // Stream listener
    FirebaseMessaging.onMessageOpenedApp.listen(_handleMessage);
  }

  void _handleMessage(RemoteMessage message) {
    if (message.data['type'] == 'chat') {
      Navigator.pushNamed(context, '/chat',
        arguments: ChatArguments(message),
      );
    }
  }

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

    // Run code required to handle interacted messages in an async function
    // as initState() must not be async
    setupInteractedMessage();
  }

  @override
  Widget build(BuildContext context) {
    return Text("...");
  }
}

วิธีจัดการกับการโต้ตอบขึ้นอยู่กับการตั้งค่าแอปพลิเคชันของคุณ ตัวอย่างด้านบนแสดงภาพประกอบพื้นฐานโดยใช้ StatefulWidget

แปลข้อความ

คุณสามารถส่งสตริงที่แปลเป็นภาษาท้องถิ่นได้สองวิธี:

  • จัดเก็บภาษาที่ต้องการของผู้ใช้แต่ละคนในเซิร์ฟเวอร์ของคุณ และส่งการแจ้งเตือนที่กำหนดเองสำหรับแต่ละภาษา
  • ฝังสตริงที่แปลเป็นภาษาท้องถิ่นในแอปของคุณและใช้ประโยชน์จากการตั้งค่าภาษาท้องถิ่นของระบบปฏิบัติการ

นี่คือวิธีการใช้วิธีที่สอง:

แอนดรอยด์

  1. ระบุข้อความภาษาเริ่มต้นของคุณใน resources/values/strings.xml :

    <string name="notification_title">Hello world</string>
    <string name="notification_message">This is a message</string>
    
  2. ระบุข้อความที่แปลในไดเร็กทอรี values- language ค่า ตัวอย่างเช่น ระบุข้อความภาษาฝรั่งเศสใน resources/values-fr/strings.xml :

    <string name="notification_title">Bonjour le monde</string>
    <string name="notification_message">C'est un message</string>
    
  3. ใน payload ของเซิร์ฟเวอร์ แทนที่จะใช้ title message และคีย์ body ให้ใช้ title_loc_key และ body_loc_key สำหรับข้อความที่แปลเป็นภาษาท้องถิ่นของคุณ และตั้งค่าให้เป็นแอตทริบิวต์ name ของข้อความที่คุณต้องการแสดง

    เพย์โหลดข้อความจะมีลักษณะดังนี้:

    {
      "data": {
        "title_loc_key": "notification_title",
        "body_loc_key": "notification_message"
      },
    }
    

iOS

  1. ระบุข้อความภาษาเริ่มต้นของคุณใน Base.lproj/Localizable.strings :

    "NOTIFICATION_TITLE" = "Hello World";
    "NOTIFICATION_MESSAGE" = "This is a message";
    
  2. ระบุข้อความที่แปลในไดเร็กทอรี language .lproj ตัวอย่างเช่น ระบุข้อความภาษาฝรั่งเศสใน fr.lproj/Localizable.strings :

    "NOTIFICATION_TITLE" = "Bonjour le monde";
    "NOTIFICATION_MESSAGE" = "C'est un message";
    

    เพย์โหลดข้อความจะมีลักษณะดังนี้:

    {
      "data": {
        "title_loc_key": "NOTIFICATION_TITLE",
        "body_loc_key": "NOTIFICATION_MESSAGE"
      },
    }
    

เปิดใช้งานการส่งออกข้อมูลการส่งข้อความ

คุณส่งออกข้อมูลข้อความไปยัง BigQuery เพื่อวิเคราะห์เพิ่มเติมได้ BigQuery ช่วยให้คุณวิเคราะห์ข้อมูลโดยใช้ BigQuery SQL ส่งออกไปยังผู้ให้บริการระบบคลาวด์รายอื่น หรือใช้ข้อมูลสำหรับโมเดล ML ที่กำหนดเอง การส่งออกไปยัง BigQuery จะรวมข้อมูลที่มีอยู่ทั้งหมดสำหรับข้อความ โดยไม่คำนึงถึงประเภทข้อความหรือว่าข้อความนั้นส่งผ่าน API หรือตัวเขียนการแจ้งเตือนหรือไม่

หากต้องการเปิดใช้งานการส่งออก ก่อนอื่นให้ทำตามขั้นตอน ที่อธิบายไว้ที่นี่ จากนั้นทำตามคำแนะนำเหล่านี้:

แอนดรอยด์

คุณสามารถใช้โค้ดต่อไปนี้: dart await FirebaseMessaging.instance.setDeliveryMetricsExportToBigQuery(true);

iOS

สำหรับ iOS คุณต้องเปลี่ยน AppDelegate.m ด้วยเนื้อหาต่อไปนี้

#import "AppDelegate.h"
#import "GeneratedPluginRegistrant.h"
#import <Firebase/Firebase.h>

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [GeneratedPluginRegistrant registerWithRegistry:self];
  // Override point for customization after application launch.
  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

- (void)application:(UIApplication *)application
    didReceiveRemoteNotification:(NSDictionary *)userInfo
          fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
  [[FIRMessaging extensionHelper] exportDeliveryMetricsToBigQueryWithMessageInfo:userInfo];
}

@end

เว็บ

สำหรับเว็บ คุณต้องเปลี่ยนพนักงานบริการของคุณเพื่อใช้ SDK เวอร์ชัน v9 ต้องรวมเวอร์ชัน v9 ดังนั้นคุณต้องใช้ตัวรวมเช่น esbuild เพื่อให้เจ้าหน้าที่บริการทำงาน ดู แอปตัวอย่าง เพื่อดูวิธีการบรรลุเป้าหมายนี้

เมื่อคุณย้ายไปที่ v9 SDK แล้ว คุณสามารถใช้รหัสต่อไปนี้:

import {
  experimentalSetDeliveryMetricsExportedToBigQueryEnabled,
  getMessaging,
} from 'firebase/messaging/sw';

...

const messaging = getMessaging(app);
experimentalSetDeliveryMetricsExportedToBigQueryEnabled(messaging, true);

อย่าลืมรัน yarn build เพื่อส่งออก Service Worker เวอร์ชันใหม่ไปยังโฟลเดอร์ web