قصص الإشعارات الفورية لنظام iOS
تحول قصص الإشعارات الفورية (Push stories) الإشعار الفوري الموسع إلى تجربة قصص بملء الشاشة بأسلوب Instagram: صور تملأ الشاشة بالكامل، أشرطة تقدم في الأعلى، صفحات تتقدم تلقائيًا، النقر للتنقل، وزر مع رابط عميق (deep link). يتم عرضها بواسطة ملحق محتوى الإشعارات (Notification Content Extension) باستخدام وحدة PushwooshNotificationUI المستقلة — كل ما عليك هو عمل subclass لوحدة تحكم عرض واحدة (view controller) ويتولى SDK التعامل مع التحليل (parsing)، تحميل الصور، التقدم، التوقيت، التنقل، والروابط العميقة.
متوفر منذ الإصدار 7.0.46.

1. إضافة ملحق محتوى الإشعارات (Notification Content Extension)
Anchor link toفي Xcode، اختر File > New > Target…، حدد Notification Content Extension، وقم بتسميته (على سبيل المثال StoriesContentExtension).

2. إضافة وحدة PushwooshNotificationUI
Anchor link toPushwooshNotificationUI هي وحدة مستقلة لا تعتمد على أي وحدات أخرى من Pushwoosh، لذا يبقى حجمها صغيرًا داخل عملية الملحق. أضفها إلى هدف ملحق المحتوى (وليس هدف التطبيق).
Swift Package Manager

CocoaPods
target 'StoriesContentExtension' do use_frameworks!
pod 'PushwooshXCFramework/PushwooshNotificationUI'end3. عمل Subclass لوحدة تحكم عرض القصص
Anchor link toاستبدل محتوى NotificationViewController الذي تم إنشاؤه بـ subclass من PushwooshStoriesViewController. هذا هو كل التكامل المطلوب.
import PushwooshNotificationUI
class NotificationViewController: PushwooshStoriesViewController {}4. تكوين Info.plist للملحق
Anchor link toفي ملف Info.plist الخاص بملحق المحتوى، قم بتعيين المفاتيح التالية تحت NSExtension > NSExtensionAttributes:
<key>UNNotificationExtensionCategory</key><string>PW_STORIES</string><key>UNNotificationExtensionUserInteractionEnabled</key><true/><key>UNNotificationExtensionDefaultContentHidden</key><true/><key>UNNotificationExtensionInitialContentSizeRatio</key><real>1.5</real>5. إرسال إشعار قصص فورية
Anchor link toأرسل إشعارًا تكون فئته PW_STORIES وتحمل بياناته المخصصة كتلة pw_stories. استخدم حقل ios_category_custom المخصص للفئة وحقل data لحمولة القصص.
{ "request": { "application": "APPLICATION_CODE", "auth": "API_ACCESS_TOKEN", "notifications": [ { "send_date": "now", "content": "Tap to explore", "ios_title": "Push Stories", "ios_category_custom": "PW_STORIES", "ios_root_params": { "aps": { "mutable-content": 1 } }, "data": { "pw_stories": { "pages": [ { "image": "https://example.com/story-1.jpg", "duration": 5.0, "link": "yourapp://page1", "button_title": "Get started", "title": "Welcome", "subtitle": "Swipe to explore what's new" }, { "image": "https://example.com/story-2.jpg", "duration": 4.0, "link": "yourapp://page2", "button_title": "Learn more", "title": "Stay in the loop", "subtitle": "Updates, tips and more" } ] } } } ] }}تدعم كل صفحة الحقول التالية. حقل image فقط هو المطلوب؛ والباقي اختياري.
| الحقل | الوصف |
|---|---|
image | رابط URL للصورة بملء الشاشة للصفحة. |
duration | عدد الثواني التي تظل فيها الصفحة على الشاشة قبل التقدم التلقائي. القيمة الافتراضية حوالي 5 ثوانٍ. |
link | رابط عميق (Deep link) يتم فتحه عند النقر على زر الصفحة. |
button_title | عنوان زر الصفحة. |
title | نص العنوان الذي يظهر فوق الصفحة. |
subtitle | نص العنوان الفرعي الذي يظهر فوق الصفحة. |
التخصيص
Anchor link toقم بتجاوز (Override) الخصائص في الـ subclass الخاص بك لتعديل التجربة. جميعها لها قيم افتراضية معقولة.
import PushwooshNotificationUI
class NotificationViewController: PushwooshStoriesViewController { override var storyAspectRatio: CGFloat { 1.5 } // keep in sync with InitialContentSizeRatio override var hapticsEnabled: Bool { true } override var longPressToPauseEnabled: Bool { true } override var crossfadesBetweenPages: Bool { true } override var loopsAfterLastPage: Bool { false }}| الخاصية | الافتراضي | الوصف |
|---|---|---|
storyAspectRatio | 1.5 | نسبة العرض إلى الارتفاع (الارتفاع ÷ العرض) لمنطقة القصص. حافظ على تزامنها مع UNNotificationExtensionInitialContentSizeRatio. |
hapticsEnabled | false | تشغيل نقرة لمسية خفيفة عند التنقل في منطقة النقر. |
longPressToPauseEnabled | false | الضغط مع الاستمرار يوقف الصفحة الحالية؛ ورفع الإصبع يستأنفها. |
crossfadesBetweenPages | false | تلاشي متقاطع بين الصفحات بدلاً من الانتقال الحاد. يعود إلى التغيير الفوري عند تشغيل تقليل الحركة (Reduce Motion). |
loopsAfterLastPage | false | إعادة التشغيل من الصفحة الأولى بعد انتهاء الصفحة الأخيرة. |
appGroupIdentifier | nil | مجموعة التطبيقات (App Group) مشتركة مع ملحق خدمة الإشعارات (Notification Service Extension) للتخزين المؤقت المسبق للوسائط (انظر أدناه). |
يمكنك أيضًا تجاوز (override) showDefaultContent(for:) لتخصيص المحتوى الاحتياطي الذي يظهر عندما تكون الحمولة مفقودة أو غير صحيحة (بشكل افتراضي، يعرض محتوى التنبيه).
التخزين المؤقت المسبق للوسائط
Anchor link toللحصول على إطار أول فوري وغير متصل بالإنترنت، شارك مجموعة تطبيقات (App Group) بين ملحق المحتوى الخاص بك وملحق خدمة الإشعارات (Notification Service Extension). قم بتجاوز appGroupIdentifier في وحدة تحكم القصص، ثم قم بتنزيل الوسائط مسبقًا من didReceive(_:withContentHandler:) في ملحق الخدمة الخاص بك:
import PushwooshNotificationUI
PushwooshStoriesMediaPrefetcher.prefetch( userInfo: request.content.userInfo, appGroupIdentifier: "group.com.example.app") { contentHandler(bestAttemptContent)}قم بتمكين قدرة App Groups على كلا الملحقين بنفس معرف المجموعة، وأرسل mutable-content: 1 حتى يعمل ملحق الخدمة. بدون مجموعة تطبيقات، يتم تخزين الوسائط مؤقتًا في دليل tmp الخاص بالملحق بدلاً من ذلك.
دورة الحياة وردود الاتصال التحليلية (Lifecycle and analytics callbacks)
Anchor link toقم بتعيين storiesDelegate لمراقبة أحداث القصة — مرات ظهور الصفحة، نقرات الأزرار، الإكمال، والمحتوى الاحتياطي. يجب أن يتوافق مع PushwooshStoriesDelegate؛ كل دالة اختيارية، لذا قم بتنفيذ الدوال التي تحتاجها فقط.
import PushwooshNotificationUI
class NotificationViewController: PushwooshStoriesViewController, PushwooshStoriesDelegate { override func viewDidLoad() { super.viewDidLoad() storiesDelegate = self }
func storiesViewController(_ controller: PushwooshStoriesViewController, didStartWithPageCount pageCount: Int) {} func storiesViewController(_ controller: PushwooshStoriesViewController, didShow page: StoryPage, at index: Int) {} func storiesViewController(_ controller: PushwooshStoriesViewController, didTapActionFor page: StoryPage, at index: Int) {} func storiesViewControllerDidFinish(_ controller: PushwooshStoriesViewController) {} func storiesViewControllerDidShowFallback(_ controller: PushwooshStoriesViewController) {}}| رد الاتصال (Callback) | متى يتم تفعيله |
|---|---|
didStartWithPageCount: | تم تحليل حمولة قصص صالحة والتشغيل على وشك البدء. |
didShow:at: | أصبحت الصفحة مرئية. استخدمها لتسجيل مرات الظهور لكل صفحة. |
didTapActionFor:at: | نقر المستخدم على زر الحث على اتخاذ إجراء. |
storiesViewControllerDidFinish: | انتهى تشغيل الصفحة الأخيرة. |
storiesViewControllerDidShowFallback: | كانت الحمولة مفقودة أو غير صحيحة وتم عرض المحتوى الاحتياطي. |
الكائن StoryPage الذي يتم تمريره إلى ردود الاتصال يكشف عن imageURL، duration، link، buttonTitle، title، و subtitle للصفحة.
التنقل
Anchor link toانقر على الثلث الأيمن من الشاشة للانتقال إلى الصفحة التالية والثلث الأيسر للعودة. لم يتم استخدام السحب الأفقي عن قصد، لأنه يتعارض مع إيماءة النظام لرفض الإشعارات. النقر على زر الصفحة يفتح الرابط العميق الخاص به ويرفض الإشعار.