Flutter uygulamasında mesaj alın

Cihazın durumuna bağlı olarak, gelen iletiler farklı şekilde işlenir. Alıcı: bu senaryoları ve FCM'yi kendi uygulamanıza nasıl entegre edeceğinizi anladığınızda öncelikle bir cihazın bulunabileceği çeşitli durumları belirlemek açısından önemlidir:

Eyalet Açıklama
Ön plan Uygulama açık, görünümde ve kullanımdayken.
Genel bilgi Uygulama açık ancak arka planda (küçültülmüş) olduğunda. Bu durum genellikle kullanıcı "ana sayfa" düğmesine bastığında gerçekleşir düğme Uygulama değiştiriciyi kullanarak başka bir uygulamaya geçmişse veya uygulamanın farklı bir sekmede (web) açılmasını sağlayabilir.
Sonlandırıldı Cihaz kilitli veya uygulama çalışmıyorken.

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

  • 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 (veya daha yeni sürümler) cihazlarda FCM yükü ilk olarak kullanıcıdan izin 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ürünü tanımlayan bir dizi adlandırılmış bağımsız değişkeni kabul eder. Örneğin, Bildirim yükü içeren mesajlar, Siri aracılığıyla bir sesi tetikleyebilir veya mesajları okuyabilir. Varsayılan olarak 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 web'de yerel bir kalıcı mod gösterilir) 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}');

NotificationSettings nesnesinin authorizationStatus özelliği istek, 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çmemiştir.
  • provisional: Kullanıcı geçici izin verdi
ziyaret edin.

NotificationSettings alanındaki diğer mülkler, belirli bir iznin geçerli olanak tanır.

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

Mesaj işleme

Uygulamanızın mevcut durumuna bağlı olarak, farklı uygulamalardan gelen mesaj türleri bunları ele almak 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ış, ayrıntılı bilgiler içeren bir RemoteMessage içeriyor nereden olduğu, benzersiz kimlik, gönderilen süre, bir bildirim ve daha fazlası. Mesaj, uygulamanız ön plandayken alındığı için Flutter hesabınıza doğrudan durumunu ve bağlamını göz önünde bulundurmalısınız.

Ön plan ve Bildirim mesajları

Uygulama ön plandayken gelen bildirim mesajları, varsayılan olarak her iki cihazda da görünür bir bildirim göstermez Android ve iOS. Ancak, bu davranışı geçersiz kılmak mümkündür:

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

Arka plan mesajları

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

Apple platformları ve Android

Bir onBackgroundMessage işleyici kaydederek arka plan mesajlarını işleyin. İletiler alındığında izole uygulaması ortaya çıktı (yalnızca Android, iOS/macOS ayrı bir yalıtım gerektirmez). Bu sayede, uygulamanız çalışmıyorken bile iletileri 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 güncelleme yapılamaz. veya mantığı etkileyen bir kullanıcı arayüzü yürütebilir. Bununla birlikte, HTTP istekleri gibi mantıksal işlemleri gerçekleştirebilir, IO işlemleri gerçekleştirebilirsiniz. (ör. yerel depolama alanını güncelleme), diğer eklentilerle iletişim kurma vb.

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:

// Please see this file for the latest firebase-js-sdk version:
// https://github.com/firebase/flutterfire/blob/master/packages/firebase_core/firebase_core_web/lib/src/firebase_sdk_version.dart
importScripts("https://www.gstatic.com/firebasejs/10.7.0/firebase-app-compat.js");
importScripts("https://www.gstatic.com/firebasejs/10.7.0/firebase-messaging-compat.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. index.html dosyasında, Flutter'ı önyükleyen <script> etiketini değiştirerek çalışanı kaydedin:

<script src="flutter_bootstrap.js" async>
  if ('serviceWorker' in navigator) {
    window.addEventListener('load', function () {
      navigator.serviceWorker.register('firebase-messaging-sw.js', {
        scope: '/firebase-cloud-messaging-push-scope',
      });
    });
  }
</script>

Hâlâ eski şablon oluşturma sistemini kullanıyorsanız Flutter'ı aşağıdaki şekilde önyükleyen <script> etiketini değiştirerek çalışanı kaydedebilirsiniz:

<html>
<body>
  <script>
      var serviceWorkerVersion = null;
      var scriptLoaded = false;
      function loadMainDartJs() {
        if (scriptLoaded) {
          return;
        }
        scriptLoaded = true;
        var scriptTag = document.createElement('script');
        scriptTag.src = 'main.dart.js';
        scriptTag.type = 'application/javascript';
        document.body.append(scriptTag);
      }

      if ('serviceWorker' in navigator) {
        // Service workers are supported. Use them.
        window.addEventListener('load', function () {
          // Register Firebase Messaging service worker.
          navigator.serviceWorker.register('firebase-messaging-sw.js', {
            scope: '/firebase-cloud-messaging-push-scope',
          });

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

          navigator.serviceWorker.register(serviceWorkerUrl).then((reg) => {
            function waitForActivation(serviceWorker) {
              serviceWorker.addEventListener('statechange', () => {
                if (serviceWorker.state == 'activated') {
                  console.log('Installed new service worker.');
                  loadMainDartJs();
                }
              });
            }
            if (!reg.active && (reg.installing || reg.waiting)) {
              // No active web worker and we have installed or are installing
              // one for the first time. Simply wait for it to activate.
              waitForActivation(reg.installing ?? reg.waiting);
            } else if (!reg.active.scriptURL.endsWith(serviceWorkerVersion)) {
              // When the app updates the serviceWorkerVersion changes, so we
              // need to ask the service worker to update.
              console.log('New service worker available.');
              reg.update();
              waitForActivation(reg.installing);
            } else {
              // Existing service worker is still good.
              console.log('Loading app from service worker.');
              loadMainDartJs();
            }
          });

          // If service worker doesn't succeed in a reasonable amount of time,
          // fallback to plaint <script> tag.
          setTimeout(() => {
            if (!scriptLoaded) {
              console.warn(
                'Failed to load app from service worker. Falling back to plain <script> tag.'
              );
              loadMainDartJs();
            }
          }, 4000);
        });
      } else {
        // Service workers not supported. Just drop the <script> tag.
        loadMainDartJs();
      }
  </script>
</body>

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ış bir uygulamadı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, bir bildirim görürseniz ve kullanıcı bu bildirime 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, BigQuery SQL'i kullanarak verileri analiz etmenize olanak tanır. başka bir bulut sağlayıcıya aktarabilir veya özel makine öğrenimi modellerinizin verilerini kullanabilirsiniz. BigQuery'ye aktarma mesaj türüne veya mesajın simgesini tıklayın.

Dışa aktarmayı etkinleştirmek için önce burada açıklanan adımları uygulayın. Ardından aşağıdaki 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 halinde sunulması gerekir. Bu nedenle, örneğin esbuild gibi bir paketleyici kullanmanız gerekir. ve hizmet çalışanının çalışmasını sağlar. 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 > Yeni > Hedef...
  2. Bir kalıcı iletişim kutusunda olası hedeflerin bir listesi sunulur. 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 uygulaması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.