跳到内容

iOS 推送故事

推送故事 (Push stories) 可将展开的推送通知转变为全屏、Instagram 风格的故事体验:全出血图像、顶部进度条、自动前进页面、点击导航以及带有深层链接的按钮。它们由通知内容扩展 (Notification Content Extension) 使用独立的 PushwooshNotificationUI 模块呈现——您只需子类化一个视图控制器,SDK 就会处理解析、图像加载、进度、计时、导航和深层链接。

自 7.0.46 版本起可用。

在展开的通知中播放推送故事

1. 添加通知内容扩展 (Notification Content Extension)

Anchor link to

在 Xcode 中,选择 File > New > Target…,选择 Notification Content Extension,并为其命名(例如 StoriesContentExtension)。

在 Xcode 中添加 Notification Content Extension 目标

2. 添加 PushwooshNotificationUI 模块

Anchor link to

PushwooshNotificationUI 是一个独立的模块,没有其他 Pushwoosh 依赖项,因此在扩展进程中保持较小体积。请将其添加到内容扩展目标(而不是应用目标)。

Swift Package Manager

将 PushwooshNotificationUI 包添加到扩展目标

CocoaPods

target 'StoriesContentExtension' do
use_frameworks!
pod 'PushwooshXCFramework/PushwooshNotificationUI'
end

3. 子类化故事视图控制器

Anchor link to

将生成的 NotificationViewController 主体替换为 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点击页面按钮时打开的深层链接。
button_title页面按钮的标题。
title叠加在页面上的标题文本。
subtitle叠加在页面上的副标题文本。

在您的子类上重写属性以调整体验。所有属性都有合理的默认值。

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 }
}
属性默认值描述
storyAspectRatio1.5故事区域的宽高比(高 ÷ 宽)。请使其与 UNNotificationExtensionInitialContentSizeRatio 保持同步。
hapticsEnabledfalse在点击区域导航时播放轻微的触觉反馈。
longPressToPauseEnabledfalse按住可暂停当前页面;松开则恢复。
crossfadesBetweenPagesfalse在页面之间使用交叉溶解效果,而不是硬切换。当“减少动态效果”开启时,会回退到即时切换。
loopsAfterLastPagefalse在最后一页播放完毕后从第一页重新开始。
appGroupIdentifiernil与通知服务扩展 (Notification Service Extension) 共享的 App Group,用于媒体预缓存(见下文)。

您还可以重写 showDefaultContent(for:) 来自定义当有效负载缺失或格式错误时显示的回退内容(默认情况下显示警报正文)。

媒体预缓存

Anchor link to

为了实现即时、离线的首帧加载,请在您的内容扩展 (Content Extension) 和通知服务扩展 (Notification Service Extension) 之间共享一个 App Group。在故事控制器上重写 appGroupIdentifier,然后从您的服务扩展的 didReceive(_:withContentHandler:) 中预下载媒体:

import PushwooshNotificationUI
PushwooshStoriesMediaPrefetcher.prefetch(
userInfo: request.content.userInfo,
appGroupIdentifier: "group.com.example.app"
) {
contentHandler(bestAttemptContent)
}

在两个扩展上启用 App Groups 功能并使用相同的组标识符,并发送 mutable-content: 1 以便服务扩展运行。如果没有 App Group,媒体将被缓存在扩展的 tmp 目录中。

生命周期和分析回调

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) {}
}
回调触发时机
didStartWithPageCount:解析了有效的故事有效负载,即将开始播放。
didShow:at:一个页面变得可见。用它来统计每页的展示次数。
didTapActionFor:at:用户点击了行为召唤按钮。
storiesViewControllerDidFinish:最后一页播放完毕。
storiesViewControllerDidShowFallback:有效负载缺失或格式错误,并显示了回退内容。

传递给回调的 StoryPage 对象公开了页面的 imageURLdurationlinkbuttonTitletitlesubtitle

点击屏幕右侧三分之一区域可前往下一页,点击左侧三分之一区域可返回上一页。我们特意不使用水平滑动,因为它与系统的通知关闭手势冲突。点击页面按钮会打开其深层链接并关闭通知。

参考资料

Anchor link to