Catch up on everything announced at Firebase Summit, and learn how Firebase can help you accelerate app development and run your app with confidence. Learn More

تلقي الرسائل في تطبيق Flutter

تنظيم صفحاتك في مجموعات يمكنك حفظ المحتوى وتصنيفه حسب إعداداتك المفضّلة.

اعتمادًا على حالة الجهاز ، يتم التعامل مع الرسائل الواردة بشكل مختلف. لفهم هذه السيناريوهات وكيفية دمج FCM في التطبيق الخاص بك ، من المهم أولاً تحديد الحالات المختلفة التي يمكن أن يكون فيها الجهاز:

حالة وصف
المقدمة عندما يكون التطبيق مفتوحًا ، يكون قيد العرض وقيد الاستخدام.
خلفية عندما يكون التطبيق مفتوحًا ، ولكن في الخلفية (مصغر). يحدث هذا عادةً عندما يضغط المستخدم على زر "الصفحة الرئيسية" على الجهاز ، أو ينتقل إلى تطبيق آخر باستخدام مبدل التطبيق ، أو عندما يكون التطبيق مفتوحًا في علامة تبويب مختلفة (ويب).
تم إنهاؤه عند قفل الجهاز أو عدم تشغيل التطبيق.

هناك بعض الشروط المسبقة التي يجب الوفاء بها قبل أن يتمكن التطبيق من تلقي حمولات الرسائل عبر FCM:

  • يجب فتح التطبيق مرة واحدة على الأقل (للسماح بالتسجيل في FCM).
  • على نظام iOS ، إذا قام المستخدم بتمرير التطبيق بعيدًا عن مبدل التطبيق ، فيجب إعادة فتحه يدويًا حتى تبدأ رسائل الخلفية في العمل مرة أخرى.
  • على نظام Android ، إذا قام المستخدم بإنهاء التطبيق من إعدادات الجهاز ، فيجب إعادة فتحه يدويًا لبدء الرسائل في العمل.
  • على الويب ، يجب أن تكون قد طلبت رمزًا مميزًا (باستخدام getToken() ) مع شهادة دفع الويب الخاصة بك.

طلب إذن لتلقي الرسائل (Apple و Web)

على أنظمة iOS و macOS والويب ، قبل تلقي حمولات FCM على جهازك ، يجب عليك أولاً طلب إذن المستخدم.

توفر حزمة firebase_messaging واجهة برمجة تطبيقات بسيطة لطلب الإذن عبر طريقة requestPermission . تقبل واجهة برمجة التطبيقات هذه عددًا من الوسائط المسماة التي تحدد نوع الأذونات التي ترغب في طلبها ، مثل ما إذا كانت الرسائل التي تحتوي على حمولات الإشعارات يمكنها تشغيل صوت أو قراءة الرسائل عبر Siri. بشكل افتراضي ، تطلب الطريقة أذونات افتراضية معقولة. يوفر المرجع API وثائق كاملة حول الغرض من كل إذن.

للبدء ، اتصل بالطريقة من التطبيق الخاص بك (في نظام iOS ، سيتم عرض نموذج أصلي ، وسيتم تشغيل تدفق واجهة برمجة التطبيقات الأصلية للمتصفح على الويب):

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 وسياقه.

رسائل المقدمة والإخطار

لن تعرض رسائل التنبيه التي تصل أثناء وجود التطبيق في المقدمة إشعارًا مرئيًا بشكل افتراضي ، على كل من Android و iOS. ومع ذلك ، من الممكن تجاوز هذا السلوك:

  • على Android ، يجب عليك إنشاء قناة إعلام "ذات أولوية عالية".
  • على نظام iOS ، يمكنك تحديث خيارات العرض التقديمي للتطبيق.

رسائل الخلفية

تختلف عملية التعامل مع رسائل الخلفية في الأنظمة الأساسية (Android و Apple) والمنصات القائمة على الويب.

منصات آبل وأندرويد

تعامل مع رسائل الخلفية بتسجيل معالج onBackgroundMessage . عند تلقي الرسائل ، يتم إنشاء عزل (Android فقط ، لا يتطلب iOS / macOS عزلًا منفصلاً) مما يسمح لك بمعالجة الرسائل حتى عندما لا يكون التطبيق الخاص بك قيد التشغيل.

هناك بعض الأشياء التي يجب وضعها في الاعتبار حول معالج الرسائل في الخلفية:

  1. يجب ألا تكون وظيفة مجهولة.
  2. يجب أن تكون وظيفة من المستوى الأعلى (على سبيل المثال ليست طريقة فئة تتطلب التهيئة).
  3. يجب وضع تعليقات توضيحية عليها باستخدام @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());
}

نظرًا لأن المعالج يعمل بمعزل خاص به خارج سياق التطبيقات الخاصة بك ، فلا يمكن تحديث حالة التطبيق أو تنفيذ أي منطق يؤثر على واجهة المستخدم. ومع ذلك ، يمكنك تنفيذ منطق مثل طلبات HTTP ، وتنفيذ عمليات الإدخال والإخراج (مثل تحديث التخزين المحلي) ، والتواصل مع المكونات الإضافية الأخرى وما إلى ذلك.

يوصى أيضًا بإكمال منطقك في أسرع وقت ممكن. يؤثر تشغيل المهام الطويلة والمكثفة على أداء الجهاز وقد يتسبب في إنهاء نظام التشغيل للعملية. إذا تم تشغيل المهام لمدة تزيد عن 30 ثانية ، فقد يقتل الجهاز العملية تلقائيًا.

الويب

على الويب ، اكتب عامل خدمة JavaScript يعمل في الخلفية. استخدم عامل الخدمة للتعامل مع رسائل الخلفية.

للبدء ، قم بإنشاء ملف جديد في دليل web الخاص بك ، firebase-messaging-sw.js :

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

يجب أن يستورد الملف كلاً من تطبيقات SDK الخاصة بالتطبيق والرسائل ، وتهيئة Firebase وكشف متغير messaging .

بعد ذلك ، يجب تسجيل العامل. ضمن ملف الإدخال ، بعد تحميل ملف main.dart.js ، قم بتسجيل العامل الخاص بك:

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

بعد ذلك ، أعد تشغيل تطبيق Flutter. سيتم تسجيل العامل وسيتم التعامل مع أي رسائل خلفية عبر هذا الملف.

التعامل مع التفاعل

نظرًا لأن الإخطارات هي إشارة مرئية ، فمن الشائع أن يتفاعل معها المستخدمون (بالضغط). السلوك الافتراضي على كل من Android و iOS هو فتح التطبيق. إذا تم إنهاء التطبيق ، فسيتم بدء تشغيله ؛ إذا كان في الخلفية ، فسيتم عرضه في المقدمة.

بناءً على محتوى الإشعار ، قد ترغب في التعامل مع تفاعل المستخدم عند فتح التطبيق. على سبيل المثال ، إذا تم إرسال رسالة دردشة جديدة عبر إشعار وضغط المستخدم عليها ، فقد ترغب في فتح محادثة محددة عند فتح التطبيق.

توفر حزمة firebase-messaging طريقتين للتعامل مع هذا التفاعل:

  • getInitialMessage() : إذا تم فتح التطبيق من حالة منتهية ، فسيتم إرجاع Future الذي يحتوي على RemoteMessage . بمجرد استهلاكها ، ستتم إزالة RemoteMessage .
  • onMessageOpenedApp : Stream RemoteMessage عند فتح التطبيق من حالة الخلفية.

يوصى بمعالجة كلا السيناريوهين لضمان تجربة مستخدم سلسة للمستخدمين. يوضح مثال الكود أدناه كيف يمكن تحقيق ذلك:

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

تعتمد كيفية التعامل مع التفاعل على إعداد التطبيق الخاص بك. يوضح المثال أعلاه توضيحًا أساسيًا باستخدام 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 للرسالة التي تريد عرضها.

    ستبدو حمولة الرسالة على النحو التالي:

    {
      "data": {
        "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";
    

    ستبدو حمولة الرسالة على النحو التالي:

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

تفعيل تصدير بيانات تسليم الرسائل

يمكنك تصدير بيانات رسالتك إلى BigQuery لمزيد من التحليل. يتيح لك BigQuery تحليل البيانات باستخدام BigQuery SQL ، أو تصديرها إلى موفر خدمة سحابي آخر ، أو استخدام البيانات لنماذج ML المخصصة. يتضمن التصدير إلى BigQuery جميع البيانات المتاحة للرسائل ، بغض النظر عن نوع الرسالة أو ما إذا كانت الرسالة مرسلة عبر واجهة برمجة التطبيقات أو منشئ الإشعارات.

لتمكين التصدير ، اتبع أولاً الخطوات الموضحة هنا ، ثم اتبع الإرشادات التالية:

ذكري المظهر

يمكنك استخدام الكود التالي: dart 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

الويب

بالنسبة للويب ، تحتاج إلى تغيير عامل الخدمة الخاص بك لاستخدام الإصدار 9 من SDK. يجب أن يتم تجميع الإصدار v9 ، لذلك تحتاج إلى استخدام حزمة مثل esbuild على سبيل المثال لتشغيل عامل الخدمة. انظر إلى مثال التطبيق لمعرفة كيفية تحقيق ذلك.

بمجرد الانتقال إلى الإصدار 9 SDK ، يمكنك استخدام الكود التالي:

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

...

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

لا تنس تشغيل yarn build لتصدير الإصدار الجديد من عامل الخدمة إلى مجلد web .