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

Flutter SDK reference

Пара: shopstory_player_flutter 0.2.0-preview.3 и native ShopStoryPlayerSDK 0.2.0-preview.2. Описание сверено с immutable tags. Установка, toolchain и starter: Flutter на iOS. Android и Flutter Web в этот adapter contract не входят.

Entry point и конфигурация​

Используйте ShopStoryPlayerFlutter.instance. Перед конфигурацией проверяйте isSupportedPlatform: он возвращает true только на iOS вне Web. На других платформах методы конфигурации и player завершаются UnsupportedError.

await ShopStoryPlayerFlutter.instance.configure(
applicationId: applicationId,
hostAppVersion: hostAppVersion,
isEnabled: true,
followMePlayerEnabled: true,
manualMinimizeEnabled: true,
);

applicationId обязателен. hostAppVersion — необязательная строка; три boolean-параметра по умолчанию равны true. Это локальные разрешения; remote policy может дополнительно запретить SDK UI. Успешное завершение configure не подтверждает доступность видео. Policy, её cache и refresh принадлежат native SDK.

Публичные методы​

APIРезультатНазначение
configure(...)Future<void>Конфигурация native SDK
setCurrentSurface(surface)Future<void>Передача реально видимого commerce-экрана
showProductDetailPreview(feedProductId: ...)Future<ShopStoryProductStreamResult>Низкоуровневый запрос и показ preview; заменяет предыдущую preview session
clearProductDetailPreview()Future<void>Снятие активного preview
closePlayer()Future<void>Закрытие SDK player surfaces
registerProductActionHandlers(...)ShopStoryProductActionHandlerRegistrationРегистрация host callbacks для product actions
lifecycleEventsStream<ShopStoryLifecycleEvent>Поток локальной диагностики

Для обычной PDP используйте ShopStoryProductDetailScope: он управляет preview session за widget. Не дублируйте его запрос вызовом showProductDetailPreview для того же экрана.

ShopStoryProductDetailScope​

ShopStoryProductDetailScope(
feedProductId: product.feedProductId,
onResult: handlePreviewResult,
onError: reportPreviewError,
child: ProductDetailView(product: product),
)

ProductDetailView, handlePreviewResult и reportPreviewError принадлежат приложению. feedProductId и child обязательны; player, onResult и onError необязательны.

Scope запрашивает preview после первого frame, обновляет его при смене товара и снимает свою session при dispose. Освобождение старого scope не должно снимать preview нового. Scope не вызывает setCurrentSurface: видимый route по-прежнему сообщает host app.

Результаты preview​

ТипПолеДействие приложения
ShopStoryProductStreamActivestreamIdСохранить ID для диагностики; SDK показывает preview
ShopStoryProductStreamUnavailablereasonОставить PDP без SDK placeholder
ShopStoryProductStreamFailureerrorСохранить рабочую PDP и записать техническую причину

Unavailable reasons: noActiveStream, scheduled, archived, disabled, notEligible. Эти варианты существуют в SDK для разбора состояния; опубликованный HTTP-контракт сейчас возвращает no_active_stream для недоступного видео.

Technical errors: sdkNotConfigured, runtimePolicyDisabled, invalidProductIdentifier, networkFailure, invalidResponse, decodingFailed, requestSuperseded, presentationUnavailable. Первые семь соответствуют native lookup errors. presentationUnavailable означает, что native UI не удалось представить; проверьте текущий экран и lifecycle приложения.

Типизированный ShopStoryProductStreamFailure приходит через результат. Ошибки вызова или platform channel обрабатываются через onError; без этого callback scope использует FlutterError.reportError.

ShopStorySurface содержит home, liveList, catalog, search, productDetail, cart, checkout, payment, auth, profile, unknown.

ShopStoryNavigatorObserver(surfaceForRoute: ...) поддерживает один root Navigator. Callback получает PageRoute<dynamic> и возвращает ShopStorySurface?:

  • обычный экран — его surface;
  • неизвестный экран — ShopStorySurface.unknown;
  • page-style overlay, сохраняющий нижележащий commerce-экран, — null.

Observer обрабатывает push, pop, replace и remove, пропускает pageless overlays и подавляет повтор одинаковой surface. Необязательный onError(Object, StackTrace) получает ошибки mapping и channel; без него используется FlutterError.

Для declarative router, tabs и nested navigators вызывайте setCurrentSurface из существующего owner видимого состояния. Observer не определяет бизнес-смысл маршрутов за приложение.

Product actions​

ShopStoryProductAction содержит kind и payload. Kind: openProduct, addProduct, unknown. Payload содержит необязательные name, feedProductId, feedProductGroupId, url, vendorCode, source. Строковый feedProductId должен совпадать с ID в каталоге и фиде; url не управляет native routing.

Регистрация принимает onOpenProduct и onAddProduct. Нужен хотя бы один callback; иначе возникает ArgumentError. Callback имеет тип FutureOr<ShopStoryProductActionResult> Function(ShopStoryProductAction).

Результат callbackКогда возвращать
ShopStoryProductActionOpenedProduct()Router принял переход на native PDP; adapter запускает handoff к Follow Me
ShopStoryProductActionSucceeded()Host подтвердил действие без открытия PDP, например успешную cart operation
ShopStoryProductActionFailed(reason)Действие отклонено или не выполнено

Не ожидайте завершения Navigator.push: его Future обычно завершается после возврата с открытой страницы. Результат OpenedProduct возвращается после принятого перехода.

Failure reasons: invalidPayload, unsupportedAction, unavailable, rejected, operationFailed. Неизвестное действие или отсутствие нужного handler не разрешает переход и изменение корзины. У onAddProduct нет автоматического fallback на onOpenProduct.

Root integration owner удерживает регистрацию и вызывает dispose() при освобождении. Новая регистрация заменяет callbacks для будущих действий; уже начавшееся действие использует прежний callback.

Timeout и результат корзины​

iOS plugin ограничивает срок ожидания product action 30 секундами. Истечение этого срока не отменяет cart operation магазина. При потерянном ответе сначала выясните её результат по operation ID; не повторяйте запись только из-за timeout.

Результат Flutter callback управляет host-side lifecycle adapter. Он не передаётся embedded player как подтверждение корзины. Merchant UI и аналитика магазина используют подтверждённый ответ Cart API независимо от состояния кнопки player.

Lifecycle diagnostics​

final subscription = ShopStoryPlayerFlutter.instance.lifecycleEvents.listen(
(event) => reportShopStoryDiagnostic(event.kind, event.rawKind),
);

// При освобождении integration owner:
await subscription.cancel();

reportShopStoryDiagnostic — функция приложения. kind содержит типизированную категорию, rawKind сохраняет исходное имя, включая неизвестное новой версии. Необязательный message предназначен только для согласованной диагностики; не показывайте его пользователю и не отправляйте целиком в стороннюю аналитику.

ГруппаПримеры ShopStoryLifecycleEventKindРеакция
PlayerplayerOpened, playerRestored, playerClosed, pageLoadedНаблюдать lifecycle; pageLoaded не подтверждает video frame
BackgroundbackgroundPaused, foregroundRestoredСверить видимую surface и текущую policy
Follow MefollowMeShown, followMeHidden, followMeRestored, followMeSuppressed, followMeUnavailableПроверить route, контейнер и разрешение policy
PreviewproductPreviewShown, productPreviewHidden, presentationUnavailableПроверить актуальный товар и экран
ОшибкиnavigationFailed, playerLoadFailed, navigationBlocked, playerLoadBlocked, bridgeMessageBlocked, runtimePolicyDisabledСохранить очищенную причину; не обходить origin и bridge checks
Product actionproductActionSuccess, productActionFailure, productActionTimeout, productActionIgnored, productActionDecodeFailed, callbackErrorПроверить handler и подтверждённый результат магазина

Lifecycle diagnostics не заменяют события аналитики. Для несовместимого bridge adapter может вызвать ShopStoryBridgeContractException; проверьте согласованную пару Flutter/native tags и чистую сборку.

Migration notes​

  • preview.2 → preview.3: root Navigator может использовать ShopStoryNavigatorObserver вместо собственного observer. Сохраните route-to-surface mapping; для tabs и nested navigation остаётся явный setCurrentSurface.
  • preview.1 → preview.2: обновите обе зависимости до соответствующих exact tags и lockfiles. Native entrypoint перестал раскрывать player URL; Dart API этой пары не изменился.

После обновления выполните приёмку перед выпуском. При проблеме используйте диагностику Mobile SDK.