انتقل إلى المحتوى

إعداد Pushwoosh InboxKit لنظام iOS

متوفر منذ iOS SDK 7.0.40.

يقدم Pushwoosh InboxKit شاشة صندوق وارد حديثة تعتمد على UIKit فوق الواجهة الخلفية الحالية لصندوق الوارد. تغطي ستة تخطيطات خلايا افتراضية أشكال بطاقات المحتوى الشائعة — من اللافتات البسيطة إلى دوارات الصور والفيديو المضمن وبطاقات Apple Wallet — وتتعامل أزرار CTA المضمنة مع التفاعلات الأكثر شيوعًا، والسطح بأكمله مفتوح للتصنيف الفرعي إذا كنت بحاجة إلى مظهر مخصص.

InboxKit feed showing banner, captioned, classic, carousel, video and Apple Wallet cards

موجز InboxKit الافتراضي مع بطاقات البانر، والتعليقات التوضيحية، والكلاسيكية، والدائرية، والفيديو، وApple Wallet.

متى تستخدم InboxKit

Anchor link to

استخدم InboxKit لأي تكامل جديد لنظام iOS. إنه البديل الموصى به لوحدة Objective-C الأقدم PushwooshInboxUI.

يمنحك InboxKit:

  • ستة أنواع خلايا مدمجة — بانر، مع تعليق، كلاسيكي، دائري، فيديو، وApple Wallet — يتم تحديدها لكل رسالة عبر displayType للحمولة، أو فرضها من الكود عبر attributes.forceCellKind. راجع أنواع البطاقات للحصول على القائمة الكاملة. (بطاقة Apple Wallet مخصصة لنظام iOS فقط.)
  • أزرار CTA مضمنة مع تعداد PushwooshInboxButtonAction محدد النوع (openURL، dismiss، markRead، custom). يتعامل SDK مع الثلاثة الأولى تلقائيًا؛ ويوجه مندوبك custom إلى منطقك الخاص.
  • دعم التثبيت: الرسائل التي تحتوي على actionParams["pinned"] == true تطفو إلى أعلى الموجز وتعرض رمز دبوس.
  • السحب للحذف، السحب للتحديث، التحديد التلقائي كمقروء عند الاختفاء — كلها قابلة للتبديل عبر PushwooshInboxKitAttributes.
  • تخزين دائم: تبقى عمليات الحذف وحالة القراءة بعد إعادة تشغيل العملية حتى لو لم يتم الإقرار باستدعاء الشبكة بعد.
  • فئة أساسية مفتوحة PushwooshInboxCell للتخطيطات المخصصة بالكامل.

عقد الخادم لم يتغير — تعمل نفس الواجهة الخلفية لصندوق الوارد في Pushwoosh، والحمولات، وأدوات لوحة التحكم كما كان من قبل.

اختر طريقة التكامل الخاصة بك

Anchor link to

أنواع البطاقات

Anchor link to

يختار InboxKit تخطيط خلية لكل رسالة. يقرأ المحلل الافتراضي displayType من حمولة الدفع — ضعه داخل كائن data، الذي يقدمه SDK تحت actionParams. عندما يكون displayType مفقودًا، يعود المحلل إلى طريقة استدلالية: صورة + لا يوجد عنوان ← بانر، صورة + عنوان + نص ← مع تعليق، وإلا كلاسيكي. لفرض تخطيط واحد للموجز بأكمله من الكود، قم بتعيين attributes.forceCellKind.

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

displayTypeالتخطيطحقل الحمولة المطلوبيتدهور إلى
bannerصورة بعرض كامل، بدون نصصورة (inbox_image أو data.image)classic عند عدم وجود صورة
captionedصورة في الأعلى، عنوان + نص أدناهصورة (inbox_image أو data.image)، title و content للرسالةclassic عند فقدان الصورة أو العنوان أو النص
classicصورة رمزية أولية ملونة + عنوان + نص— (من المتوقع وجود عنوان ونص وأيقونة)—
carouselمعرض صور متعددة قابل للسحبtitle و content للرسالة، data.carousel (1–5 شرائح)classic عند عدم وجود شرائح أو عدم وجود عنوان/نص
videoملصق مع شارة تشغيل، مشغل بملء الشاشة عند النقرdata.video (url + poster اختياري)classic عند عدم وجود واصف
walletزر “Add to Apple Wallet” (لنظام iOS فقط)data.wallet (عنوان URL لـ .pkpass)classic عند عدم وجود عنوان URL للمرور
InboxKit banner card
بطاقة بانر
InboxKit captioned card
بطاقة مع تعليق
InboxKit classic card
بطاقة كلاسيكية
InboxKit carousel card
بطاقة دائرية
InboxKit video card
بطاقة فيديو
InboxKit Apple Wallet card
بطاقة Apple Wallet

يتم تشغيل بطاقات البانر، والتعليقات التوضيحية، والكلاسيكية بواسطة حقول الرسائل القياسية (الصورة، العنوان، النص) بالإضافة إلى مصفوفة buttons الاختيارية — راجع إضافة أزرار CTA مضمنة. تحمل بطاقات الدوارة والفيديو وApple Wallet بيانات منظمة إضافية داخل data، موثقة أدناه.

بطاقة دائرية

Anchor link to

تعرض البطاقة الدائرية عدة صور من رسالة واحدة — معرض قابل للسحب مع تعليقات اختيارية لكل شريحة ووجهات للنقر. توجد الشرائح في data.carousel. تحتاج كل شريحة إلى image؛ title (تراكب التعليق) و url (رابط عميق يفتح عند النقر) اختيارية. يتم إسقاط الشريحة التي لا تحتوي على صورة؛ والنقر على شريحة بدون url ينتقل إلى إجراء الصف الافتراضي للرسالة. يتم عرض 5 شرائح على الأكثر — يتم إسقاط الشرائح الإضافية (الشريحة التي لا تحتوي على صورة لا تستهلك مكانًا). title و content للرسالة إلزاميان لهذا التخطيط؛ بدونهما تتدهور البطاقة إلى classic.

POST https://api.pushwoosh.com/json/1.3/createMessage
{
"request": {
"application": "XXXXX-XXXXX",
"auth": "API_TOKEN",
"notifications": [{
"send_date": "now",
"ios_title": "New arrivals",
"content": "Swipe through this week's drops",
"inbox_days": 7,
"data": {
"displayType": "carousel",
"carousel": [
{ "image": "https://cdn.example.com/inbox/1.jpg", "title": "New in", "url": "myapp://product/1" },
{ "image": "https://cdn.example.com/inbox/2.jpg", "title": "On sale", "url": "myapp://product/2" },
{ "image": "https://cdn.example.com/inbox/3.jpg" }
]
},
"platforms": [1]
}]
}
}

بطاقة فيديو

Anchor link to

تعرض بطاقة الفيديو صورة ملصق مع شارة تشغيل؛ يؤدي النقر عليها إلى فتح مشغل بملء الشاشة (الصوت قيد التشغيل، حتى مع تعشيق مفتاح الصامت). يوجد الواصف في data.video: url مطلوب ويجب أن يكون بثًا أو ملفًا http/https؛ poster هو صورة معاينة اختيارية.

POST https://api.pushwoosh.com/json/1.3/createMessage
{
"request": {
"application": "XXXXX-XXXXX",
"auth": "API_TOKEN",
"notifications": [{
"send_date": "now",
"ios_title": "Watch the reveal",
"content": "Tap to play",
"inbox_days": 7,
"data": {
"displayType": "video",
"video": {
"url": "https://cdn.example.com/inbox/clip.mp4",
"poster": "https://cdn.example.com/inbox/poster.jpg"
}
},
"platforms": [1]
}]
}
}

بطاقة Apple Wallet

Anchor link to

تعرض بطاقة Apple Wallet صورة بطل اختيارية وعنوانًا ونصًا فوق زر Add to Apple Wallet الرسمي. يؤدي النقر على الزر إلى تنزيل .pkpass وتقديم ورقة إضافة التصاريح الخاصة بالنظام. استخدمها لتقديم القسائم أو بطاقات الولاء أو التذاكر أو بطاقات الصعود إلى الطائرة مباشرة من صندوق الوارد. البطاقة مخصصة لنظام iOS / Mac Catalyst فقط — على المنصات الأخرى، يتم عرض الرسالة كبطاقة كلاسيكية.

يوجد عنوان URL للمرور في data.wallet، إما كسلسلة نصية مجردة أو ككائن يحتوي على حقل pass. تضيف data.image الاختيارية صورة البطل. يخفي الزر نفسه تلقائيًا عند عدم وجود عنوان URL للمرور أو عندما لا يتمكن الجهاز من إضافة التصاريح.

POST https://api.pushwoosh.com/json/1.3/createMessage
{
"request": {
"application": "XXXXX-XXXXX",
"auth": "API_TOKEN",
"notifications": [{
"send_date": "now",
"ios_title": "Your loyalty card is ready",
"content": "Add it to Apple Wallet in one tap",
"inbox_days": 7,
"data": {
"displayType": "wallet",
"image": "https://cdn.example.com/inbox/loyalty.png",
"wallet": "https://passes.example.com/v1/passes/pass.com.example.loyalty/abc123?token=…"
},
"platforms": [1]
}]
}
}

يتم إبلاغ مندوبك بالنتيجة:

extension MyInboxHost: PushwooshInboxKitDelegate {
func inboxKit(_ vc: PushwooshInboxKitViewController,
didAddWalletPassFor message: PWInboxMessageProtocol) {
// The pass is now in the user's Wallet — show a confirmation if you like.
}
func inboxKit(_ vc: PushwooshInboxKitViewController,
didFailToAddWalletPassFor message: PWInboxMessageProtocol,
error: Error?) {
// Download failed — surface a retry, log, etc.
}
}

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

إمكانية الوصول

Anchor link to

خلايا InboxKit جاهزة لـ VoiceOver خارج الصندوق. تعرض بطاقات البانر، والتعليقات التوضيحية، والكلاسيكية عنوانها ونصها وتاريخها من خلال التسميات الأساسية، وتقرأ أزرار CTA المضمنة عناوينها الخاصة. تضيف البطاقات الغنية دلالات صريحة:

  • الفيديو — يتم عرض الملصق كعنصر زر واحد يسمى “تشغيل الفيديو” (السمات .button + .startsMediaSession)، لذلك يعلن VoiceOver عنه كعنصر تحكم في الوسائط بدلاً من صورة عادية.
  • الدوارة — كل شريحة هي عنصر زر تكون تسمية إمكانية الوصول الخاصة به هي تعليق الشريحة، أو “شريحة” عندما لا تحتوي على أي تعليق. يعلن مؤشر الصفحة عن الموضع الحالي كـ “n من الإجمالي”.
  • Apple Wallet — زر Add to Apple Wallet هو زر PKAddPassButton القياسي من Apple، والذي يحمل تسمية VoiceOver المترجمة الخاصة به.

لإجراء اختبارات واجهة المستخدم والأتمتة، يتم تعيين معرفين ثابتين لـ accessibilityIdentifier: inboxkit.video.play على ملصق الفيديو و inboxkit.wallet.add على زر Wallet.

قراءة البيانات المخصصة من رسالة

Anchor link to

لجعل إشعار الدفع يظهر في صندوق الوارد، يجب أن يتضمن طلب createMessage في Messages API inbox_image أو inbox_date أو inbox_days — بدون أحد هذه الحقول، يتم تسليم إشعار الدفع كإشعار عادي ولا يصل أبدًا إلى موجز صندوق الوارد. توضع البيانات المخصصة ذات الشكل الحر تحت مفتاح data، الذي يقدمه SDK إلى العميل كمعلمة u:

POST https://api.pushwoosh.com/json/1.3/createMessage
{
"request": {
"application": "XXXXX-XXXXX",
"auth": "API_TOKEN",
"notifications": [{
"send_date": "now",
"ios_title": "Summer sale",
"content": "30% off everything — limited time only",
"inbox_image": "https://cdn.example.com/inbox/summer.png",
"inbox_days": 7,
"data": {
"displayType": "captioned",
"promo_id": "SUMMER2026",
"screen": "promo_details"
},
"platforms": [1]
}]
}
}

يعرض SDK هذا الكائن في رسالة صندوق الوارد من خلال actionParams. اقرأه من المندوب عندما ينقر المستخدم على الصف أو على زر CTA مضمن:

extension MyInboxHost: PushwooshInboxKitDelegate {
func inboxKit(_ vc: PushwooshInboxKitViewController,
didSelect message: PWInboxMessageProtocol) -> Bool {
guard let params = message.actionParams as? [String: Any] else { return true }
// The custom `data` object arrives under the "u" key —
// either as a nested dictionary or as a JSON-encoded string,
// depending on how the payload was built upstream.
let custom: [String: Any]? = {
if let dict = params["u"] as? [String: Any] { return dict }
if let raw = params["u"] as? String,
let bytes = raw.data(using: .utf8),
let parsed = try? JSONSerialization.jsonObject(with: bytes) as? [String: Any] {
return parsed
}
return nil
}()
if let promoId = custom?["promo_id"] as? String {
navigateToPromo(promoId)
return false // we handled the tap; SDK should not run the default action
}
return true
}
}

يعمل نفس البحث actionParams["u"] داخل inboxKit(_:didTapButton:onMessage:) لأزرار CTA المضمنة. بالنسبة لحالات CTA المكتوبة (openURL، dismiss، markRead)، يقوم SDK بالفعل بتنفيذ الإجراء الافتراضي — أرجع true للحفاظ على هذا السلوك، أو false لقمعه وتشغيل سلوكك الخاص.

إضافة أزرار CTA مضمنة

Anchor link to

يمكن أن تحمل الرسالة ما يصل إلى ثلاثة أزرار استدعاء مضمنة. توجد الأزرار جنبًا إلى جنب مع البيانات المخصصة الأخرى داخل data كمصفوفة buttons. يقوم SDK بعرضها تلقائيًا داخل الخلايا ذات التعليقات التوضيحية والكلاسيكية:

POST https://api.pushwoosh.com/json/1.3/createMessage
{
"request": {
"application": "XXXXX-XXXXX",
"auth": "API_TOKEN",
"notifications": [{
"send_date": "now",
"ios_title": "New promo card",
"content": "Tap a button to claim or save",
"inbox_image": "https://cdn.example.com/inbox/promo.png",
"inbox_days": 7,
"data": {
"displayType": "captioned",
"promo_id": "SUMMER2026",
"buttons": [
{ "title": "Claim", "url": "https://example.com/promo/SUMMER2026" },
{ "title": "Read", "action": "markRead" },
{ "title": "Save", "action": "custom", "tag": "save_promo" }
]
},
"platforms": [1]
}]
}
}

يحتوي كل كائن زر على هذه الحقول:

الحقلالنوعمتى
titlestringمطلوب. تسمية الزر المرئية.
urlstringينتج عنوان URL غير فارغ وقابل للتحليل إجراء openURL. يفتحه SDK عبر UIApplication.shared.open ما لم يقم مندوبك بقمعه.
actionstringرمز إجراء صريح: dismiss (يزيل الرسالة من الموجز)، markRead (يحدد الرسالة كمقروءة)، أو custom (يتعامل معه المضيف). غير حساس لحالة الأحرف.
أي شيء آخرanyعندما يكون action هو custom، يتم إعادة توجيه كل مفتاح في كائن الزر باستثناء title و action إلى مندوبك كحمولة مخصصة — اتفق على مفتاح مع المسوق (مثل tag) وقم بالتوزيع بناءً عليه.

أولوية الحل: رمز action الصريح أولاً، ثم url إذا كان غير فارغ، وإلا فإن الزر يقع في custom حاملاً الحمولة الكاملة (ناقص title و action).

اعترض النقرات من مندوبك. خاصية button.action هي تعداد PushwooshInboxButtonAction المكتوب:

extension MyInboxHost: PushwooshInboxKitDelegate {
func inboxKit(_ vc: PushwooshInboxKitViewController,
didTapButton button: PushwooshInboxButton,
onMessage message: PWInboxMessageProtocol) -> Bool {
switch button.action {
case .openURL(let url):
// Default behavior is fine — let SDK open the URL.
return true
case .dismiss, .markRead:
// SDK handles both. Return false if you want to override.
return true
case .custom(let payload):
// Marketer-defined custom button. Dispatch on a key you agreed on.
if let tag = payload["tag"] as? String {
switch tag {
case "save_promo":
saveCurrentPromoLocally(message: message)
default:
break
}
}
return true // ignored for custom — SDK never runs a default action here
}
}
}