Перейти к основному содержимому

Mobile SDK для native iOS

Эта инструкция относится к ShopStoryPlayerSDK 0.2.0-preview.2. Требуются iOS 15+, Xcode 16+ и read-only доступ к пакету. Для другой версии используйте её README и migration notes: версии и выпуск.

Установить SDK​

В Xcode откройте File → Add Package Dependencies, вставьте URL из выданного доступа и выберите Exact Version: 0.2.0-preview.2. Добавьте product ShopStoryPlayerSDK в app target. Сохраните Package.resolved в репозитории приложения.

Если проект использует CocoaPods, возьмите Podfile из инструкции к этой версии пакета. Не добавляйте токен в URL, Package.swift или Podfile.

До запуска получите applicationId, один feedProductId с опубликованным VOD и один ID без видео. SDK использует реальные данные проекта; произвольные значения не создают demo-каталог.

Запустить starter​

Скачать iOS starter. В архиве — app target, экран товара и SDK player. README описывает размещение приватного пакета рядом с проектом и запуск без клиентских данных.

После настройки откройте тестовый товар. Для активного видео должен появиться SDK entrypoint; нажатие открывает player. Для товара без видео entrypoint отсутствует. Ошибка SDK сохраняет экран товара рабочим.

Starter проверяет первое воспроизведение и передачу product action приложению. Корзину он не изменяет. Перенос активной сессии в Follow Me подключается отдельно по примеру ниже.

Configure и video lookup​

import ShopStoryPlayerSDK

private let shopStory = ShopStorySDK.shared
@MainActor
private var shopStoryConfigured = false
@MainActor
private var productStateRequest: ShopStoryProductStreamStateRequest?

@MainActor
func configureShopStory() {
do {
try shopStory.configure(
applicationId: applicationId,
hostAppVersion: Bundle.main.object(
forInfoDictionaryKey: "CFBundleShortVersionString"
) as? String
)
shopStoryConfigured = true
} catch {
shopStoryConfigured = false
hideShopStoryEntrypoint()
reportIntegrationError(error)
}
}

@MainActor
func clearShopStoryProduct() {
productStateRequest?.cancel()
productStateRequest = nil
hideShopStoryEntrypoint()
}

@MainActor
func loadShopStory(for product: Product) {
clearShopStoryProduct()
guard shopStoryConfigured else { return }

shopStory.setCurrentSurface(.productDetail)
productStateRequest = shopStory.loadProductStreamState(
feedProductId: product.feedProductId
) { result in
switch result {
case let .success(.active(entrypoint)):
showShopStoryEntrypoint(entrypoint)
case .success(.unavailable):
hideShopStoryEntrypoint()
case let .failure(error):
hideShopStoryEntrypoint()
reportIntegrationError(error)
}
}
}

Вызывайте конфигурацию один раз при запуске приложения. Ошибка оставляет ShopStory UI скрытым и не прерывает запуск приложения. При смене товара сначала отмените запрос и уберите прежний entrypoint, затем запрашивайте видео нового товара. При закрытии PDP вызовите clearShopStoryProduct(). .unavailable означает отсутствие доступного видео; .failure(error) передавайте в диагностический logger приложения. Полученный entrypoint передавайте в coordinator целиком; не собирайте player URL вручную.

Full-screen player и Follow Me​

Lookup из предыдущего примера только получает entrypoint. Для воспроизведения host app выполняет ещё шесть действий:

  1. Root integration owner создаёт и удерживает одну playback session, один ShopStoryPlayerCoordinator и floating-player controller.
  2. Full-screen container вызывает coordinator.attach(to:), затем coordinator.load(entrypoint:).
  3. Coordinator delegate принимает типизированные product actions и lifecycle events.
  4. При переходе из player в native PDP host отсоединяет player view без teardown, открывает PDP и монтирует ту же сессию в follow-me container.
  5. После каждого route transition host вызывает setCurrentSurface и применяет shouldShowFollowMePlayer() к активной сессии: показывает или скрывает container и синхронизирует playback state.
  6. teardown() вызывается при закрытии, завершении сессии или remote disable. Product handoff между full-screen и follow-me не завершает сессию.

Создавайте ShopStoryPlaybackOwner после успешного configure, когда начинается активная playback session. Root integration owner приложения удерживает этот объект до stop().

player-owner.swift
import ShopStoryPlayerSDK
import UIKit

@MainActor
final class ShopStoryPlaybackOwner: ShopStoryPlayerCoordinatorDelegate {
private let sdk = ShopStorySDK.shared
private let floatingController = ShopStorySDK.shared.makeFloatingPlayerController()
private(set) lazy var coordinator = ShopStoryPlayerCoordinator(delegate: self)

func start(entrypoint: ShopStoryProductDetailEntrypoint, in container: UIView) {
coordinator.attach(to: container)
coordinator.load(entrypoint: entrypoint)
}

func moveToFollowMe(
in container: UIView,
surface: ShopStorySurface,
mediaOrientation: ShopStoryMediaOrientation
) {
coordinator.detach()
coordinator.attach(to: container)
reconcile(surface: surface, mediaOrientation: mediaOrientation)
}

func shopStoryPlayerCoordinator(
_ coordinator: ShopStoryPlayerCoordinator,
didReceive action: ShopStoryProductAction
) {
guard let feedProductId = action.payload.feedProductId,
!feedProductId.isEmpty else {
reportInvalidProductAction(action)
return
}

handleProductAction(action.kind, feedProductId: feedProductId)
}

func reconcile(
surface: ShopStorySurface,
mediaOrientation: ShopStoryMediaOrientation
) {
sdk.setCurrentSurface(surface)

if sdk.shouldShowFollowMePlayer() {
let geometry = sdk.followMeGeometry(mediaOrientation: mediaOrientation)
floatingController.show(using: geometry)
coordinator.resumePlayback()
} else {
coordinator.pausePlayback(reason: .surfaceBlocked)
floatingController.suppress()
}
}

func shopStoryPlayerCoordinator(
_ coordinator: ShopStoryPlayerCoordinator,
didUpdate event: ShopStoryPlayerLifecycleEvent
) {
handlePlayerLifecycle(event)
}

func stop() {
floatingController.close()
coordinator.teardown()
}
}

handleProductAction, handlePlayerLifecycle и нативные контейнеры принадлежат приложению. После принятого перехода на PDP приложение монтирует follow-me container и вызывает moveToFollowMe. В этот метод передаётся контейнер, в котором SDK-компонент размещает coordinator.playerView. При переносе не вызывайте load или teardown: используется тот же coordinator и его player view. Полная схема контейнеров и их освобождения входит в руководство к поставленной версии SDK.

Следующий шаг​

Подключите lifecycle и product actions, затем аналитику приложения.