با استفاده از Firebase Cloud Messaging پیام ها را دریافت کنید

این راهنما نحوه راه‌اندازی Firebase Cloud Messaging در برنامه‌های موبایل و کلاینت وب خود توضیح می‌دهد تا بتوانید پیام‌ها را به‌طور مطمئن دریافت کنید.

پیام ها را در یک برنامه Flutter دریافت کنید

بسته به وضعیت دستگاه، پیام‌های دریافتی به گونه‌ای متفاوت مدیریت می‌شوند. برای درک این سناریوها و نحوه ادغام FCM در برنامه خود، ابتدا مهم است که وضعیت‌های مختلفی را که یک دستگاه می‌تواند در آن قرار گیرد مشخص کنید:

ایالت توضیحات
پیش زمینه وقتی برنامه باز است، در حال مشاهده و در حال استفاده است.
پس زمینه هنگامی که برنامه باز است، اما در پس زمینه (به حداقل می رسد). این معمولاً زمانی اتفاق می‌افتد که کاربر دکمه «خانه» را روی دستگاه فشار داده باشد، با استفاده از تعویض‌کننده برنامه به برنامه دیگری تغییر مکان داده باشد، یا برنامه در یک برگه دیگر (وب) باز شود.
خاتمه یافت وقتی دستگاه قفل است یا برنامه اجرا نمی شود.

چند پیش شرط وجود دارد که باید قبل از اینکه برنامه بتواند بارهای پیام را با استفاده از FCM دریافت کند، رعایت شود:

  • برنامه باید حداقل یک بار باز شده باشد (برای ثبت نام در FCM).
  • در iOS، اگر کاربر برنامه را از سوئیچر برنامه دور کند، باید به صورت دستی باز شود تا پیام‌های پس‌زمینه دوباره شروع به کار کنند.
  • در اندروید، اگر کاربر برنامه را به اجبار از تنظیمات دستگاه خارج کند، باید به صورت دستی باز شود تا پیام ها شروع به کار کنند.
  • در وب، باید یک توکن (با استفاده از getToken() ) همراه با گواهی فشار وب خود درخواست کرده باشید.

درخواست مجوز برای دریافت پیام

در iOS، macOS، وب و اندروید 13 (یا جدیدتر)، قبل از دریافت بارهای FCM در دستگاه شما، ابتدا باید از کاربر اجازه بگیرید.

بسته firebase_messaging یک API برای درخواست مجوز با استفاده از روش requestPermission فراهم می کند. این API تعدادی آرگومان نام‌گذاری شده را می‌پذیرد که نوع مجوزهایی را که می‌خواهید درخواست کنید، تعریف می‌کنند، مانند اینکه آیا پیام‌های حاوی بارهای اعلان می‌توانند صدا را تحریک کنند یا پیام‌هایی را با استفاده از Siri بخوانند. به طور پیش فرض، متد مجوزهای پیش فرض معقولی را درخواست می کند. API مرجع مستندات کاملی را در مورد اینکه هر مجوز برای چه چیزی است ارائه می دهد.

برای شروع، روش را از برنامه خود فراخوانی کنید (در iOS یک مدال داخلی نمایش داده می شود، در وب، جریان API مرورگر فعال می شود):

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

ویژگی authorizationStatus شی NotificationSettings که از درخواست بازگردانده شده است می تواند برای تعیین تصمیم کلی کاربر استفاده شود:

  • authorized : کاربر اجازه داده است.
  • denied : کاربر اجازه رد کرد.
  • notDetermined : کاربر هنوز انتخاب نکرده است که مجوز بدهد یا خیر.
  • provisional : کاربر مجوز موقت داده است

ویژگی‌های دیگر در NotificationSettings برمی‌گردند، چه مجوز خاصی در دستگاه فعلی فعال، غیرفعال یا پشتیبانی نشده باشد.

پس از اعطای مجوز و درک انواع مختلف وضعیت دستگاه، برنامه شما اکنون می‌تواند شروع به رسیدگی به محموله‌های ورودی FCM کند.

مدیریت پیام

بر اساس وضعیت فعلی برنامه شما، بارهای دریافتی از انواع پیام های مختلف به پیاده سازی های متفاوتی برای رسیدگی به آنها نیاز دارند:

پیام های پیش زمینه

برای مدیریت پیام ها در حالی که برنامه شما در پیش زمینه است، به جریان onMessage گوش دهید.

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

این جریان حاوی یک RemoteMessage است که اطلاعات مختلفی را در مورد محموله، از جمله اینکه از کجا بوده است، شناسه منحصربه‌فرد، زمان ارسال، حاوی اعلان و موارد دیگر است. از آنجایی که پیام در حالی که برنامه شما در پیش زمینه است بازیابی شده است، می توانید مستقیماً به وضعیت و زمینه برنامه Flutter خود دسترسی داشته باشید.

پیش زمینه و پیام های اعلان

پیام‌های اعلان‌هایی که در زمانی که برنامه در پیش‌زمینه است دریافت می‌شوند، به‌طور پیش‌فرض اعلان قابل مشاهده‌ای را در اندروید و iOS نشان نمی‌دهند. با این حال، می توان این رفتار را نادیده گرفت:

  • در اندروید، باید یک کانال اعلان با «اولویت بالا» ایجاد کنید.
  • در iOS، می توانید گزینه های ارائه برنامه را به روز کنید.

پیام های پس زمینه

فرآیند مدیریت پیام‌های پس‌زمینه در پلتفرم‌های اندروید، اپل و وب متفاوت است.

پلتفرم های اپل و اندروید

با ثبت یک کنترل کننده onBackgroundMessage ، پیام های پس زمینه را مدیریت کنید. هنگامی که پیام‌ها دریافت می‌شوند، یک ایزوله ایجاد می‌شود (فقط اندروید، iOS/macOS نیازی به جداسازی جداگانه ندارد) که به شما امکان می‌دهد پیام‌ها را حتی زمانی که برنامه شما اجرا نمی‌شود مدیریت کنید.

چند نکته را باید در مورد مدیریت پیام پس‌زمینه خود در نظر داشته باشید:

  1. نباید یک تابع ناشناس باشد.
  2. این باید یک تابع سطح بالا باشد (مثلاً یک روش کلاسی که نیاز به مقداردهی اولیه دارد).
  3. هنگام استفاده از Flutter نسخه 3.3.0 یا بالاتر، کنترل کننده پیام باید با @pragma('vm:entry-point') درست بالای اعلان تابع حاشیه نویسی شود (در غیر این صورت ممکن است هنگام تکان دادن درخت برای حالت انتشار حذف شود).
@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());
}

از آنجایی که کنترل کننده در ایزوله خود خارج از زمینه برنامه های کاربردی شما اجرا می شود، امکان به روز رسانی وضعیت برنامه یا اجرای منطق تأثیرگذار UI وجود ندارد. با این حال، می‌توانید منطقی مانند درخواست‌های HTTP، عملیات IO (مثلاً به‌روزرسانی فضای ذخیره‌سازی محلی)، برقراری ارتباط با سایر افزونه‌ها و غیره را انجام دهید.

همچنین توصیه می شود در اسرع وقت منطق خود را تکمیل کنید. انجام کارهای طولانی و فشرده بر عملکرد دستگاه تأثیر می گذارد و ممکن است باعث شود که سیستم عامل فرآیند را خاتمه دهد. اگر کارها بیش از 30 ثانیه اجرا شوند، دستگاه ممکن است به طور خودکار فرآیند را از بین ببرد.

وب

در وب، یک JavaScript Service Worker بنویسید که در پس‌زمینه اجرا می‌شود. از سرویس‌کار برای مدیریت پیام‌های پس‌زمینه استفاده کنید.

برای شروع، یک فایل جدید در فهرست web خود ایجاد کنید و آن را firebase-messaging-sw.js نامید:

// See this file for the latest firebase-js-sdk version:
// https://github.com/firebase/flutterfire/blob/main/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);
});

فایل باید هر دو SDK برنامه و پیام را وارد کند، Firebase را مقداردهی اولیه کند و متغیر messaging در معرض نمایش قرار دهد.

بعد، کارگر باید ثبت نام کند. در فایل index.html ، با تغییر تگ <script> که Flutter را بوت استرپ می کند، کارگر را ثبت کنید:

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

اگر هنوز از سیستم قالب قدیمی استفاده می کنید، می توانید با تغییر تگ <script> که Flutter را بوت استرپ می کند، کارگر را به صورت زیر ثبت کنید:

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

بعد برنامه Flutter خود را مجددا راه اندازی کنید. کارگر ثبت خواهد شد و هرگونه پیام پس زمینه با استفاده از این فایل مدیریت می شود.

مدیریت تعامل

از آنجایی که اعلان‌ها یک نشانه قابل مشاهده هستند، معمولاً کاربران با آنها تعامل دارند (با فشار دادن). رفتار پیش فرض در اندروید و iOS باز کردن برنامه است. اگر برنامه خاتمه یابد، شروع خواهد شد. اگر در پس‌زمینه باشد، در پیش‌زمینه قرار می‌گیرد.

بسته به محتوای یک اعلان، ممکن است بخواهید هنگام باز شدن برنامه، تعامل کاربر را کنترل کنید. به عنوان مثال، اگر یک پیام چت جدید با استفاده از اعلان ارسال شود و کاربر آن را فشار دهد، ممکن است بخواهید با باز شدن برنامه، مکالمه خاصی را باز کنید.

بسته firebase-messaging دو راه برای مدیریت این تعامل ارائه می‌دهد:

  • getInitialMessage() : اگر برنامه از حالت پایان یافته باز شود، Future حاوی RemoteMessage برگردانده می شود. پس از مصرف، RemoteMessage حذف خواهد شد.
  • onMessageOpenedApp : Stream که وقتی برنامه از حالت پس‌زمینه باز می‌شود، یک RemoteMessage ارسال می‌کند.

توصیه می شود که هر دو سناریو برای اطمینان از یک UX صاف برای کاربران خود بررسی شوند. مثال کد زیر چگونگی دستیابی به این امر را شرح می دهد:

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

نحوه مدیریت تعامل به تنظیمات برنامه شما بستگی دارد. مثال قبلی یک تصویر اساسی را با استفاده از StatefulWidget نشان می دهد.

بومی سازی پیام ها

شما می توانید رشته های محلی را به دو روش مختلف ارسال کنید:

  • زبان دلخواه هر یک از کاربران خود را در سرور خود ذخیره کنید و اعلان های سفارشی برای هر زبان ارسال کنید
  • رشته های محلی شده را در برنامه خود جاسازی کنید و از تنظیمات محلی داخلی سیستم عامل استفاده کنید

در اینجا نحوه استفاده از روش دوم آورده شده است:

اندروید

  1. پیام های زبان پیش فرض خود را در resources/values/strings.xml مشخص کنید:

    <string name="notification_title">Hello world</string>
    <string name="notification_message">This is a message</string>
    
  2. پیام های ترجمه شده را در فهرست راهنمای values- language مشخص کنید. به عنوان مثال، پیام های فرانسوی را در resources/values-fr/strings.xml مشخص کنید:

    <string name="notification_title">Bonjour le monde</string>
    <string name="notification_message">C'est un message</string>
    
  3. در بار سرور، به جای استفاده از کلیدهای title ، message و body ، از title_loc_key و body_loc_key برای پیام محلی خود استفاده کنید و آنها را روی ویژگی name پیامی که می خواهید نمایش دهید تنظیم کنید.

    محموله پیام به این صورت خواهد بود:

    {
      "android": {
         "notification": {
           "title_loc_key": "notification_title",
           "body_loc_key": "notification_message"
         }
      }
    }
    

iOS

  1. پیام های زبان پیش فرض خود را در Base.lproj/Localizable.strings مشخص کنید:

    "NOTIFICATION_TITLE" = "Hello World";
    "NOTIFICATION_MESSAGE" = "This is a message";
    
  2. پیام های ترجمه شده را در فهرست راهنمای language .lproj مشخص کنید. به عنوان مثال، پیام های فرانسوی را در fr.lproj/Localizable.strings مشخص کنید:

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

    محموله پیام به این صورت خواهد بود:

    {
      "apns": {
         "payload": {
           "alert": {
             "title-loc-key": "NOTIFICATION_TITLE",
             "loc-key": "NOTIFICATION_MESSAGE"
           }
         }
      }
    }
    

فعال کردن صادرات داده های تحویل پیام

می توانید داده های پیام خود را برای تجزیه و تحلیل بیشتر به BigQuery صادر کنید. BigQuery به شما امکان می‌دهد داده‌ها را با استفاده از BigQuery SQL تجزیه و تحلیل کنید، آن‌ها را به ارائه‌دهنده ابری دیگر صادر کنید یا از داده‌ها برای مدل‌های ML سفارشی خود استفاده کنید. صادرات به BigQuery شامل تمام داده‌های موجود برای پیام‌ها، صرف‌نظر از نوع پیام یا اینکه آیا پیام با استفاده از API یا سازنده Notifications ارسال می‌شود، می‌شود.

برای فعال کردن صادرات، ابتدا مراحل موجود در سند تحویل درک را دنبال کنید، سپس این دستورالعمل‌ها را دنبال کنید:

اندروید

می توانید از کد زیر استفاده کنید:

await FirebaseMessaging.instance.setDeliveryMetricsExportToBigQuery(true);

iOS

برای iOS، باید AppDelegate.m با محتوای زیر تغییر دهید.

#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

وب

برای وب، برای استفاده از نسخه v9 SDK باید سرویس کار خود را تغییر دهید. نسخه v9 باید باندل شود، بنابراین باید از باندلری مانند esbuild استفاده کنید تا سرویس‌کار را به کار بیاورید. برای مشاهده نحوه دستیابی به این برنامه به مثال برنامه مراجعه کنید.

هنگامی که به v9 SDK مهاجرت کردید، می توانید از کد زیر استفاده کنید:

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

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

فراموش نکنید که yarn build اجرا کنید تا نسخه جدید سرویس کارگر خود را به پوشه web صادر کنید.

نمایش تصاویر در اعلان ها در iOS

در دستگاه‌های اپل، برای اینکه اعلان‌های FCM ورودی تصاویر را از محموله FCM نمایش دهند، باید یک افزونه سرویس اعلان اضافی اضافه کنید و برنامه خود را برای استفاده از آن پیکربندی کنید.

اگر از احراز هویت تلفن Firebase استفاده می کنید، باید غلاف Firebase Auth را به Podfile خود اضافه کنید.

مرحله 1 - یک برنامه افزودنی سرویس اعلان اضافه کنید

  1. در Xcode، روی File > New > Target کلیک کنید...
  2. یک مدال فهرستی از اهداف احتمالی را ارائه می دهد. برای انتخاب گزینه Notification Service Extension به آن بروید یا از فیلتر استفاده کنید. روی Next کلیک کنید.
  3. نام محصول را اضافه کنید (از "ImageNotification" برای دنبال کردن این آموزش استفاده کنید)، Swift یا Objective-C انتخاب کنید و روی Finish کلیک کنید.
  4. با کلیک روی فعال کردن، طرح را فعال کنید.

مرحله 2 - هدف را به Podfile اضافه کنید

سویفت

با افزودن آن به هدف Runner ، اطمینان حاصل کنید که برنامه افزودنی جدید شما به بسته سریع FirebaseMessaging دسترسی دارد:

  1. از Navigator، SDK پلتفرم های Apple Firebase را اضافه کنید : File > Add Package Dependencies...

  2. URL بسته را جستجو یا وارد کنید: none https://github.com/firebase/firebase-ios-sdk

  3. افزودن به Project Runner : افزودن بسته

  4. FirebaseMessaging را انتخاب کنید و ImageNotification را به هدف اضافه کنید: بسته را اضافه کنید

هدف-C

با افزودن آن در Podfile، اطمینان حاصل کنید که برنامه افزودنی جدید شما به غلاف Firebase/Messaging دسترسی دارد:

  1. از Navigator، Podfile را باز کنید: Pods > Podfile

  2. به انتهای فایل رفته و اضافه کنید:

    target 'ImageNotification' do
      use_frameworks!
      pod 'Firebase/Auth' # Add this line if you are using FirebaseAuth phone authentication
      pod 'Firebase/Messaging'
    end
    
  3. پادهای خود را با استفاده از pod install از فهرست ios یا macos نصب یا به روز کنید.

مرحله 3 - از افزونه کمک کننده استفاده کنید

در این مرحله، همه چیز همچنان باید به طور عادی اجرا شود. مرحله آخر فراخوانی کمک کننده افزونه است.

سویفت

  1. از ناوبر، پسوند ImageNotification خود را انتخاب کنید

  2. فایل NotificationService.swift را باز کنید.

  3. محتوای NotificationService.swift را با:

    import UserNotifications
    import FirebaseMessaging
    
    class NotificationService: UNNotificationServiceExtension {
    
        var contentHandler: ((UNNotificationContent) -> Void)?
        var bestAttemptContent: UNMutableNotificationContent?
    
        override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
            self.contentHandler = contentHandler
            bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
    
            Messaging.serviceExtension().populateNotificationContent(bestAttemptContent!, withContentHandler: contentHandler)
        }
    
        override func serviceExtensionTimeWillExpire() {
            if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
                contentHandler(bestAttemptContent)
            }
        }
    }
    

هدف-C

  1. از ناوبر، پسوند ImageNotification خود را انتخاب کنید

  2. فایل NotificationService.m را باز کنید.

  3. در بالای فایل، FirebaseMessaging.h درست بعد از NotificationService.h وارد کنید.

    محتوای NotificationService.m را با موارد زیر جایگزین کنید:

    #import "NotificationService.h"
    #import "FirebaseMessaging.h"
    #import <FirebaseAuth/FirebaseAuth-Swift.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 () <NSURLSessionDelegate>
    
    @property(nonatomic) void (^contentHandler)(UNNotificationContent *contentToDeliver);
    @property(nonatomic) 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 - تصویر را به محموله اضافه کنید

در محموله اعلانات خود، اکنون می توانید یک تصویر اضافه کنید. به مستندات iOS در مورد نحوه ایجاد درخواست ارسال مراجعه کنید. به خاطر داشته باشید که حداکثر اندازه تصویر 300 کیلوبایت توسط دستگاه اعمال می شود.