Created with to build something
Version: 5.0.0
cover-mengintegrasikan-flutter-local-notification-firebase-messaging

Codding

Mengintegrasikan Flutter Local Notification & Firebase Messaging

Tutorial mengenai penggunaan firebase messaging pada project flutter dan mengintegrasikannya dengan library flutter_local_notification

Nov 13, 2020

Notifikasi merupakan salah satu fitur terpenting yang tersematkan pada aplikasi mobile dalam hal mengantarkan sebuah informasi dalam bentuk singkat, dalam aplikasi yang berbasis mobile rasanya hal ini sangatlah begitu penting karena kemudahan yang ditawarkan pada smartphone sangat tidak cukup untuk menghandle dua aplikasi secara bersamaan. Diperangkat desktop mungkin anda cukup membuka banyak aplikasi untuk melihat informasi, sedangkan di aplikasi mobile anda perlu membuka aplikasi satu per satu untuk sebuah informasi yang begitu singkat.

Dalam membuat sebuah notifikasi pada flutter anda perlu menggunakan library flutter_local_notification, dengan library tersebut maka kamu bisa membuat dan menjadwalkan notifikasi yang akan ditampilkan. Akan tetapi saya ingin dapat menggunakan firebase cloud messaging sebagai layanan push notification pihak ketiga yang nantinya digunakan untuk menerima notifikasi.

Sebelum Memulai

Sebelum kita memulai project kita perlu memasang depedensi yang digunakan untuk memulai tutorial ini, karena menggunakan layanan firebase messaging pastikan anda sudah mengetahui dan telah menyelesaikan setup firebase console. Jika diperlukan maka bisa saja anda integrasikan dengan backend yang anda sukai, saat ini firebase admin SDK mendukung beberapa bahasa pemrograman seperti PHP, Javascript (NodeJS), Phyton, Java, Go, C#.

Silahkan buka project yang telah anda buat dan buka file pubspec.yaml, tambahkan depedensi firebase_messaging dan flutter_local_notification kurang lebih kodenya akan seperti ini.

dependencies:
  flutter:
    sdk: flutter
    ....
  firebase_messaging: ^7.0.3
  flutter_local_notifications: ^3.0.0

Simpan file tersebut dan jalankan perintah flutter pub get atau pub get dari terminal atau text editor maupun IDE yang sudah terintegrasi dengan flutter SDK dan dart SDK.

Tutorial ini menggunakan depedensi yang sesuai dengan versi pada contoh pubspec.yaml diatas, perbedaan kode dapat terjadi jika anda menggunakan versi paling terbaru.

Setup Firebase Messaging

Pertama kita akan mengimplementasikan firebase messaging ke dalam project flutter, pada tahap ini kalian perlu memperbarui setiap native module agar dapat berfungsi dengan baik. Pada tutorial ini saya hanya mengimplementasikan aplikasi ini pada sistem operasi android, untuk implementasi pada sistem operasi iOS kamu perlu melihat halaman dokumentasi lebih lanjut.

Menambahkan Firebase Key

Sebelum melakukan konfigurasi firebase lebih jauh, anda perlu mendaftarkan nama aplikasi yang anda buat pada firebase console untuk mendapatkan file identity key bernama google-services.json. Selain sebagai identitas file tersebut digunakan untuk credentials dalam mengakses project yang telah anda daftarkan pada firebase console.

Anda dapat membuat file google-services.json pada pengaturan project dari project firebase anda, lalu tambahkan aplikasi sesuai dengan jenisnya. Setelah berhasil anda dapat mengunduhnya, kurang lebih tampilannya akan seperti ini.

alt images

Letakkan file google-services.json pada direktori [rootproject]/android.

Menambah classpath baru

Karena nantinya kita akan menggunakan google services, maka kita perlu menambahkan classpath baru pada file build.gradle yang terdapat pada direktori root native android atau pada direktori [rootproject]/android/build.gradle.

dependencies {
  // Example existing classpath
  classpath 'com.android.tools.build:gradle:3.5.3'
  // Add the google services classpath
  classpath 'com.google.gms:google-services:4.3.2'
}

Silahkan simpan dan rebuild gradle tersebut baik menggunakan gradlew clean atau sejenisnya melalui integrasi IDE ataupun teks editor.

Menerapkan plugin baru

Setelah classpath telah ditambahkan apply plugin com.google.gms.google-services pada direktori [rootproject]/android/app/build.gradle

dependencies {
    ...
    // Tambahkan kode ini diantara dependencies
    implementation 'com.google.firebase:firebase-messaging:20.3.0'
    ....
}

// Kode paling bawah.
apply plugin: 'com.google.gms.google-services'

Mengubah Android Manifest

Tahap ini memungkinkan project flutter yang kita buat dalam menerima notifikasi ketika aplikasi sedang berjalan, hal ini sangat direkomendasikan untuk diterapkan. Letakkan kode intent-filter diantara baris <activity>

    <activity>
        .....
        <intent-filter>
            <action android:name="FLUTTER_NOTIFICATION_CLICK" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </activity>

Memperbarui MainActivity.kt

Setelah memperbarui beberapa konfigurasi, langkah terakhir yang diperlukan agar dapat menerima notifikasi secara background adalah memperbarui aplikasi native android pada file application.kt. Harap dicatat bahwa pada tutorial ini saya mendapatkan file kotlin sebagai base project native dari project flutter, sehingga mungkin akan sedikit berbeda dengan versi java.

Untuk tahap awal perbarui file MainActivity.kt yang terdapat pada direktori [rootproject/android/app/src/main/kotlin/com/[orgs]/[appname]/MainActivity.kt.

// Sesuaikan bagian ini dengan project yang anda miliki.
package com.orgs.appname

import io.flutter.embedding.android.FlutterActivity

class MainActivity: FlutterActivity() {
}

lalu langkah selanjutnya buat file baru bernama Application.kt pada direktori yang sama.

// Sesuaikan bagian ini dengan project yang anda miliki.
package com.orgs.appname

import io.flutter.app.FlutterApplication
import io.flutter.plugin.common.PluginRegistry
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback
import io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin
import io.flutter.view.FlutterMain
import io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService
import com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin

class Application : FlutterApplication(), PluginRegistrantCallback {
    override fun onCreate() {
        super.onCreate()
        FlutterFirebaseMessagingService.setPluginRegistrant(this);
        FlutterMain.startInitialization(this)
    }
    override fun registerWith(registry: PluginRegistry) {
        FirebaseMessagingPlugin.registerWith(registry.registrarFor("io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin"))
        FlutterLocalNotificationsPlugin.registerWith(registry!!.registrarFor("com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin"));
    }
}

Memperbarui AndroidManifest

Setelah tahap sebelumnya selesai maka anda perlu memperbarui properti android:name menjadi .Application, adapun contohnya dapat anda lihat dibawah ini :

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.orgs.appname">
    <!-- io.flutter.app.FlutterApplication is an android.app.Application that
         calls FlutterMain.startInitialization(this); in its onCreate method.
         In most cases you can leave this as-is, but you if you want to provide
         additional functionality it is fine to subclass or reimplement
         FlutterApplication and put your custom class here. -->
    <application
        android:name=".Application"
        android:label="Aplikasi"
        android:icon="@mipmap/ic_launcher"
        >

Menerapkan FCM pada Flutter

Untuk menerapkan FCM pada flutter mungkin harus diperhatikan bahwa sebagainya letakkan fungsi FCM pada root file flutter atau pada main.dart atau sejenisnya yang merupakan root file dari project flutter yang anda buat, sehingga secara tidak langsung hal ini dapat mempermudah dalam melakukan perbaikan.

Untuk menerapkan firebase messaging pada flutter, kalian dapat menerapkannya pada constructor dari widget yang telah kalian buat.

  _MainAppState() {
    /**
     * FCM Service Register on Main App State
     */
    _fcm.configure(
        onMessage: (Map<String, dynamic> message) async {
          print(message);
        },
        onLaunch: (Map<String, dynamic> message) async {
          print(message);
        },

        onResume: (Map<String, dynamic> message) async {
         print(message);
        }
    );
  }

Ada beberapa penjelasan mengenai konfigurasi yang diterapkan pada contoh diatas :

  • onMessage : Parameter yang dijalankan ketika aplikasi sedang berjalan, jadi ketika terdapat notifikasi baru masuk dan aplikasi sedang berjalan maka parameter ini akan berjalan..
  • onLaunch : Parameter yang dijalankan ketika aplikasi benar - benar tidak berjalan sama sekali, jadi jika terdapat notifikasi masuk dan aplikasi dalam kondisi tidak berjalan sama sekali maka parameter ini akan dijalankan.
  • onResume : Parameter ini dijalankan ketika aplikasi sedang berjalan di background, jadi ketika terdapat notifikasi masuk dan aplikasi sedang berjalan di background maka parameter ini akan dijalankan.
  • onBackgroundMessage : Parameter ini digunakan untuk melakukan handling notifikasi agar dapat berjalan di background.

Setup Flutter Local Notification

Kedua kita perlu mensetup flutter_local_notification sebagai depedensi yang akan digunakan untuk menampilkan notifikasi, secara default firebase_messaging juga dapat digunakan untuk menampilkan notifikasi hanya saja fungsinya sangat terbatas untuk keadaan tertentu seperti misalnya dalam hal membuat jadwal kapan notifikasi akan ditampilkan.

Memperbarui AndroidManifest

Jika anda ingin menggunakan atau berniat flutter_local_notification untuk menjadwalkan kapan notifikasi akan dimunculkan, anda dapat memperbarui androidmanifest dengan menambahkan sedikit permission.

        <receiver android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
                <action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
                <action android:name="android.intent.action.QUICKBOOT_POWERON" />
            </intent-filter>
        </receiver>

Contoh selengkapnya anda dapat lihat pada link ini,

Membuat Service Notification

Pada tahap ini kita akan membuat sebuah file yang nantinya akan digunakan untuk melakukan handling terhadap fitur notifikasi pada project flutter, pada tutorial kali ini saya hanya mencontohkan bagaimana cara menampilkan notifikasi dan menangani notifikasi ketika di tap pada daftar notifikasi menggunakan bantuan flutter_local_notification.

import 'dart:convert';

import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter/material.dart';

import 'notification_navigate.dart';

final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();

class LocalNotification {
  static Future<void> showNotification(dynamic payload) async {
    // Parsing data notifikasi
    final dynamic data = jsonDecode(payload['data']['data']);
    final dynamic notification = jsonDecode(payload['data']['notification']);
    
    // Parsing ID Notifikasi
    final int idNotification = data['id'] != null ? int.parse(data['id']) : 1;


    // Daftar jenis notifikasi dari aplikasi.
    const AndroidNotificationDetails androidPlatformChannelSpecifics = AndroidNotificationDetails(
        'BBD', 'Notification', 'All Notification is Here',
        importance: Importance.max,
        priority: Priority.high,
        ticker: 'ticker');
    const NotificationDetails platformChannelSpecifics = NotificationDetails(android: androidPlatformChannelSpecifics);
    
    // Menampilkan Notifikasi
    await flutterLocalNotificationsPlugin.show(
        idNotification, notification['title'], notification['body'], platformChannelSpecifics,
        payload: data['type']);
  }

  Future<void> notificationHandler(GlobalKey<NavigatorState> navigatorKey) async {
    // Pengaturan Notifikasi
    
    // AndroidInitializationSettings default value is 'app_icon'
    const AndroidInitializationSettings initializationSettingsAndroid = AndroidInitializationSettings('logo_bbd_sm');
    final InitializationSettings initializationSettings = InitializationSettings(android: initializationSettingsAndroid);
    
    // Handling notifikasi yang di tap oleh pengguna
    flutterLocalNotificationsPlugin.initialize(initializationSettings,
        onSelectNotification: (String payload) async {
          if (payload != null) {
            NavigatorNavigate().go(navigatorKey, payload);
          }
        });
  }
}

Ada beberapa yang seharusnya saya jelaskan diantaranya yaitu :

  1. Method showNotification memiliki parameter dynamic agar dapat menyesuaikan dengan jenis tipe data yang diterima oleh firebase messaging, alangkah baiknya jika kalian membuat model untuk mempermudah melakukan parsing sehingga kalian tidak perlu menebak - nebak apakah ini benar atau salah.
  2. Method notifiicationHandler akan menggunakan parameter navigator state untuk melakukan handling ketika notifikasi di tap maka aplikasi akan otomatis mengalihkannya ke halaman yang sesuai dengan tujuannya. Method ini hanya akan dijalankan sekali ketika screen utama dari aplikasi sudah di load, harap dipastikan bahwa method ini digunakan untuk berjalan sekali.
  3. Pada bagian AndroidInitializationSettings('logo_bbd_sm') pastikan anda menyesuaikannya dengan asset android yang terdapat pada direktori root android, jika anda menggunakan icon yang terdapat pada android_manifest gunakan parameter app_icon pada sehingga hasilnya seperti ini AndroidInitializationSettings('app_icon') .
  4. Penambahan asset berupa ikon aplikasi sangat disarankan untuk menggunakan Android Studio.

Karena pengecekkan terhadap jenis dari notifikasi yang diterima biasanya lumayan banyak, jadi untuk mempermudah pengembangan pengecekkan aksi navigasi pada notificationHandler akan dipisah. Pada file kedua saya akan membuat file service digunakan untuk membuat percabangan dimana di dalam percabangan ketika kondisinya benar maka aplikasi akan membuka screen yang sesuai dengan jenis notifikasi yang di tap.

....
import 'package:flutter/material.dart';

class NavigatorNavigate {
  go(GlobalKey<NavigatorState> navState, String type) {
    switch(type) {
      case 'login':
        navState.currentState.pushNamed('/');
        break;

      default:
        navState.currentState.pushNamed('error');
    }
  }
}

Memperbarui konfigurasi FCM.

Pada tahap ini kita akan mengintegrasikan flutter_local_notification yang sudah kita bungkus pada sebuah service dengan firebase messaging, ada beberapa catatan yang harus diketahui bahwa untuk menghandling backgroundMessage pada firebase messaging anda harus membuat sebuah method yang sifatnya static atau berada pada top level di luar class widget yang anda buat.

// Di letakkan sesudah mengimport depedencies yang diperlukan.
Future<dynamic> onBackgroundMessage(Map<String, dynamic> message) {
  return LocalNotification.showNotification(message);
}

Lalu perbarui firebase configurasi yang sudah dibuat hingga seperti ini :

  _MainAppState() {
    /**
     * FCM Service Register on Main App State
     */
    _fcm.configure(
        onMessage: (Map<String, dynamic> message) async {
          LocalNotification.showNotification(message);
        },
        onBackgroundMessage: onBackgroundMessage,
        onLaunch: (Map<String, dynamic> message) async {
          LocalNotification.showNotification(message);
        },

        onResume: (Map<String, dynamic> message) async {
          LocalNotification.showNotification(message);
        }
    );
  }

Perhatian anda perlu mengimport service yang sudah kalian buat untuk menjalankan flutter_local_notification

Memperbarui MaterialApp

Karena pada tutorial ini saya akan menerapkan sebuah event handling ketika notifikasi di tap maka akan otomatis membuka sebuah halaman tertentu, maka untuk mewujudkannya kita perlu memperbarui MaterialApp yang sudah kalian buat. Untuk mewujudkannya kita perlu membuat sebuah GlobalKey yang nantinya digunakan sebagai kunci untuk melakukan navigasi ke halaman yang dituju sesuai dengan notifikasi yang diterima, adapun contohnya adalah sebagai berikut :

...
  final GlobalKey<NavigatorState> navigatorKey = GlobalKey(debugLabel: "Main Navigator");
  LocalNotification().notificationHandler(navigatorKey);
      
  @override
  Widget build(BuildContext context) {
    return SlideTransition(
      position: _animation,
      child: MaterialApp(
        title: 'Aplikasi',
        debugShowCheckedModeBanner: false,
        navigatorKey: navigatorKey,
        theme: ThemeData(
          primarySwatch: Colors.blue,
          visualDensity: VisualDensity.adaptivePlatformDensity,
          canvasColor: Colors.transparent
        ),
        initialRoute: '/',
        onGenerateRoute: Routes().onGenerateRoute,
      ),
    );
  }
...

Beberapa Masalah Yang Diketahui

Dari tutorial ini dirilis saya mencatat terdapat beberapa masalah yang sebaiknya perlu diperhatikan :

Payload Firebase Cloud Messaging

Perlu di catat penggunaan library firebase_messaging hanya digunakan untuk menerima notifikasi dari akun firebase messaging yang kita daftarkan, itu menandakan bahwa anda perlu melakukan eksplorasi lebih jauh tentang penggunaan library ini. Dari beberapa tutorial yang ada di youtube, mungkin firebase_messaging belum sepowerfull library - library lainnya disamping hanya bisa digunakan untuk menerima pesan maupun hanya menampilkan notifikasi di background.

{
    "notification" : {
        // Data notifikasinya diisini
    }
}

Anda masih menemukan bahwa notifikasinya masih berjalan dengan baik ketika aplikasi sedang berjalan, namun ketika aplikasi ini di tutup dan berjalan di background notifikasi tidak dapat ditampilkan karena method pada onBackgroundMessage tidak dijalankan sehingga anda perlu mengakalinya dengan memasukan semua isi notifikasi dalam object data.

{
    "notification": {},
    "data": {
        "title" : "Ini Notifikasi",
        "body": "Ini isi notifikasi",
        "payload": "transaksi_010102",
        "id": 1311202002
    }
}

Pada tutorial ini saya menggunakan payload seperti ini karena firebase tidak menerima penggunaan object di dalam object sehingga payload yang mengandung object saya convert terlebih dahulu menjadi string atau text.

{
  "data" : {
    "notification": "{\n\"title\": \"Judul\",\n\"body\": \"Isi Judul\"\n}",
    "data": "{\n\"id\": \"01212\",\n\"type\": \"Transaksi\"\n}"
  }
}

Sebenarnya issue ini sudah dijelaskan pada dokumentasi library firebase_messaging pada bagian sending messages, hanya saja karena keterbatasan dokumentasi beberapa pengguna library ini cukup tampak kebingungan apalagi saya sebagai penulis.

Android Application Icon

Pada tutorial diatas saya melampirkan kode berikut untuk membuat pengaturan notifikasi pada ikon notifikasi yang nantinya akan ditampilkan.

const AndroidInitializationSettings initializationSettingsAndroid = AndroidInitializationSettings('logo_bbd_sm');

Merujuk pada kode tersebut bahwa flutter_local_notification dapat diatur penggunaan iconnya sesuai dengan kebutuhan, jika merujuk pada tutorial tersebut maka file ikon nantinya akan diletakkan pada drawable yang terletak pada root project android. Jika anda ingin mengubah pengaturan tersebut agar sesuai dengan pengaturan android manifest silahkan ubah parameter tersebut menjadi app_icon

const AndroidInitializationSettings initializationSettingsAndroid = AndroidInitializationSettings('app_icon');

Untuk merubah aplikasi ikon pada project anda saya lebih mereferensikan menggunakan android studio untuk melakukan itu, panduan penggunaannya dapat kalian lihat pada link berikut.

Contoh Kode

Untuk contoh dari tutorial ini anda dapat lihat pada gist github, perlu diketahui bahwa pada gist tersebut saya juga menggunakan bloclibrary sehingga anda dapat mengetahui bagaimana penggunaan FCM dalam melakukan subscribe topic dan menghapus instance key. Video demo ketika notifikasi di tap juga kalian dapat lihat pada link youtube berikut.

Jika kalian punya pertanyaan mengenai ini, silahkan tinggalkan di kolom komentar yaa.

Pembaruan Artikel

22 Februari 2021 : Pembaruan artikel terkait komentar pada link berikut.

Ingin Berkomentar ?

Gunakan fitur komentar dengan bijak demi keamanan dan kenyamanan anda saat berselancar di dunia maya ini, mungkin undang - undang atau peraturan dari sebagian wilayah akan menjerat aktivitas yang ada pada kolom komentar.