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

iOS SDK reference

Версия: ShopStoryPlayerSDK 0.2.0-preview.2. Описание сверено с исходниками immutable tag. Установка и собираемый starter: native iOS. Совместимость и приёмка: версии и выпуск.

Конфигурация​

try ShopStorySDK.shared.configure(
applicationId: applicationId,
hostAppVersion: hostAppVersion,
isEnabled: true,
followMePlayerEnabled: true,
manualMinimizeEnabled: true
)
ПараметрТип / defaultНазначение
applicationIdString, обязательныйВыданный проект. SDK обрезает пробелы и приводит значение к нижнему регистру
hostAppVersionString? = nilВерсия приложения для диагностики
isEnabledBool = trueЛокальное разрешение SDK UI; remote policy может дополнительно его запретить
followMePlayerEnabledBool = trueЛокальное разрешение Follow Me
manualMinimizeEnabledBool = trueРазрешение ручного скрытия floating player к краю

Некорректный applicationId вызывает ShopStorySDKConfigurationError.invalidApplicationId и отключает SDK surfaces без завершения host app. Успешный configure начинает cache-aware обновление policy; он не означает готовность видео. Обновление policy, её cache и транспорт принадлежат SDK.

Product lookup​

let request: ShopStoryProductStreamStateRequest =
ShopStorySDK.shared.loadProductStreamState(
feedProductId: feedProductId
) { result in
// Result<ShopStoryProductStreamState, ShopStoryProductStreamStateError>
handleProductState(result)
}

// При уходе с PDP или замене товара:
request.cancel()

handleProductState — функция host app. Completion доставляется асинхронно на main actor. Храните request для текущего товара. cancel() отменяет незавершённый запрос и подавляет его completion; ожидать callback отмены не нужно.

РезультатДействие host app
.success(.active(entrypoint))Показать SDK entrypoint для текущего товара
.success(.unavailable(reason))Убрать SDK-блок без пустого placeholder
.failure(error)Убрать SDK-блок, сохранить PDP рабочей и записать typed error в диагностику

ShopStoryProductStreamUnavailableReason содержит noActiveStream, scheduled, archived, disabled, notEligible. Это варианты типа SDK. Опубликованный HTTP-контракт сейчас возвращает no_active_stream для недоступного видео; наличие остальных enum cases не обещает их доступность в Public API.

Entrypoint​

ShopStoryProductDetailEntrypoint возвращается SDK; приложение не собирает его из URL.

ПолеТипНазначение
streamIdStringИдентификатор эфира или записи
feedProductIdStringТоварный ID клиента, с сохранением ведущих нулей
productIdString?Внутренний ID ShopStory для диагностики
previewURL, posterURLURL?Медиа preview и poster, если доступны
startTimeInt?Стартовая позиция из состояния товара
mediaOrientationShopStoryMediaOrientationportrait, landscape, square, unknown

Адрес player внутри entrypoint не является публичным полем. Передавайте объект в coordinator.load(entrypoint:) целиком.

Ошибки lookup​

ShopStoryProductStreamStateErrorПроверка
sdkNotConfiguredconfigure успешно выполнен до lookup
runtimePolicyDisabledПроект и текущая runtime policy разрешают SDK UI
invalidProductIdentifierПередан непустой строковый feedProductId из фида
networkFailureДоступна сеть; повтор разрешён только пока товар остаётся текущим
invalidResponse, decodingFailedВерсия SDK соответствует контракту; приложите очищенную диагностику в поддержку
requestSupersededКонфигурация SDK изменилась до завершения lookup; используйте актуальный запрос

Не заменяйте техническую ошибку утверждением «у товара нет видео»: для этого есть успешный .unavailable.

Player coordinator​

ShopStoryPlayerCoordinator и его delegate работают на @MainActor. Integration root удерживает один coordinator на активную playback session. delegate — weak; host app удерживает его отдельно.

APIПоведение
init(delegate:)Создаёт coordinator; delegate необязателен
playerView: UIViewOpaque native view. Внутренний WebView не передаётся host app
attach(to: UIView)Монтирует player view в контейнер с constraints по его границам
load(entrypoint:)Загружает разрешённый товарный entrypoint
load(trustedPlayerURL:)Для native списка эфиров: только HTTPS URL, полученный напрямую из ShopStory API
detach()Снимает view с контейнера без завершения playback session
pausePlayback(reason:)Приостанавливает media; причины: appBackgrounded, hostRequested, surfaceBlocked, teardown
resumePlayback()Возобновляет media с учётом текущего состояния coordinator
teardown()Завершает session и освобождает player. Для нового воспроизведения создайте новый coordinator

При full-screen → PDP → Follow Me переносите тот же playerView через detach / attach. Повторный load не нужен. Полный пример owner: Full-screen player и Follow Me.

Product actions​

Delegate получает ShopStoryProductAction через shopStoryPlayerCoordinator(_:didReceive:). kind — openProduct или addProduct. payload содержит необязательные name, feedProductId, feedProductGroupId, url, vendorCode, source.

Проверьте payload.feedProductId и разрешите его через native catalogue. url — справочное поле, оно не должно управлять native navigation. В delegate нет completion: действие передаётся в одну сторону. Приложение самостоятельно открывает PDP или выполняет Cart API и показывает подтверждённый результат в своём UI.

Lifecycle diagnostics​

Delegate получает ShopStoryPlayerLifecycleEvent через shopStoryPlayerCoordinator(_:didUpdate:).

EventСмысл
pageLoadedЗавершилась навигация страницы player. Это не подтверждение первого video frame
closeRequestedPlayer запросил закрытие; host завершает session
backgroundPaused, foregroundRestoredИзменился app lifecycle; перед показом Follow Me снова проверьте surface и policy
navigationFailed(String)Ошибка загрузки; строка предназначена для очищенной диагностики
navigationBlocked(String), bridgeMessageBlocked(String)SDK отклонил navigation или bridge message; не обходите проверку
runtimePolicyDisabledSDK UI отключён runtime policy; освободите host container
productActionDecodeFailed(kind)Product action не удалось разобрать; не выполняйте commerce-действие

Состояния coordinator не заменяют commerce events. Публичного native события «оплаченный заказ» в этом контракте нет.

Surface и floating player​

После изменения видимого экрана вызывайте setCurrentSurface(_:). Доступные стандартные значения: home, liveList, catalog, search, productDetail, cart, checkout, payment, auth, profile, unknown. Для дополнительной поверхности используйте ShopStorySurface(rawValue:) и согласованную policy. Неизвестный экран не следует считать разрешённым.

shouldOpenPlayer() проверяет разрешение player UI. shouldShowFollowMePlayer(on:) проверяет заданную или текущую поверхность. Геометрию возвращают followMeGeometry(for:) и overloads с mediaOrientation.

После configure создайте и удерживайте makeFloatingPlayerController(). Его show(using:) применяет геометрию; hide(to:) скрывает к краю; restore() восстанавливает; suppress() убирает UI по policy; close() закрывает floating UI. Закрытие controller не заменяет coordinator.teardown() при завершении session.

SwiftUI host может использовать ShopStoryProductDetailPreview, ShopStoryProductDetailEntrypointView и ShopStoryManagedFloatingPlayerContainer. Containers и route owner остаются частью приложения; ориентируйтесь на sample выбранной версии.

Обновление с preview.1​

В товарной интеграции замените старый load(playerURL:) передачей entrypoint целиком:

coordinator.load(entrypoint: entrypoint)

Для списка эфиров старый load(playerURL:) заменён на load(trustedPlayerURL:). Не передавайте в него URL из product action или пользовательского ввода. Затем обновите lockfile и повторите приёмку.

Разбор проблем: диагностика Mobile SDK. Flutter reference описывает отдельный adapter contract.