Flutter uygulamasında mesaj alın

Cihazın durumuna bağlı olarak, gelen iletiler farklı şekilde işlenir. Bu senaryoları ve FCM'yi kendi uygulamanıza nasıl entegre edeceğinizi anlamak için öncelikle bir cihazın bulunabileceği çeşitli durumları belirlemeniz önemlidir:

Eyalet Açıklama
Ön plan Uygulama açık, görünür ve kullanımda olduğunda.
Genel bilgi Uygulama açık ancak arka planda (küçültülmüş) olduğunda. Bu durum genellikle kullanıcı cihazdaki "ana sayfa" düğmesine bastığında, uygulama değiştiriciyi kullanarak başka bir uygulamaya geçtiğinde veya uygulamayı farklı bir sekmede (web) açtığında meydana gelir.
Sonlandırıldı Cihaz kilitli veya uygulama çalışmıyorken.

Uygulamanın FCM aracılığıyla mesaj yüklerini alabilmesi için karşılanması gereken birkaç ön koşul vardır:

  • Başvuru, FCM'ye kayıt için en az bir kez açılmış olmalıdır.
  • iOS'te, kullanıcı uygulamayı uygulama değiştiriciden hızlıca kaydırırsa arka plan mesajlarının tekrar çalışmaya başlaması için uygulamanın manuel olarak yeniden açılması gerekir.
  • Android'de, kullanıcı cihaz ayarlarından uygulamadan zorla çıkarsa mesajların çalışmaya başlaması için uygulama manuel olarak yeniden açılmalıdır.
  • Web'de, web push sertifikanızla birlikte bir jeton (getToken() kullanarak) istemiş olmanız gerekir.

Mesaj almak için izin isteme

iOS, macOS, web ve Android 13'te (veya daha yeni sürümlerde) FCM yüklerinin cihazınızda alınabilmesi için önce kullanıcının iznini almanız gerekir.

firebase_messaging paketi, requestPermission yöntemiyle izin istemek için basit bir API sunar. Bu API, talep etmek istediğiniz izin türlerini tanımlayan çeşitli adlandırılmış bağımsız değişkenleri kabul eder (örneğin, bildirim yüklerini içeren mesajların Siri aracılığıyla bir ses tetiklemesi veya mesajları sesli okuması gibi). Varsayılan olarak bu yöntem, makul varsayılan izinler ister. Referans API, her iznin neyle ilgili olduğuyla ilgili tüm belgeleri sunar.

Başlamak için uygulamanızdaki yöntemi çağırın (iOS'te yerel bir kalıcı mod gösterilir, web'de tarayıcının yerel API akışı tetiklenir):

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

İstekten döndürülen NotificationSettings nesnesinin authorizationStatus özelliği, kullanıcının genel kararını belirlemek için kullanılabilir:

  • authorized: Kullanıcı izin verdi.
  • denied: Kullanıcı izni reddetti.
  • notDetermined: Kullanıcı, izin verip vermeyeceğini henüz seçmedi.
  • provisional: Kullanıcı geçici izin verdi

NotificationSettings alanındaki diğer mülkler, belirli bir iznin mevcut cihazda etkin, devre dışı veya desteklenmiyor olup olmadığını döndürür.

İzin verildikten ve farklı cihaz durumu türleri anlaşıldıktan sonra uygulamanız artık gelen FCM yüklerini işlemeye başlayabilir.

Mesaj işleme

Uygulamanızın mevcut durumuna bağlı olarak, farklı mesaj türlerinden gelen yüklerinin işlenmesi için farklı uygulamalar gerekir:

Ön plan mesajları

Uygulamanız ön plandayken mesajları işlemek için onMessage akışını dinleyin.

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

Akış; yük hakkında nerede olduğu, benzersiz kimlik, gönderilme zamanı, bildirim içerip içermediği gibi yük hakkında çeşitli bilgileri ayrıntılı olarak gösteren bir RemoteMessage içerir. Mesaj, uygulamanız ön plandayken alındığı için Flutter uygulamanızın durum ve bağlamına doğrudan erişebilirsiniz.

Ön plan ve Bildirim mesajları

Uygulama ön plandayken gelen bildirim mesajları, hem Android'de hem de iOS'te varsayılan olarak görünür bir bildirim görüntülemez. Ancak, bu davranışı geçersiz kılmak mümkündür:

  • Android'de "Yüksek Öncelikli" bildirim kanalı oluşturmalısınız.
  • iOS'te, uygulamanın sunu seçeneklerini güncelleyebilirsiniz.

Arka plan mesajları

Arka plan mesajlarının işlenme süreci yerel platformlarda (Android ve Apple) ve web tabanlı platformlarda farklıdır.

Apple platformları ve Android

Bir onBackgroundMessage işleyicisi kaydederek arka plan mesajlarını işleyin. Mesajlar alındığında, bir yalıtım oluşturulur (yalnızca Android, iOS/macOS ayrı bir yalıtım gerektirmez). Bu sayede, uygulamanız çalışmıyorken bile mesajları ele alabilirsiniz.

Arka plan mesajı işleyicinizle ilgili olarak aklınızda bulundurmanız gereken birkaç şey vardır:

  1. Anonim bir işlev olmamalıdır.
  2. Üst düzey bir işlev olmalıdır (ör. başlatma gerektiren bir sınıf yöntemi olmamalıdır).
  3. Flutter 3.3.0 veya sonraki bir sürümünü kullanırken, mesaj işleyicide işlev bildiriminin hemen üzerinde @pragma('vm:entry-point') ek açıklaması yer almalıdır (aksi takdirde serbest bırakma modu için ağaç sallama sırasında kaldırılabilir).
@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());
}

İşleyici, uygulama bağlamı dışında kendi izolasyonunda çalıştığından uygulama durumunu güncellemek veya kullanıcı arayüzünü etkileyen mantığı yürütmek mümkün değildir. Bununla birlikte, HTTP istekleri gibi mantıksal işlemleri gerçekleştirebilir, G/Ç işlemleri (ör. yerel depolama alanını güncelleme) gerçekleştirebilir, diğer eklentilerle iletişim kurabilirsiniz.

Ayrıca mantığınızı en kısa sürede tamamlamanız önerilir. Uzun ve yoğun görevlerin çalıştırılması cihaz performansını etkiler ve işletim sisteminin işlemi sonlandırmasına neden olabilir. Görevler 30 saniyeden daha uzun sürerse cihaz işlemi otomatik olarak sonlandırabilir.

Web

Web'de, arka planda çalışan bir JavaScript Hizmet Çalışanı yazın. Arka plandaki mesajları işlemek için Service Worker'ı kullanın.

Başlamak için web dizininizde yeni bir dosya oluşturun ve bu dosyayı firebase-messaging-sw.js olarak adlandırın:

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

Dosya hem uygulama hem de mesajlaşma SDK'larını içe aktarmalı, Firebase'i başlatmalı ve messaging değişkenini göstermelidir.

Ardından, çalışanın kaydedilmesi gerekir. main.dart.js dosyası yüklendikten sonra giriş dosyasında çalışanınızı kaydedin:

<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>

Ardından Flutter uygulamanızı yeniden başlatın. Çalışan kaydedilecek ve arka plan mesajları bu dosya üzerinden işlenecek.

Etkileşimi Yönetme

Bildirimler görünür bir işaret olduğundan, kullanıcıların onlarla etkileşim kurması (basarak) yaygındır. Hem Android'de hem de iOS'te varsayılan davranış, uygulamayı açmaktır. Uygulama sonlandırılırsa başlatılır, arka plandaysa ön plana getirilir.

Bir bildirimin içeriğine bağlı olarak, kullanıcının uygulama açıldığında etkileşimini yönetmek isteyebilirsiniz. Örneğin, bildirim aracılığıyla yeni bir sohbet mesajı gönderilirse ve kullanıcı bu mesaja basarsa uygulama açıldığında ilgili ileti dizisini açmak isteyebilirsiniz.

firebase-messaging paketi, bu etkileşimi yönetmek için iki yol sunar:

  • getInitialMessage(): Uygulama sonlandırılmış bir durumda açılırsa RemoteMessage içeren bir Future döndürülür. Kullanıldıktan sonra RemoteMessage kaldırılır.
  • onMessageOpenedApp: Uygulama arka plan durumundan açıldığında RemoteMessage mesajı yayınlayan bir Stream.

Kullanıcılarınıza sorunsuz bir kullanıcı deneyimi sunmak için her iki senaryonun da ele alınması önerilir. Aşağıdaki kod örneğinde bunun nasıl elde edilebileceği özetlenmiştir:

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("...");
  }
}

Etkileşimi nasıl ele alacağınız, uygulama kurulumunuza bağlıdır. Yukarıdaki örnekte, StatefulWidget kullanan temel bir açıklama gösterilmektedir.

İletileri Yerelleştirme

Yerelleştirilmiş dizeleri iki farklı şekilde gönderebilirsiniz:

  • Sunucunuzda her kullanıcı için tercih edilen dili depolayın ve her dil için özelleştirilmiş bildirimler gönderin
  • Yerelleştirilmiş dizeleri uygulamanıza yerleştirin ve işletim sisteminin yerel yerel ayarlarından yararlanın

İkinci yöntemin nasıl kullanılacağı aşağıda açıklanmıştır:

Android

  1. resources/values/strings.xml dilinde varsayılan dildeki mesajlarınızı belirtin:

    <string name="notification_title">Hello world</string>
    <string name="notification_message">This is a message</string>
    
  2. values-language dizininde çevrilmiş iletileri belirtin. Örneğin, resources/values-fr/strings.xml dilinde Fransızca mesajları belirtin:

    <string name="notification_title">Bonjour le monde</string>
    <string name="notification_message">C'est un message</string>
    
  3. Sunucu yükünde, yerelleştirilmiş mesajınız için title, message ve body anahtarlarını kullanmak yerine title_loc_key ve body_loc_key değerlerini kullanın ve bunları, görüntülemek istediğiniz mesajın name özelliğine ayarlayın.

    Mesaj yükü aşağıdaki gibi görünür:

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

iOS

  1. Base.lproj/Localizable.strings dilinde varsayılan dildeki mesajlarınızı belirtin:

    "NOTIFICATION_TITLE" = "Hello World";
    "NOTIFICATION_MESSAGE" = "This is a message";
    
  2. language.lproj dizininde çevrilmiş iletileri belirtin. Örneğin, fr.lproj/Localizable.strings dilinde Fransızca mesajları belirtin:

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

    Mesaj yükü aşağıdaki gibi görünür:

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

Mesaj teslimi verilerini dışa aktarmayı etkinleştir

Mesaj verilerinizi daha ayrıntılı analiz için BigQuery'ye aktarabilirsiniz. BigQuery, verileri BigQuery SQL kullanarak analiz etmenize, başka bir bulut sağlayıcıya aktarmanıza veya özel ML modellerinizde kullanmak istediğiniz verileri kullanmanıza olanak tanır. BigQuery'ye aktarma işlemi, mesaj türüne veya mesajın API ya da Notifications oluşturucu aracılığıyla gönderilmesine bakılmaksızın, mesajlar için mevcut tüm verileri içerir.

Dışa aktarmayı etkinleştirmek için önce burada açıklanan adımları uygulayın, ardından şu talimatları uygulayın:

Android

Şu kodu kullanabilirsiniz:

await FirebaseMessaging.instance.setDeliveryMetricsExportToBigQuery(true);

iOS

iOS için AppDelegate.m bölümünü aşağıdaki içerikle değiştirmeniz gerekir.

#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

Web

Web söz konusu olduğunda, SDK'nın v9 sürümünü kullanmak için hizmet çalışanınızı değiştirmeniz gerekir. v9 sürümünün paket haline getirilmesi gerekir. Bu nedenle, hizmet çalışanının çalışmasını sağlamak için esbuild gibi bir paketleyici kullanmanız gerekir. Bunun nasıl yapılacağını öğrenmek için örnek uygulamaya bakın.

v9 SDK'sına geçiş yaptıktan sonra aşağıdaki kodu kullanabilirsiniz:

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

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

Service Worker'ınızın yeni sürümünü web klasörüne aktarmak için yarn build komutunu çalıştırmayı unutmayın.

iOS'teki bildirimlerde resimleri göster

Apple cihazlarda, gelen FCM Bildirimleri'nin FCM yükündeki resimleri göstermesi için ek bir bildirim hizmeti uzantısı eklemeniz ve uygulamanızı bunu kullanacak şekilde yapılandırmanız gerekir.

Firebase telefonla kimlik doğrulamayı kullanıyorsanız Firebase Auth kapsülünü Podfile'ınıza eklemeniz gerekir.

1. Adım - Bildirim hizmet uzantısı ekleyin

  1. Xcode'da File > New > Target... (Dosya > Yeni > Hedef...) seçeneğini tıklayın.
  2. Kalıcı bir seçenek, olası hedeflerin listesini sunar. Sayfayı aşağı kaydırın veya filtreyi kullanarak Bildirim Hizmeti Uzantısı'nı seçin. Sonraki'yi tıklayın.
  3. Bir ürün adı ekleyin (bu eğiticiyle devam etmek için "ImageDescription" kullanın), dili Objective-C olarak ayarlayın ve Finish'i (Son) tıklayın.
  4. Etkinleştir'i tıklayarak şemayı etkinleştirin.

2. Adım - Podfile'a hedef ekleyin

Yeni uzantınızı Podfile'a ekleyerek Firebase/Messaging kapsülüne erişimi olduğundan emin olun:

  1. Navigator'da Podfile'ı açın: Pods > Podfile

  2. Dosyanın alt kısmına gidin ve aşağıdakileri ekleyin:

    target 'ImageNotification' do
      use_frameworks!
      pod 'Firebase/Auth' # Add this line if you are using FirebaseAuth phone authentication
      pod 'Firebase/Messaging'
    end
    
  3. ios veya macos dizininden pod install aracını kullanarak kapsüllerinizi yükleyin veya güncelleyin.

3. Adım - Uzantı yardımcısını kullanın

Bu noktada, her şey normal şekilde çalışıyor olmalıdır. Son adım, uzantı yardımcısını çağırmaktır.

  1. Gezinme panelinden ImageBildirim uzantınızı seçin.

  2. NotificationService.m dosyasını açın.

  3. Dosyanın üst kısmında, aşağıda gösterildiği gibi NotificationService.h öğesinin hemen ardından FirebaseMessaging.h dosyasını içe aktarın.

    NotificationService.m içeriğini şununla değiştir:

    #import "NotificationService.h"
    #import "FirebaseMessaging.h"
    #import "FirebaseAuth.h" // Add this line if you are using FirebaseAuth phone authentication
    #import <UIKit/UIKit.h> // Add this line if you are using FirebaseAuth phone authentication
    
    @interface NotificationService ()
    
    @property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
    @property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;
    
    @end
    
    @implementation NotificationService
    
    /* Uncomment this if you are using Firebase Auth
    - (BOOL)application:(UIApplication *)app
                openURL:(NSURL *)url
                options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
      if ([[FIRAuth auth] canHandleURL:url]) {
        return YES;
      }
      return NO;
    }
    
    - (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts {
      for (UIOpenURLContext *urlContext in URLContexts) {
        [FIRAuth.auth canHandleURL:urlContext.URL];
      }
    }
    */
    
    - (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
        self.contentHandler = contentHandler;
        self.bestAttemptContent = [request.content mutableCopy];
    
        // Modify the notification content here...
        [[FIRMessaging extensionHelper] populateNotificationContent:self.bestAttemptContent withContentHandler:contentHandler];
    }
    
    - (void)serviceExtensionTimeWillExpire {
        // Called just before the extension will be terminated by the system.
        // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
        self.contentHandler(self.bestAttemptContent);
    }
    
    @end
    

4. Adım - Resmi yüke ekleyin

Bildirim yükünüze artık bir resim ekleyebilirsiniz. Gönderme isteği oluşturma ile ilgili iOS dokümanlarına bakın. Cihazın maksimum 300 KB resim boyutunu zorunlu kıldığını unutmayın.