web analytics

Flutter : แสดง Notification ด้วย Firebase Messaging ใน Flutter

สวัสดีผู้อ่านครับ จากตอนที่แล้วผมได้ลองเล่นเกี่ยวกับการแสดง Notification ใน Flutter ไปแล้ว ซึ่งป็นการใช้งานคำสั่งให้แสดง notification จากตัวแอปเอง แต่ในงานจริงๆการแสดง notification จะมาจากการส่งที่ server หรือหลังบ้าน ดังนั้นการทำให้แสดง notification แบบ offline จะยังไม่เพียงพอ ควรต้องเพิ่มส่วนต่อขยายให้แอปสามารถรับผลจาก server แล้วแสดง notification ได้นั่นเอง ซึ่งในที่นี้พระเอกคือ Firebase Cloud Messaging (FCM) จะช่วยให้เราสามารถส่ง notification มายังแอปได้ เอาละมาลองเล่นกัน

ใครยังไม่ได้อ่านในตอนที่แล้ว เพราะบล็อกนี้เป็นภาคต่อ แนะนำอ่านก่อนนะครับ

ติดตั้ง Firebase ใน project

ในบล็อกนี้จะไม่อธิบายขั้นตอนการติดตั้ง firebase นะครับ เพราะมีอธิบายไว้ในเว็บของ firebase แล้วทั้ง iOS และ Android

เพิ่ม dependencies

เพิ่ม firebase_messaging และ firebase_core ใน pubspec.yaml

dependencies:
  ..
  flutter_local_notifications: 0.7.0
  http: 0.12.0+2
  path_provider: 0.5.0+1
  firebase_messaging: 4.0.0+4
  firebase_core: ^0.3.0

หากมี error ลองเปลี่ยนเวอชั่นใน android/build.gradle เป็น 3.3.2

buildscript {
    ..
    dependencies {
        classpath 'com.android.tools.build:gradle:3.3.2'

การใช้งาน

import ไฟล์ firebase_messaging เข้ามา

import 'package:firebase_messaging/firebase_messaging.dart';

ประกาศตัวแปร FirebaseMessaging

class _MyHomePageState extends State<MyHomePage> {
  FirebaseMessaging firebaseMessaging = FirebaseMessaging();

จุดสำคัญอยู่ตรงนี้คือ firebaseMessaging.configure()
ซึ่ง callback ของมัน คือ onMessage ที่ถูกเรียกเมื่อมี noti ส่งเข้ามา

 @override
 initState(){
   initFirebaseMessaging();
   super.initState();
  }

  void initFirebaseMessaging() {
    firebaseMessaging.configure(
      onMessage: (Map<String, dynamic> message) async {
        print("onMessage: $message");
      },
      onLaunch: (Map<String, dynamic> message) async {
        print("onLaunch: $message");
      },
      onResume: (Map<String, dynamic> message) async {
        print("onResume: $message");
      },
    );

    firebaseMessaging.requestNotificationPermissions(
        const IosNotificationSettings(sound: true, badge: true, alert: true));
    firebaseMessaging.onIosSettingsRegistered
        .listen((IosNotificationSettings settings) {
      print("Settings registered: $settings");
    });

    firebaseMessaging.getToken().then((String token) {
      assert(token != null);
      print("Token : $token");
    });
  }
}

ลองใช้งานกัน ก่อนอื่นเราจะทดสอบส่ง noti แบบใช้ token ที่ได้มาจากจากคำสั่ง getToken()

ไปที่เว็บ firebase สร้าง notification ใหม่ ใส่ title , body

จากนั้นกดที่ send test message แล้วเอา token วางลงไป กดส่ง test ได้เลย

สิ่งที่ได้คือ มันจะวิ่งมาที่ onMessage แล้วมี data มาให้ ประมาณนี้

{notification: {title: Hello, body: benznest} data:{}}

เราก็แค่เอา data ที่ได้รับแปลงออกมา แล้วเรียกใช้คำสั่ง notification จาก library ในตอนที่แล้ว

 firebaseMessaging.configure(
      onMessage: (Map<String, dynamic> message) async {
        print("onMessage: $message");
        Map mapNotification = message["notification"];
        String title = mapNotification["title"];
        String body = mapNotification["body"];
        sendNotification(title: title, body: body);
      }
      ..
  }

เท่านี้ก็กดส่ง noti จาก firebase ไปแสดงในแอปได้แล้ว

ส่ง Noti แบบแนบ data

ที่ firebase เราสามารถแนบ data ที่มี key ไปด้วยได้ ซึ่งจะอยู่ในหัวข้อ Additional แล้วก็ถ้ามี channel ก็ให้ใส่ Channel ให้ตรงกับที่เรากำหนดไว้ด้วย

ค่าที่ได้ใน onMessage จะเป็นประมาณนี้ ก็คือ data จะอยู่ใน key ที่ชื่อว่า data นั่นเอง

{notification: {title: Hello, body: benznest}, data: {job: developer}}

Subscribe

การส่ง noti อีกแบบคือ การส่งแบบไปให้คนที่อยู่ในกลุ่มที่เรากำหนด ใน firebase เรียก topic ก็คือให้เรากำหนด topic แล้วให้ผู้ใช้มา subscribe ว่าอยู่ใน topic นี้ จากนั้นเราสามารถส่ง noti ไปหาทุกคนใน topic ในคราวเดียวได้เลย

การใช้งานง่ายมากคือ subscribeToTopic แล้วกำหนดชื่อ topic
หากอยากออกจาก topic ก็ใช้ unsubscribeFromTopic

firebaseMessaging.subscribeToTopic("NEWS");   // subscribe topic News
firebaseMessaging.unsubscribeFromTopic("NEWS");

การส่ง noti ไปแบบ topic นี้สามารถกำหนดได้ที่หัวข้อ Target

ลองใช้งานกัน ผมจะเพิ่มสวิทตัวนึง เอาไว้เลือกว่าต้องการ subscribe ไหม

class _MyHomePageState extends State<MyHomePage> {
  bool isSubscribeHotNews= false;
  ..

เพิ่ม Switch โดยถ้า switch เปิดก็ subscribe หากปิดจะเป็น unsubscribe

            Container(
              decoration: BoxDecoration(
                  color: Colors.blue[50],
                  borderRadius: BorderRadius.circular(6),
                  border: Border.all(width: 1, color: Colors.black54)),
              padding: EdgeInsets.all(16),
              margin: EdgeInsets.all(16),
              child: Column(children: <Widget>[
                Text("Subscribe news "),
                Switch(
                    value: isSubscribeHotNews,
                    onChanged: (checked) {
                      if(checked) {
                        firebaseMessaging.subscribeToTopic("NEWS");
                      }else{
                        firebaseMessaging.unsubscribeFromTopic("NEWS");
                      }
                      setState(() => isSubscribeHotNews = checked);
                    })
              ]),
            )

ผลคือ หากเปิด switch ก็สามารถส่งแจ้งเตือนมาได้ แต่หากปิดแจ้งเตือนก็จะไม่มานั่นเอง

Firebase Messaging + Local Notification

ตอนนี้ Firebase Messaging สามารถใช้งานร่วมกับ local_notification ใน iOS ได้แล้ว หลัวจากที่ก่อนหน้านี้มีปัญหา conflict กัน

  firebase_messaging: ^5.1.2
  flutter_local_notifications: ^0.8.0