ข้ามไปยังเนื้อหา

การตั้งค่า Pushwoosh InboxKit iOS

มีให้ใช้งานตั้งแต่ iOS SDK 7.0.40

Pushwoosh InboxKit นำเสนอหน้าจอกล่องข้อความ UIKit ที่ทันสมัยซึ่งทำงานบนแบ็กเอนด์ของกล่องข้อความที่มีอยู่เดิม เลย์เอาต์เซลล์เริ่มต้นหกแบบครอบคลุมรูปทรงการ์ดเนื้อหาทั่วไป ตั้งแต่แบนเนอร์ธรรมดาไปจนถึงแกลเลอรีภาพแบบคารูเซล วิดีโอในตัว และบัตร Apple Wallet — ปุ่ม CTA ในตัวจัดการกับการโต้ตอบที่พบบ่อยที่สุด และพื้นผิวทั้งหมดเปิดให้ทำการ subclassing หากคุณต้องการรูปลักษณ์ที่กำหนดเอง

ฟีด InboxKit แสดงการ์ดแบนเนอร์, มีคำบรรยาย, คลาสสิก, คารูเซล, วิดีโอ และ Apple Wallet

ฟีด InboxKit เริ่มต้นพร้อมการ์ดแบนเนอร์, มีคำบรรยาย, คลาสสิก, คารูเซล, วิดีโอ และ Apple Wallet

เมื่อใดควรใช้ InboxKit

Anchor link to

ใช้ InboxKit สำหรับการผสานรวม iOS ใหม่ทั้งหมด เป็นโมดูลที่แนะนำให้ใช้แทนที่โมดูล Objective-C PushwooshInboxUI รุ่นเก่า

InboxKit ให้คุณ:

  • ประเภทเซลล์ในตัวหกประเภท — แบนเนอร์, มีคำบรรยาย, คลาสสิก, คารูเซล, วิดีโอ และ Apple Wallet — เลือกต่อข้อความผ่าน displayType ของ payload หรือบังคับจากโค้ดผ่าน attributes.forceCellKind ดู ประเภทการ์ด สำหรับรายการทั้งหมด (การ์ด Apple Wallet มีเฉพาะใน iOS เท่านั้น)
  • ปุ่ม CTA ในตัวพร้อม enum PushwooshInboxButtonAction ที่ระบุประเภท (openURL, dismiss, markRead, custom) SDK จะจัดการสามอย่างแรกโดยอัตโนมัติ delegate ของคุณจะส่ง custom ไปยังตรรกะของคุณเอง
  • รองรับการปักหมุด: ข้อความที่มี actionParams["pinned"] == true จะลอยอยู่ด้านบนของฟีดและแสดงสัญลักษณ์หมุด
  • ปัดเพื่อลบ, ดึงเพื่อรีเฟรช, ทำเครื่องหมายว่าอ่านแล้วโดยอัตโนมัติเมื่อหายไป — ทั้งหมดนี้สามารถสลับเปิดปิดได้ผ่าน PushwooshInboxKitAttributes
  • การจัดเก็บข้อมูลถาวร: การลบและสถานะการอ่านจะยังคงอยู่แม้จะรีสตาร์ทโปรเซสแล้ว แม้ว่าการเรียกเครือข่ายจะยังไม่ได้รับการยืนยันก็ตาม
  • คลาสพื้นฐาน PushwooshInboxCell ที่เปิดกว้างสำหรับเลย์เอาต์ที่กำหนดเองทั้งหมด

สัญญาของเซิร์ฟเวอร์ไม่เปลี่ยนแปลง — แบ็กเอนด์, payload และเครื่องมือบนแดชบอร์ดของ Pushwoosh inbox ยังคงทำงานเหมือนเดิม

เลือกวิธีการผสานรวมของคุณ

Anchor link to

ประเภทการ์ด

Anchor link to

InboxKit จะเลือกเลย์เอาต์เซลล์ต่อข้อความ ตัวแก้ไขเริ่มต้นจะอ่าน displayType จาก push payload — วางไว้ในอ็อบเจกต์ data ซึ่ง SDK จะส่งมอบภายใต้ actionParams เมื่อ displayType หายไป ตัวแก้ไขจะกลับไปใช้ฮิวริสติก: รูปภาพ + ไม่มีชื่อเรื่อง → แบนเนอร์, รูปภาพ + ชื่อเรื่อง + เนื้อหา → มีคำบรรยาย, มิฉะนั้นจะเป็นคลาสสิก หากต้องการบังคับใช้เลย์เอาต์เดียวสำหรับทั้งฟีดจากโค้ด ให้ตั้งค่า attributes.forceCellKind

แต่ละเลย์เอาต์ที่ซับซ้อนจะลดระดับลงอย่างสวยงาม: หากฟิลด์ที่จำเป็นขาดหายไปหรือมีรูปแบบไม่ถูกต้อง การ์ดจะกลับไปเป็น classic แทนที่จะแสดงตัวยึดตำแหน่งที่ว่างเปล่า (และจะมีการบันทึก WARN พร้อมเหตุผล) classic เป็นตัวสำรองสุดท้ายและจะแสดงสิ่งที่ข้อความมีอยู่ โดยคาดว่าตัวแก้ไขข้อความจะเติมชื่อเรื่อง, เนื้อหา และไอคอน

displayTypeเลย์เอาต์ฟิลด์ payload ที่จำเป็นลดระดับเป็น
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 เมื่อไม่มี descriptor
walletปุ่ม “Add to Apple Wallet” (เฉพาะ iOS)data.wallet (URL ของ .pkpass)classic เมื่อไม่มี URL ของบัตร
การ์ดแบนเนอร์ InboxKit
การ์ดแบนเนอร์
การ์ดมีคำบรรยาย InboxKit
การ์ดมีคำบรรยาย
การ์ดคลาสสิก InboxKit
การ์ดคลาสสิก
การ์ดคารูเซล InboxKit
การ์ดคารูเซล
การ์ดวิดีโอ InboxKit
การ์ดวิดีโอ
การ์ด Apple Wallet ของ InboxKit
การ์ด Apple Wallet

การ์ดแบนเนอร์, มีคำบรรยาย และคลาสสิกขับเคลื่อนโดยฟิลด์ข้อความมาตรฐาน (รูปภาพ, ชื่อเรื่อง, เนื้อหา) บวกกับอาร์เรย์ buttons ที่เป็นตัวเลือก — ดู เพิ่มปุ่ม CTA ในตัว การ์ดคารูเซล, วิดีโอ และ Apple Wallet มีข้อมูลโครงสร้างเพิ่มเติมภายใน data ซึ่งมีเอกสารอธิบายไว้ด้านล่าง

การ์ดคารูเซล

Anchor link to

คารูเซลจะแสดงภาพหลายภาพจากข้อความเดียว — เป็นแกลเลอรีที่ปัดได้พร้อมคำบรรยายและปลายทางการแตะต่อสไลด์ที่เป็นตัวเลือก สไลด์จะอยู่ใน data.carousel แต่ละสไลด์ต้องมี image; title (คำบรรยายซ้อนทับ) และ url (deep link ที่เปิดเมื่อแตะ) เป็นตัวเลือก สไลด์ที่ไม่มีรูปภาพจะถูกทิ้ง การแตะบนสไลด์ที่ไม่มี 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

การ์ดวิดีโอจะแสดงภาพโปสเตอร์พร้อมป้ายเล่น การแตะจะเปิดเครื่องเล่นเต็มหน้าจอ (เปิดเสียง แม้จะเปิดสวิตช์ปิดเสียงอยู่) descriptor จะอยู่ใน 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]
}]
}
}

ผลลัพธ์จะถูกรายงานไปยัง delegate ของคุณ:

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

ทั้งสอง callback เป็นตัวเลือก (มีการใช้งานเริ่มต้นที่ว่างเปล่า) การที่ผู้ใช้ยกเลิกชีตของระบบไม่ถือเป็นความสำเร็จหรือความล้มเหลว ดังนั้นจะไม่มี callback ใดทำงานในกรณีนั้น

การเข้าถึง

Anchor link to

เซลล์ของ InboxKit พร้อมใช้งานกับ VoiceOver ทันทีที่แกะกล่อง การ์ดแบนเนอร์, มีคำบรรยาย และคลาสสิกจะเปิดเผยชื่อเรื่อง, เนื้อหา และวันที่ผ่านป้ายกำกับพื้นฐาน และปุ่ม CTA ในตัวจะอ่านชื่อเรื่องของตัวเอง การ์ดที่ซับซ้อนจะเพิ่มความหมายที่ชัดเจน:

  • วิดีโอ — โปสเตอร์จะถูกเปิดเผยเป็นองค์ประกอบปุ่มเดียวที่มีป้ายกำกับว่า “Play video” (ลักษณะ .button + .startsMediaSession) ดังนั้น VoiceOver จะประกาศว่าเป็นตัวควบคุมสื่อแทนที่จะเป็นภาพธรรมดา
  • คารูเซล — แต่ละสไลด์เป็นองค์ประกอบปุ่มที่มีป้ายกำกับการเข้าถึงเป็นคำบรรยายของสไลด์ หรือ “Slide” เมื่อไม่มีคำบรรยาย ตัวบ่งชี้หน้าจะประกาศตำแหน่งปัจจุบันเป็น “n of total”
  • Apple Wallet — ปุ่ม Add to Apple Wallet เป็นปุ่ม PKAddPassButton มาตรฐานของ Apple ซึ่งมีป้ายกำกับ VoiceOver ที่แปลเป็นภาษาท้องถิ่นของตัวเอง

สำหรับการทดสอบ UI และระบบอัตโนมัติ มีการตั้งค่า accessibilityIdentifier ที่เสถียรสองตัว: inboxkit.video.play บนโปสเตอร์วิดีโอ และ inboxkit.wallet.add บนปุ่ม Wallet

อ่านข้อมูลที่กำหนดเองจากข้อความ

Anchor link to

เพื่อให้ push ปรากฏในกล่องข้อความ คำขอ createMessage ของ Messages API ต้องมี inbox_image, inbox_date หรือ inbox_days — หากไม่มีฟิลด์เหล่านี้ push จะถูกส่งเป็นการแจ้งเตือนปกติและจะไม่ไปถึงฟีดกล่องข้อความ ข้อมูลที่กำหนดเองแบบอิสระจะอยู่ภายใต้คีย์ 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 อ่านจาก delegate เมื่อผู้ใช้แตะแถวหรือ 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

ข้อความสามารถมีปุ่ม call-to-action ในตัวได้สูงสุดสามปุ่ม ปุ่มจะอยู่ร่วมกับข้อมูลที่กำหนดเองอื่น ๆ ภายใน 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จำเป็น ป้ายกำกับปุ่มที่มองเห็นได้
urlstringURL ที่ไม่ว่างเปล่าและสามารถแยกวิเคราะห์ได้จะสร้างการกระทำ openURL SDK จะเปิดผ่าน UIApplication.shared.open เว้นแต่ delegate ของคุณจะระงับไว้
actionstringโทเค็นการกระทำที่ชัดเจน: dismiss (ลบข้อความออกจากฟีด), markRead (ทำเครื่องหมายข้อความว่าอ่านแล้ว) หรือ custom (จัดการโดยโฮสต์) ไม่คำนึงถึงตัวพิมพ์เล็ก-ใหญ่
อื่นๆanyเมื่อ action เป็น custom ทุกคีย์บนอ็อบเจกต์ปุ่มยกเว้น title และ action จะถูกส่งต่อไปยัง delegate ของคุณเป็น payload ที่กำหนดเอง — ตกลงคีย์กับนักการตลาด (เช่น tag) และจัดการตามนั้น

ลำดับความสำคัญในการแก้ไข: โทเค็น action ที่ชัดเจนก่อน จากนั้นเป็น url หากไม่ว่างเปล่า มิฉะนั้นปุ่มจะตกไปอยู่ใน custom โดยมี payload ทั้งหมด (ลบ title และ action)

ดักจับการแตะจาก delegate ของคุณ คุณสมบัติ button.action คือ enum 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
}
}
}