Push Stories для iOS
Push stories превращают расширенное push-уведомление в полноэкранный просмотр историй в стиле Instagram: изображения без полей, индикаторы выполнения вверху, автоматическое переключение страниц, навигация касанием и кнопка с deep link’ом. Они отображаются с помощью Notification Content Extension, используя автономный модуль PushwooshNotificationUI — вы создаете подкласс одного view controller’а, а SDK обрабатывает парсинг, загрузку изображений, прогресс, тайминги, навигацию и deep link’и.
Доступно с версии 7.0.46.

1. Добавьте Notification Content Extension
Anchor link toВ Xcode выберите File > New > Target…, затем Notification Content Extension и назовите его (например, StoriesContentExtension).

2. Добавьте модуль PushwooshNotificationUI
Anchor link toPushwooshNotificationUI — это автономный модуль без других зависимостей от Pushwoosh, поэтому он остается небольшим в процессе расширения. Добавьте его в цель расширения контента (content extension target), а не в цель приложения (app target).
Swift Package Manager

CocoaPods
target 'StoriesContentExtension' do use_frameworks!
pod 'PushwooshXCFramework/PushwooshNotificationUI'end3. Создайте подкласс для view controller’а историй
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. Отправьте push-уведомление с историями
Anchor link toОтправьте уведомление, категория которого — PW_STORIES, а пользовательские данные (custom data) содержат блок 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Переопределите свойства в вашем подклассе, чтобы настроить опыт взаимодействия. У всех свойств есть разумные значения по умолчанию.
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 | Плавный переход между страницами вместо резкой смены. При включенном режиме «Уменьшение движения» используется мгновенная смена. |
loopsAfterLastPage | false | Начинать с первой страницы после завершения последней. |
appGroupIdentifier | nil | App Group, используемая совместно с Notification Service Extension для предварительного кэширования медиа (см. ниже). |
Вы также можете переопределить showDefaultContent(for:), чтобы настроить резервный вариант, который будет показан, если полезная нагрузка отсутствует или некорректна (по умолчанию показывается тело уведомления).
Предварительное кэширование медиа
Anchor link toДля мгновенного отображения первого кадра в офлайн-режиме используйте общую App Group для вашего Content Extension и Notification Service Extension. Переопределите appGroupIdentifier в контроллере историй, а затем предварительно загрузите медиа из didReceive(_:withContentHandler:) вашего Service Extension:
import PushwooshNotificationUI
PushwooshStoriesMediaPrefetcher.prefetch( userInfo: request.content.userInfo, appGroupIdentifier: "group.com.example.app") { contentHandler(bestAttemptContent)}Включите возможность App Groups для обоих расширений с одинаковым идентификатором группы и отправьте mutable-content: 1, чтобы Service Extension запустился. Без 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, передаваемый в колбэки, предоставляет доступ к imageURL, duration, link, buttonTitle, title и subtitle страницы.
Навигация
Anchor link toНажмите на правую треть экрана, чтобы перейти к следующей странице, и на левую треть, чтобы вернуться назад. Горизонтальный свайп намеренно не используется, так как он конфликтует с системным жестом закрытия уведомления. Нажатие на кнопку страницы открывает ее deep link и закрывает уведомление.