این راهنما نحوه تنظیم Firebase Cloud Messaging را در برنامههای موبایل و کلاینت وب شما شرح میدهد تا بتوانید پیامها را به طور قابل اعتمادی دریافت کنید.
دریافت پیامها در یک برنامه Flutter
بسته به وضعیت دستگاه، پیامهای ورودی به طور متفاوتی مدیریت میشوند. برای درک این سناریوها و نحوه ادغام FCM در برنامه خود، ابتدا مهم است که وضعیتهای مختلفی را که یک دستگاه میتواند در آن باشد، مشخص کنید:
ایالت | توضیحات |
---|---|
پیشزمینه | وقتی برنامه باز، در معرض دید و در حال استفاده است. |
پیشینه | وقتی برنامه باز است، اما در پسزمینه (مینیمایز شده). این معمولاً زمانی اتفاق میافتد که کاربر دکمه «خانه» را روی دستگاه فشار داده باشد، با استفاده از تعویض برنامه به برنامه دیگری رفته باشد، یا برنامه در یک تب متفاوت (وب) باز باشد. |
فسخ شده | وقتی دستگاه قفل است یا برنامه در حال اجرا نیست. |
قبل از اینکه برنامه بتواند با استفاده از FCM، پیامهای ارسالی را دریافت کند، باید چند پیششرط رعایت شود:
- برنامه باید حداقل یک بار باز شده باشد (تا امکان ثبت نام در FCM فراهم شود).
- در iOS، اگر کاربر برنامه را از طریق app switcher به بیرون بکشد، برای اینکه پیامهای پسزمینه دوباره شروع به کار کنند، باید آن را به صورت دستی دوباره باز کند.
- در اندروید، اگر کاربر از طریق تنظیمات دستگاه، برنامه را به زور ببندد، برای اینکه پیامها شروع به کار کنند، باید برنامه را به صورت دستی دوباره باز کند.
- در وب، شما باید یک توکن (با استفاده از
getToken()
) را با گواهی web push خود درخواست کرده باشید.
درخواست مجوز برای دریافت پیامها
در iOS، macOS، وب و اندروید ۱۳ (یا جدیدتر)، قبل از اینکه بتوانید بارهای FCM را روی دستگاه خود دریافت کنید، ابتدا باید از کاربر اجازه بگیرید.
The firebase_messaging
package provides an API for requesting permission using the requestPermission
method. This API accepts a number of named arguments which define the type of permissions you'd like to request, such as whether messaging containing notification payloads can trigger a sound or read out messages using Siri. By default, the method requests sensible default permissions. The reference API provides full documentation on what each permission is for.
برای شروع، متد را از برنامه خود فراخوانی کنید (در 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
است که اطلاعات مختلفی در مورد payload، مانند مبدا، شناسه منحصر به فرد، زمان ارسال، اینکه آیا حاوی اعلان بوده است یا خیر و موارد دیگر را شرح میدهد. از آنجایی که پیام در حالی که برنامه شما در پیشزمینه است بازیابی شده است، میتوانید مستقیماً به وضعیت و زمینه برنامه Flutter خود دسترسی داشته باشید.
پیامهای پیشزمینه و اعلانها
پیامهای اعلانی که هنگام اجرای برنامه در پیشزمینه دریافت میشوند، بهطور پیشفرض، چه در اندروید و چه در iOS، اعلان قابل مشاهدهای را نمایش نمیدهند. با این حال، میتوان این رفتار را لغو کرد:
- در اندروید، باید یک کانال اعلان «اولویت بالا» ایجاد کنید.
- در iOS، میتوانید گزینههای ارائه برنامه را بهروزرسانی کنید.
پیامهای پسزمینه
فرآیند مدیریت پیامهای پسزمینه در اندروید، اپل و پلتفرمهای مبتنی بر وب متفاوت است.
پلتفرمهای اپل و اندروید
با ثبت یک کنترلکننده onBackgroundMessage
، پیامهای پسزمینه را مدیریت کنید. وقتی پیامها دریافت میشوند، یک ایزوله ایجاد میشود (فقط اندروید، iOS/macOS به ایزوله جداگانهای نیاز ندارد) که به شما امکان میدهد پیامها را حتی زمانی که برنامه شما در حال اجرا نیست، مدیریت کنید.
چند نکته وجود دارد که باید در مورد کنترلکننده پیام پسزمینه خود در نظر داشته باشید:
- نباید یک تابع ناشناس باشد.
- باید یک تابع سطح بالا باشد (مثلاً یک متد کلاس که نیاز به مقداردهی اولیه دارد نباشد).
- هنگام استفاده از فلاتر نسخه ۳.۳.۰ یا بالاتر، مدیریتکننده پیام باید با
@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، عملیات IO (مثلاً بهروزرسانی فضای ذخیرهسازی محلی)، ارتباط با سایر افزونهها و غیره را انجام دهید.
همچنین توصیه میشود منطق خود را در اسرع وقت تکمیل کنید. اجرای وظایف طولانی و فشرده بر عملکرد دستگاه تأثیر میگذارد و ممکن است باعث شود سیستم عامل فرآیند را خاتمه دهد. اگر وظایف بیش از 30 ثانیه اجرا شوند، دستگاه ممکن است به طور خودکار فرآیند را از بین ببرد.
وب
در وب، یک سرویس ورکر جاوااسکریپت بنویسید که در پسزمینه اجرا شود. از سرویس ورکر برای مدیریت پیامهای پسزمینه استفاده کنید.
برای شروع، یک فایل جدید در دایرکتوری 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
را نمایش دهد.
در مرحله بعد، worker باید ثبت شود. در فایل index.html
، worker را با تغییر تگ <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>
که فلاتر را بوتاسترپ میکند، به صورت زیر، worker را ثبت کنید:
<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 خود را مجدداً راه اندازی کنید. worker ثبت خواهد شد و هرگونه پیام پس زمینه با استفاده از این فایل مدیریت خواهد شد.
مدیریت تعامل
از آنجایی که اعلانها یک نشانه قابل مشاهده هستند، تعامل کاربران با آنها (با فشار دادن) امری رایج است. رفتار پیشفرض در اندروید و 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 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 را نشان میدهد.
پیامها را محلیسازی کنید
شما میتوانید رشتههای محلیشده را به دو روش مختلف ارسال کنید:
- زبان مورد نظر هر یک از کاربران خود را در سرور خود ذخیره کنید و اعلانهای سفارشیشده را برای هر زبان ارسال کنید.
- رشتههای محلیسازیشده را در برنامه خود جاسازی کنید و از تنظیمات محلی داخلی سیستم عامل استفاده کنید.
نحوه استفاده از روش دوم به شرح زیر است:
اندروید
زبان پیشفرض پیامهای خود را در
resources/values/strings.xml
مشخص کنید:<string name="notification_title">Hello world</string> <string name="notification_message">This is a message</string>
پیامهای ترجمهشده را در دایرکتوری
values- language
مشخص کنید. برای مثال، پیامهای فرانسوی را درresources/values-fr/strings.xml
مشخص کنید:<string name="notification_title">Bonjour le monde</string> <string name="notification_message">C'est un message</string>
در فایل اجرایی سرور، به جای استفاده از کلیدهای
title
،message
وbody
، ازtitle_loc_key
وbody_loc_key
برای پیام محلی خود استفاده کنید و آنها را برابر با ویژگیname
پیامی که میخواهید نمایش دهید، قرار دهید.محتوای پیام به این شکل خواهد بود:
{ "android": { "notification": { "title_loc_key": "notification_title", "body_loc_key": "notification_message" } } }
آیاواس
زبان پیشفرض پیامهای خود را در
Base.lproj/Localizable.strings
مشخص کنید:"NOTIFICATION_TITLE" = "Hello World"; "NOTIFICATION_MESSAGE" = "This is a message";
پیامهای ترجمهشده را در دایرکتوری
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، باید 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، باید service worker خود را تغییر دهید. نسخه v9 باید bundle شود، بنابراین برای راهاندازی service worker باید از یک bundler مانند esbuild
استفاده کنید. برای مشاهده نحوه دستیابی به این هدف، به برنامه نمونه مراجعه کنید.
پس از مهاجرت به SDK نسخه ۹، میتوانید از کد زیر استفاده کنید:
import {
experimentalSetDeliveryMetricsExportedToBigQueryEnabled,
getMessaging,
} from 'firebase/messaging/sw';
...
const messaging = getMessaging(app);
experimentalSetDeliveryMetricsExportedToBigQueryEnabled(messaging, true);
فراموش نکنید که برای خروجی گرفتن از نسخه جدید سرویس ورکر خود به پوشه web
، yarn build
اجرا کنید.
نمایش تصاویر در اعلانها در iOS
در دستگاههای اپل، برای اینکه اعلانهای FCM ورودی، تصاویر مربوط به FCM payload را نمایش دهند، باید یک افزونه سرویس اعلان اضافی اضافه کنید و برنامه خود را برای استفاده از آن پیکربندی کنید.
اگر از احراز هویت تلفنی Firebase استفاده میکنید، باید Pod Firebase Auth را به Podfile خود اضافه کنید.
مرحله ۱ - افزودن افزونه سرویس اعلان
- در Xcode، روی File > New > Target... کلیک کنید.
- یک پنجرهی مدال (modal) لیستی از اهداف ممکن را نمایش میدهد؛ به قسمت افزونهی سرویس اعلان (Notification Service Extension) بروید یا از فیلتر برای انتخاب آن استفاده کنید. روی «بعدی» (Next) کلیک کنید.
- یک نام برای محصول اضافه کنید (برای دنبال کردن این آموزش از "ImageNotification" استفاده کنید)، یکی از
Swift
یاObjective-C
انتخاب کنید و روی Finish کلیک کنید. - با کلیک روی «فعال کردن» ، طرح را فعال کنید.
مرحله 2 - اضافه کردن هدف به Podfile
سویفت
با افزودن پکیج FirebaseMessaging
swift به Runner
target خود، مطمئن شوید که افزونه جدید شما به آن دسترسی دارد:
از طریق ناویگاتور، SDK مربوط به پلتفرمهای اپل فایربیس را اضافه کنید : فایل > افزودن وابستگیهای بسته...
آدرس بسته را جستجو یا وارد کنید:
none https://github.com/firebase/firebase-ios-sdk
افزودن به
Runner
پروژه: افزودن بستهFirebaseMessaging را انتخاب کنید و ImageNotification را به target اضافه کنید: Add Package
هدف-سی
با اضافه کردن افزونه جدیدتان به Podfile، مطمئن شوید که به Firebase/Messaging
Pod دسترسی دارد:
از طریق ناوبر، فایل پاد را باز کنید: Pods > Podfile
به انتهای فایل بروید و اضافه کنید:
target 'ImageNotification' do use_frameworks! pod 'Firebase/Auth' # Add this line if you are using FirebaseAuth phone authentication pod 'Firebase/Messaging' end
پادهای خود را با استفاده از
pod install
از دایرکتوریios
یاmacos
نصب یا بهروزرسانی کنید.
مرحله ۳ - استفاده از افزونه کمکی
در این مرحله، همه چیز باید به طور عادی اجرا شود. مرحله آخر، فراخوانی تابع کمکی افزونه است.
سویفت
از طریق ناوبر، افزونهی ImageNotification خود را انتخاب کنید.
فایل
NotificationService.swift
را باز کنید.محتوای
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) } } }
هدف-سی
از طریق ناوبر، افزونهی ImageNotification خود را انتخاب کنید.
فایل
NotificationService.m
را باز کنید.در بالای فایل،
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
مرحله ۴ - تصویر را به payload اضافه کنید
اکنون میتوانید در بخش اعلانهای خود، یک تصویر اضافه کنید. برای کسب اطلاعات بیشتر، به نحوهی ساخت یک درخواست ارسال مراجعه کنید.