跳到内容

设置 Pushwoosh InboxKit iOS

自 iOS SDK 7.0.40 起可用。

Pushwoosh InboxKit 在现有收件箱后端的基础上提供了一个现代化的 UIKit 收件箱屏幕。六种默认的单元格布局涵盖了常见的内容卡片形式——从简单的横幅到图片轮播、内联视频和 Apple Wallet 通行证——内联 CTA 按钮处理最常见的交互,并且整个界面都开放用于子类化,以满足您定制外观的需求。

InboxKit 信息流,显示横幅、带标题、经典、轮播、视频和 Apple Wallet 卡片

默认的 InboxKit 信息流,包含横幅、带标题、经典、轮播、视频和 Apple Wallet 卡片。

何时使用 InboxKit

Anchor link to

对于任何新的 iOS 集成,请使用 InboxKit。它是对旧版 Objective-C PushwooshInboxUI 模块的推荐替代品。

InboxKit 为您提供:

  • 六种内置单元格类型——横幅、带标题、经典、轮播、视频和 Apple Wallet——可通过 payload 的 displayType 为每条消息选择,或通过代码中的 attributes.forceCellKind 强制指定。完整列表请参见卡片类型。(Apple Wallet 卡片仅适用于 iOS。)
  • 带有类型化 PushwooshInboxButtonAction 枚举(openURLdismissmarkReadcustom)的内联 CTA 按钮。SDK 会自动处理前三种;您的委托将 custom 路由到您自己的逻辑。
  • 置顶支持:actionParams["pinned"] == true 的消息会浮动到信息流顶部并呈现一个图钉图标。
  • 滑动删除、下拉刷新、消失时自动标记为已读——所有这些都可以通过 PushwooshInboxKitAttributes 进行切换。
  • 持久化存储:即使网络调用尚未被确认,删除和已读状态在进程重启后依然保留。
  • 一个开放的 PushwooshInboxCell 基类,用于完全自定义的布局。

服务器契约保持不变——与之前一样,使用相同的 Pushwoosh 收件箱后端、payload 和仪表板工具。

选择您的集成方法

Anchor link to

卡片类型

Anchor link to

InboxKit 为每条消息选择一个单元格布局。默认解析器从推送 payload 中读取 displayType——将其放在 data 对象内,SDK 会在 actionParams 下传递该对象。当 displayType 缺失时,解析器会回退到一个启发式规则:有图片无标题 → 横幅,有图片有标题 → 带标题,否则为经典。要从代码中为整个信息流强制使用一种布局,请设置 attributes.forceCellKind

每种富文本布局都能优雅地降级:如果所需的 payload 缺失或格式错误,卡片会回退到 classic,而不是渲染一个空的占位符(并会记录一个 WARN)。

displayType布局必需的 payload 字段降级为
banner全出血图片,无文本图片(inbox_imagedata.image无图片时为 classic
captioned顶部图片,下方标题+正文图片(inbox_imagedata.image无图片时为 classic
classic彩色首字母头像+标题+正文
carousel可滑动的多图库data.carousel(幻灯片数组)无幻灯片时为 classic
video带播放徽章的海报,点击后全屏播放data.videourl + 可选的 poster无描述符时为 classic
wallet“添加到 Apple Wallet” 按钮(仅限 iOS)data.wallet.pkpass URL)无通行证 URL 时为 classic
InboxKit 横幅卡片
横幅卡片
InboxKit 带标题卡片
带标题卡片
InboxKit 经典卡片
经典卡片
InboxKit 轮播卡片
轮播卡片
InboxKit 视频卡片
视频卡片
InboxKit Apple Wallet 卡片
Apple Wallet 卡片

横幅、带标题和经典卡片由标准消息字段(图片、标题、正文)以及可选的 buttons 数组驱动——请参见添加内联 CTA 按钮。轮播、视频和 Apple Wallet 卡片在 data 内部携带额外的结构化数据,具体如下所述。

轮播卡片

Anchor link to

轮播卡片可从单条消息中渲染多张图片——一个可滑动的图库,带有可选的每张幻灯片标题和点击目标。幻灯片位于 data.carousel 中。每张幻灯片都需要一个 imagetitle(标题覆盖层)和 url(点击时打开的深层链接)是可选的。没有图片的幻灯片将被丢弃;点击没有 url 的幻灯片会回退到消息的默认行操作。

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 卡片在官方的添加到 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) {
// 通行证现在在用户的 Wallet 中——如果需要,可以显示一个确认信息。
}
func inboxKit(_ vc: PushwooshInboxKitViewController,
didFailToAddWalletPassFor message: PWInboxMessageProtocol,
error: Error?) {
// 下载失败——提供重试、记录日志等。
}
}

两个回调都是可选的(它们带有默认的空实现)。用户取消系统界面既不是成功也不是失败,因此在这种情况下不会触发任何回调。

辅助功能

Anchor link to

InboxKit 单元格开箱即支持 VoiceOver。横幅、带标题和经典卡片通过其底层的标签公开其标题、正文和日期,内联 CTA 按钮会读出自己的标题。富文本卡片添加了明确的语义:

  • 视频 — 海报被公开为单个按钮元素,标记为“播放视频”(特征为 .button + .startsMediaSession),因此 VoiceOver 会将其作为媒体控件而不是普通图片来播报。
  • 轮播 — 每个幻灯片都是一个按钮元素,其辅助功能标签是幻灯片的标题,如果没有标题则是“幻灯片”。页面指示器会播报当前位置为“第 n 页,共 total 页”。
  • Apple Wallet添加到 Apple Wallet 按钮是 Apple 的标准 PKAddPassButton,它带有自己的本地化 VoiceOver 标签。

对于 UI 测试和自动化,设置了两个稳定的 accessibilityIdentifier:视频海报上的 inboxkit.video.play 和 Wallet 按钮上的 inboxkit.wallet.add

从消息中读取自定义数据

Anchor link to

要使推送出现在收件箱中,Messages APIcreateMessage 请求必须包含 inbox_imageinbox_dateinbox_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 }
// 自定义 `data` 对象在 "u" 键下到达——
// 可以是嵌套的字典,也可以是 JSON 编码的字符串,
// 具体取决于 payload 在上游的构建方式。
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 // 我们处理了点击;SDK 不应运行默认操作
}
return true
}
}

对于内联 CTA 按钮,在 inboxKit(_:didTapButton:onMessage:) 内部使用相同的 actionParams["u"] 查找。对于类型化的 CTA 情况(openURLdismissmarkRead),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必需。可见的按钮标签。
urlstring一个非空的可解析 URL 会产生一个 openURL 操作。除非您的委托禁止,否则 SDK 会通过 UIApplication.shared.open 打开它。
actionstring显式操作令牌:dismiss(从信息流中移除消息)、markRead(将消息标记为已读)或 custom(由宿主处理)。不区分大小写。
其他任何字段anyactioncustom 时,按钮对象上除 titleaction 之外的每个键都会作为自定义 payload 转发给您的委托——与营销人员商定一个键(例如 tag)并据此进行分派。

解析优先级:首先是显式的 action 令牌,然后如果 url 非空则使用 url,否则按钮会回退到 custom,并携带完整的 payload(减去 titleaction)。

从您的委托中拦截点击。button.action 属性是类型化的 PushwooshInboxButtonAction 枚举:

extension MyInboxHost: PushwooshInboxKitDelegate {
func inboxKit(_ vc: PushwooshInboxKitViewController,
didTapButton button: PushwooshInboxButton,
onMessage message: PWInboxMessageProtocol) -> Bool {
switch button.action {
case .openURL(let url):
// 默认行为没问题——让 SDK 打开 URL。
return true
case .dismiss, .markRead:
// SDK 处理这两种情况。如果想覆盖,返回 false。
return true
case .custom(let payload):
// 营销人员定义的自定义按钮。根据你们商定的键进行分派。
if let tag = payload["tag"] as? String {
switch tag {
case "save_promo":
saveCurrentPromoLocally(message: message)
default:
break
}
}
return true // 对于 custom 会被忽略——SDK 在这里从不运行默认操作
}
}
}