Bu uygulama ile firebase messaging kullanarak nasıl bildirim alacağımızı anlatacağım.

FCM: Firebase Cloud Messaging Nedir?

Firebase, Google tarafından sağlanan ücretsiz (evet, sıfır maliyetli!) bir çapraz platform çözüm ailesidir. Çeşitli platformlarda kullanmak için özelleştirilmiş pek çok farklı servisi içerisinde bulunduruyor.

Firebase Cloud Messaging (FCM), çok çeşitli mesajlaşma seçenekleri ve özellikleri sunan Firebase’e bağlı bir servistir. FCM; Android ve IOS ortamları için uygulamalar arası mesaj gönderebilme ve bu uygulamayı kullanan kullanıcılara ve istemcilere mesaj gönderebiliriz.

FCM ile istemcilere iki tür mesaj gönderebilirsiniz:

  • “Ekran mesajları” olarak düşünülen bildirim mesajları. Bunlar, FCM SDK tarafından otomatik olarak işlenen mesajlardır.
  • İstemci uygulaması tarafından işlenen veri mesajları.

Bu makalede size hem Android hem de iOS’ta push bildirimlerini nasıl uygulayacağınızı göstereceğim.

Firebase Uygulaması İçin Gereklilikler

  • Bir Telefon (Android veya IOS)
  • Firebase servisinde bir proje açmak.

Firebase’i Android veya iOS uygulamanıza eklemeden önce bir Firebase projesi oluşturmanız gerekir. Bundan sonra, her platform için kurulum yapmak üzere aşağıdaki adımları takip edebilirsiniz.

  1. https://console.firebase.google.com/ Adresine girip kendi Google Mail Adresimiz ile giriş yapıyoruz. Bizi girişin ardından şöyle bir ekran karşılayacak. Ben daha önceden beri kullandığım için 2 projem halihazırda var ama bunu önemsemeyin.

2. Add project yazan butona tıklayalım. Önümüze açılan pencerede bize projemizin adı sorulacak.

Bu adımda projemize ben fcm-push-notifications adını vereceğim. Aşağı kaydırdığımızda Google Analitics’i bize sormakta. Şimdilik zararı yok. Açık kalsın. (Bazı durumlarda bunu kapatmak firebase servislerinden bazılarını kullanırken sorun yaşattığı için ben hep açık tutuyorum. Sorun kendi firebase yapılandırmam ile alakalı da olabilir ama yine de kişisel tercihim bu yönde.)

Şimdiki adımda ise bize analitics için kullanılacak kullanıcı sorulmakta. Ben öntanımlı Firebase kullanıcısını yaptım.

Eğer ki siz bir kuruma bağlı çalışıyorsanız ve bu kurumun kendi analitics hesabı varsa onu da kullanabilirsiniz.

Ve şimdi de projeyi oluşturmaya bırakalım. Çok kısa süren bir süreç. Yaklaşık 20 saniyede proje hazırlanmış olacak.

Projemiz oluşmasının ardından ileride Flutter uygulamamız içerisinde bu projeyi kullanacağız. Şimdi proje sayfamıza devam edelim.

Açılan ilk sayfamızda bizden bir firebase uygulaması oluşturmamızı tavsiye eden bir pencere bulunuyor.

Biz bu sayfada pencerenin sol tarafındaki işaretciklerden cloud messaging sayfasını kullanacağız. Bu sayfa genelde yandaki panelin en sonunda yer almaktadır. Paneli kaydırarak ulaşabilirsiniz.

Sonraki adımda hemen bir flutter uygulaması açıp geri gelelim

Flutter Uygulamasını Oluşturmak

Flutter ile yeni bir uygulama açalım.

$ flutter create new fcm_push_notification

Şimdi bu uygulamayı null-safety’e taşıyalım.

$ cd fcm_push_notification
$ dart migrate --apply-changes

Bu uygulamayı başlattığımızda karşımıza standart bir flutter başlangıç uygulaması çıkacak.

$ flutter run

FCM servisini kullanmak için bizim firebase_messaging bağımlılığını projeye eklememiz gerekmekte. Bunun için aşağıdaki komutu kullanabilir:

$ flutter pub add firebase_messaging

veya elle bu bağımlılığı pubspec.yaml üzerine ekleyebiliriz:

dependencies:  firebase_messaging: ^9.1.2

Şimdi bağımlılıkları getirelim.

$ flutter pub get

Bu adımdan sonra FCM için gerekliliklerimizi yapılandırıp uygulamamızı çalışır hale getirebiliriz.

Uygulamamızda ayrıca bu mesajları local notification servisi olarak almak istiyorsanız, ki ben de tam olarak bunu yapacağım, bir de flutter_local_notifications bağımlılığı gerekmekte. Yine onun için de:

$ flutter pub add flutter_local_notifications

veya elle bu bağımlılığı pubspec.yaml üzerine ekleyebiliriz:

dependencies:  firebase_messaging: ^9.1.2

Firebase Üzerinden Uygulama Oluşturmak

Öncelikle firebase üzerine bir uygulama açarak başlayalım.

Android İçin

İlk çıkan ekranda yer alan Android Package Name için projemizin android/app/src/main/AndroidManifest.xml yolunda bulunan manifest dosyasından package olarak verilen uygulama adını alıp yapıştırın.

Diğer boşlukları da uygun şekilde dolduralım

Register app için tıkladığımızda bizim için bir config dosyası vermekte.

Bunu indirelim ve projemizin içerisinde android/app/ klasörü altına atalım.

Bu aşamanın ardından yapmamız gereken şey Android için gerekli olan ayarları yapmak olacak. Bu ayarları gradle dosyalarını düzenleyerek yapacağız. İlk olarak Android Manifest dosyasını düzenleyeceğiz. Bu dosya daha öncesinde belirttiğim gibi android/app/src/main/AndroidManifest.xml yolunda bulunmakta.

Flutter Android Embedding V1 için, arka plan hizmetinin, arka plan izolatıyla eklentileri kaydetmek için bir geri arama sağlanması gerekir. Bu, uygulamanızın onCreate yöntemini çağırmak için FlutterFirebaseMessagingBackgroundService’e bir geri arama verilerek yapılır. Bu geri arama işlemini bir java classı ile yapacağız. Başta bu class’ı manifeste ekleyelim:

2021-04-23-dart2_AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.fcm_push_notification">
   <application
        android:label="fcm_push_notification"
	android:name=".Application"
        android:icon="@mipmap/ic_launcher">
        <activity
        .......

Kaynak kod (Gist)

Şimdi de projemizin android/app/src/main/java/com/example/fcm_push_notification yoluna Application.java adında bir class oluşturup şu içeriği yazalım

Application.java

package com.example.fcm_push_notification;

import io.flutter.app.FlutterApplication;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback;
import io.flutter.plugins.GeneratedPluginRegistrant;
import io.flutter.plugins.firebase.messaging.FlutterFirebaseMessagingBackgroundService;
import io.flutter.plugins.firebase.messaging.FlutterFirebaseMessagingPlugin;

public class PuttyApplication extends FlutterApplication implements PluginRegistrantCallback {
    @Override
    public void onCreate() {
        super.onCreate();
        FlutterFirebaseMessagingBackgroundService.setPluginRegistrant(this);
    }

    @Override
    public void registerWith(PluginRegistry registry) {
        FlutterFirebaseMessagingPlugin.registerWith(registry.registrarFor("io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin"));
    }
}

Kaynak kod (Gist)

Artık kurulumun diğer işlemlerine devam edebiliriz. Firebase kurulum sayfasına dönelim ve buna da devam et diyelim.

Karşımıza çıkan sayfada bizim bazı gradle dosyalarını değiştirmemiz gerektiğine dair bir bilgi verilmiş. Bu bilgiler ile kendi kişisel çıkarımlarım sonucunda şunlar gerekmekte diye söyleyebilirim.

android/app/build.gradle dosyası içerisine:

  • android/defaultConfig tagı altında yer alan minSdkVersion değeri en az 21 olmalıdır. Bu da android 5.0 sonrası ile uyumlu bir proje oluşturmamız demektir. Bunun sebebi firebase ile android 5.0 öncesi gerek emulator gerekse telefonlarda sıkıntı yaşamış olmam. Size de bunu öneririm.
  • Ayrıca en sonda yer alan dependencies tagı altına şunları eklememiz gerekmektedir.
implementation platform('com.google.firebase:firebase-bom:27.0.0')
implementation 'com.google.firebase:firebase-analytics'
implementation 'com.google.firebase:firebase-messaging'

bu adımla beraber işlemlerimizi tamamlamış oluyoruz ve ardından Continue to console diyerek uygulama konsoluna geçelim

IOS İçin

İlk çıkan ekranda yer alan iOS bundle ID için Xcode ortamında General tabında yer alan Bundle Identifier değerini kullanalım.Diğer boşlukları da uygun şekilde dolduralım.

Register app diyince karşımıza bir config dosyası çıkmakta. Bunu da alarak uygulamamızda ios/Runner yoluna koyalım.

Google servisleri IOS için CocoaPods kullanmaktadır. Sonraki aşama için XCode üzerinde komut satırı açarak şu komutu girelim.

$ pod init

Ardından oluşan Podfile dosyasını açarak şu satırı ekleyelim.

pod 'Firebase/Analytics'

Ve ardından cocoapod’un bağımlılık kurulum işlemini yapalım.

$ pod install

Bu, aşamadan sonra uygulama içerisinde bir .xcworkspace dosyası oluşur. Bu dosyayı, uygulamanızda gelecekteki tüm geliştirmeler için kullanacağız.

Uygulamamızın ios/Runner/AppDelegate.swift yolundaki dosyayı açalım ve Firebase modülünü de import edip, ana fonksiyon içerisine şunu yazalım

FirebaseApp.configure()

işlemini de ekleyelim. Sonuçta oluşacak dosya şu şekilde görünecektir.

AppDelegate.swift

import UIKit
import Flutter
import Firebase

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    FirebaseApp.configure()
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

Kaynak kod (Gist)

ve artık hazırız. Console’ye doğru hareket edebiliriz.

FCM Consolu

Uygulamayı Yazmaya Başlamadan Son Bir Ön Hazırlık

Başlangıçta uygun gereksinimleri hem Android hem de IOS için gereksinen uygulama erişimlerini alalım.

Android

Yine AndroidManifest.xml dosyasına şu satırı ekleyelim. Bunu manifest/application/activity altına ekleyelim.

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

Ve şu satırları da manifest altına ekleyelim:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.INTERNET"/>

Sonuçta oluşacak AndroidManifest.xml dosyası şuna benzeyecek:

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.fcm_push_notification">

   <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
   <uses-permission android:name="android.permission.INTERNET"/>

   <application
        android:label="fcm_push_notification"
        android:name=".Application"
        android:icon="@mipmap/ic_launcher">
        <activity
            android:name=".MainActivity"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">

            <meta-data
              android:name="io.flutter.embedding.android.NormalTheme"
              android:resource="@style/NormalTheme"
              />
            <meta-data
              android:name="io.flutter.embedding.android.SplashScreenDrawable"
              android:resource="@drawable/launch_background"
              />
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
            <intent-filter>
                <action android:name="FLUTTER_NOTIFICATION_CLICK" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>

        </activity>
        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />
    </application>
</manifest>

Kaynak kod (Gist)

IOS

FCM via APNs Integration | FlutterFire _This guide applies to both iOS & macOS Flutter apps, repeat each step for the platforms you require. E.g. if you…_firebase.flutter.dev

  • Firebase belgelerindeki bu kılavuzu izleyerek Apple’ın push bildirimlerini almak için ihtiyaç duyduğu sertifikaları oluşturun. “Temel Hazırlık Profili Oluştur” başlıklı bölümü atlayabilirsiniz.
  • Xcode’da, Proje Gezgini’nde Çalıştırıcı’yı seçin. Yetenekler Sekmesinde Push Bildirimleri ve Arka Plan Modlarını açın ve Arka Plan Modları altında Arka Plan getirme ve Uzaktan bildirimleri etkinleştirin.
  • Firebase belgelerinin “APNs sertifikanızı yükleyin” bölümündeki adımları izleyin.

Flutter ile Uygulamayı Yazmak

Bu aşamada başta bizim “firebase_messaging” kütüphanesini import etmemiz gerekmektedir.

main.dart

import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:firebase_core/firebase_core.dart';

Kaynak kod (Gist)

Ardından FCM için FlutterLocalNotificationsPlugin için bir atama yapalım. Bu atamanın ardından Firebase için bir başlatıcı fonksiyon ve arka planda çalışmayı denetleyecek bir işleyici yazalım.

main.dart

final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
    FlutterLocalNotificationsPlugin();


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

_initFirebase() async {
  try {
    await Firebase.initializeApp();
    FirebaseMessaging.onBackgroundMessage(
        _firebaseMessagingBackgroundHandler);
  } catch (e) {}
}

Kaynak kod (Gist)

Şimdi de local notification işleyicisi oluşturalım ve Firebase Messaging işleyicisi ile bağlayalım:

main.dart

const AndroidNotificationChannel channel = AndroidNotificationChannel(
  'high_importance_channel',
  'High Importance Notifications',
  'This channel is used for important notifications.',
  importance: Importance.high,
);

_initNotifications() async {
  try {
    await flutterLocalNotificationsPlugin
        .resolvePlatformSpecificImplementation<
            AndroidFlutterLocalNotificationsPlugin>()
        ?.createNotificationChannel(channel);

    await FirebaseMessaging.instance
        .setForegroundNotificationPresentationOptions(
      alert: true,
      badge: true,
      sound: true,
    );
  } catch (e) {}
}


Kaynak kod (Gist)

main fonksiyonumuza ise son bir dokunuş yapalım.

main.dart

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  // runApp(MyApp());
  _initFirebase().then((_) => runApp(MyApp()));
}

Kaynak kod (Gist)

Şimdi firebase’in uygulama çalıştırılana kadar çalışır hale geldiğinden emin olduktan sonra son bir işimiz kalıyor. Firebase ve Local Notifications’ı MyApp widgetimiz içerisinde başlatmak bunu da MyApp içerisinde oluşturacağımız bir init constructor fonksiyonu ile yapacağız.

main.dart

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

  FirebaseMessaging.instance
      .getInitialMessage()
      .then((RemoteMessage? message) {
    if (message != null) {
      print("Taken message From ${message}");
    }
  });

  FirebaseMessaging.onMessage.listen((RemoteMessage message) {
    RemoteNotification notification = message.notification!;
    AndroidNotification? android = message.notification?.android;
    if (notification != null && android != null) {
      flutterLocalNotificationsPlugin.show(
          notification.hashCode,
          notification.title,
          notification.body,
          NotificationDetails(
            android: AndroidNotificationDetails(
              channel.id,
              channel.name,
              channel.description,
              icon: 'launch_background',
            ),
          ));
    }
  });

  FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
    print('A new onMessageOpenedApp event was published!');
  });
}

Kaynak kod (Gist)

Bütünü ile main.dart ise şöyle olacaktır.

main.dart

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

/* FCM Initialization */

/// Initialize the [FlutterLocalNotificationsPlugin] package for heads up FCM.
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
    FlutterLocalNotificationsPlugin();

/* AMC Initialization */

/// [AndroidNotificationChannel] for heads up notifications
const AndroidNotificationChannel channel = AndroidNotificationChannel(
  'high_importance_channel', // id
  'High Importance Notifications', // title
  'This channel is used for important notifications.', // description
  importance: Importance.high,
);

/* Firebase Messaging Functions */

/// To verify things are working, check out the native platform logs.
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  await Firebase.initializeApp();
  print('Handling a background message ${message.messageId}');
}

/// Firebase Initialiazation

_initFirebase() async {
  try {
    await Firebase.initializeApp(); // Initializes Application
    FirebaseMessaging.onBackgroundMessage(
        _firebaseMessagingBackgroundHandler); //Initializes Messaging Platform
  } catch (e) {}
}

_initNotifications() async {
  try {
    await flutterLocalNotificationsPlugin
        .resolvePlatformSpecificImplementation<
            AndroidFlutterLocalNotificationsPlugin>()
        ?.createNotificationChannel(channel);

    /// Update the iOS foreground notification presentation options to allow
    /// heads up notifications.
    await FirebaseMessaging.instance
        .setForegroundNotificationPresentationOptions(
      alert: true,
      badge: true,
      sound: true,
    );
  } catch (e) {}
}

/* Runner Function */
bool USE_FIRESTORE_EMULATOR = false;
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  // runApp(MyApp());
  _initFirebase().then((_) => runApp(MyApp()));
}

/**   Main Function   **/

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();

    FirebaseMessaging.instance
        .getInitialMessage()
        .then((RemoteMessage? message) {
      if (message != null) {
        print("Taken message From ${message}");
      }
    });

    FirebaseMessaging.onMessage.listen((RemoteMessage message) {
      RemoteNotification notification = message.notification!;
      AndroidNotification? android = message.notification?.android;
      if (notification != null && android != null) {
        flutterLocalNotificationsPlugin.show(
            notification.hashCode,
            notification.title,
            notification.body,
            NotificationDetails(
              android: AndroidNotificationDetails(
                channel.id,
                channel.name,
                channel.description,
                icon: 'launch_background',
              ),
            ));
      }
    });

    FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
      print('A new onMessageOpenedApp event was published!');
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: "FCM Try",
        debugShowCheckedModeBanner: false,
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: Scaffold(
          appBar: AppBar(
            title: Text("FCM Try"),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  'FCM Notifications Example',
                ),
              ],
            ),
          ),
        ));
  }
}

Kaynak kod (Gist)

Firebase’den Mesaj Göndermek ve Uygulamayı Test Etmek

Uygulamamızı yazdığımıza göre artık an uygulamamızı test etme anı.

Şimdi yine Firebase Konsolumuzu açalım. Ve yeni bir mesaj oluşturmayı seçelim.

Şimdi bildirim için bir başlık ve içerik verelim

Bir sonraki adımda bunu göndereceğimiz uygulamayı seçelim.

Bir sonraki adımda bize bu mesajı göndereceğimiz tarihi belirlememize imkan sağlıyor. Biz anlık olarak almak istediğimiz için olduğu gibi bırakalım

Sonraki adım analytics ile alakalı. Eğer ki bir uygulamanın ilk defa açıldığı an veya uygulama içi satın alma bildirimi oluşturmak istiyorsanız burada Select goal metric ile bunu tanımlamanız gerekmektedir. Ki şu an bana gerekmediği için öylece geçiyorum bunu.

Şimdi ise ek bazı şeyler soruyor bize. Burayı da bana gerekmediği için ellemiyor ve Review’a tıklıyorum.

Karşıma çıkan pencerede son bir kontrol açıyor. Buna da evet diyorum.

Ve artık uygulamamız ilk mesajını alması için bu mesajı göndermiş olduk. Bizi attığı sayfada görünen gibi bir satır çıkacak. Servis yoğunluğuna bağlı olarak birkaç saniye ile birkaç dakika arasında bir sürenin ardından telefonumuz ilk bildirimini almış olacaktır.

Sonuç

Firebase ve servisleri mobil geliştirme yapan pek çok kişi için bulunmaz bir nimet değerinde.

Bu örnek uygulamada da biz de Firebase kullanarak bir uygulamaya geliştirdik ve Firebase Cloud Messaging servisini nasıl kullanabileceğinizi görmüş oldunuz. Siz de bu gibi uzaktan mesaj alabilmenizi sağlayan uygulamalar yapabilirsiniz.

Daha fazlası için bakınız:

[**FlutterFire FlutterFire**:_The official Firebase plugins for Flutter The FlutterFire AdMob package is deprecated and will be removed in the…_firebase.flutter.dev](https://firebase.flutter.dev/)

Kaynak kod:

Zaryob/FlutterGarbage: A new Flutter project. This project is a starting point for a Flutter application. A few resources to get you started…_github.com

Kaynakça: