@bambuser/ react-native-commerce-sdk (英语)
反应原生包装为班布瑟商号SDK. 在您的iOS和Android React Industrial Apps中嵌入了视频直播购物体验,其中包含一个单一的宣告组件.
该套件包装了Bambuse的原生iOS和Android SDKs(分别为3.3.0和3.7.0版本),并通过回放组件外加必须的 ref-based API来曝光. 您的应用程序中不需要本地代码 .
特征概览
| 特性 | iOS系统 | 机器人 |
|---|---|---|
| 现场视频播放 | ✅ | ✅ |
| 播放 / 暂停 / 哑声 / 解密 | ✅ | ✅ |
invoke 编号 : notify (调用玩家回复调用) | ✅ | ✅ |
| 图片插图 | ✅ | ✅ |
玩家状态事件( E)onStatus, (中文(简体) ), onProgress, (中文(简体) ), onError(中文(简体) ) | ✅ | ✅ |
自定义事件( E)onEvent(中文(简体) ) | ✅ | ✅ |
缩略图自制回调( U)onThumbnailTapped(中文(简体) ) | ✅ | – 说吧 – |
| 安全区边缘控制 | ✅ | ✅ |
视频缩放模式( E)videoScaleMode(中文(简体) ) | ✅ | ✅ |
分析跟踪BambuserSDK.track(中文(简体) ) | ✅ | ✅ |
可商店视频回放( E)mode="shoppable"(中文(简体) ) | ✅ | ✅ |
可商店收藏物查询( U)fetchShoppableCollection(中文(简体) ) | ✅ | ✅ |
可储存的收集元数据(fetchShoppableCollectionMetadata(中文(简体) ) | ✅ | ✅ |
预览/全经验模式开关( E)setMode(中文(简体) ) | ✅ | ✅ |
重置可购买播放器( N)resetPlayer(中文(简体) ) | ✅ | – 说吧 – |
查找( E)seek(中文(简体) ) | ✅ | ✅ |
所需资源
- 原生反应 : >= 0.72
- iOS: (英语) 页:1
- 机器人:
minSdkVersion >= 26
安装
npm install @bambuser/react-native-commerce-sdk
# or
yarn add @bambuser/react-native-commerce-sdk
iOS系统
cd ios && pod install
Bambuerser Commerce SDK xcframework在包内销售——不需要额外的源/回取配置.
添加 -ObjC 对你的应用目标 其他链接标记 (构建设置-链接). 没有它,SDK内部的目标-C类别在链接时间被剥去,玩家在运行时间被崩溃.
机器人
Android SDK发布给由班布瑟主持Maven Repo. 把它加入你的项目 android/settings.gradle数字 :
dependencyResolutionManagement {
repositories {
// ... existing repos
maven { url "https://repo.repsy.io/mvn/bambuser/bambuser-commerce-sdk" }
}
}
SDK内部使用Jetpack Compose. 将 Cotlin 插件添加到您的根中 android/build.gradle数字 :
plugins {
id "org.jetbrains.kotlin.plugin.compose" version "2.1.20" apply false
}
弹出 minSdkVersion 改为 26岁或以上 在你身边 android/build.gradle。 。 。 .
图片内插画( Android)
机器人用途 活动层面 Pi. 为了启用它,添加 supportsPictureInPicture 到您的主机活动 AndroidManifest.xml数字 :
<activity
android:name=".MainActivity"
android:supportsPictureInPicture="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
... />
当活动进入PiP时 整个活动 收缩(不只是视频). 隐藏非视频 UI 当 onPiPStateChanged 火灾 'started' 并恢复它上 'stopped'。 。 。 .
快速启动
import { useRef } from 'react';
import {
BambuserVideoView,
type BambuserVideoViewRef,
} from '@bambuser/react-native-commerce-sdk';
export function LiveVideoScreen() {
const playerRef = useRef<BambuserVideoViewRef>(null);
return (
<BambuserVideoView
ref={playerRef}
style={{ flex: 1 }}
id="your-video-id"
server="US"
configuration={{
autoplay: true,
currency: 'USD',
locale: 'en-US',
}}
onStatus={(e) => console.log('state:', e.nativeEvent.state)}
onError={(e) => console.error(e.nativeEvent.message)}
/>
);
}
组件 API
<BambuserVideoView />
道具
| Prop | 类型 | 默认 | 平台 | 说明 |
|---|---|---|---|---|
id | string | 所需经费 | 两者 | 视频标识符. |
server | 'US' | 'EU' | 'US' | 两者 | 组织服务器区域. |
mode | 'live' | 'shoppable' | 'live' | 两者 | 视频模式. 使用 'shoppable' 用于点播可购买的视频。 见 可商店视频。 。 。 . |
events | string[] | ['*'] | 两者 | 要订阅的自定义事件 。 更改此道具将创建一个新玩家 . |
configuration | Record<string, any> | {} | 两者 | 玩家配置. 更改此道具会创造出一个新的玩家——回忆. |
ignoredSafeAreaEdges | SafeAreaEdge[] | [] | 两者 | 当玩家计算安全区域粘贴时忽略边框 . mode="live" 仅;可购买的玩家从未在任一平台上收到过安全区域贴上,因为它们通常被嵌入而非全屏. |
videoScaleMode | 'fit' | 'fill' | 'fit' | 两者 | 视频如何在玩家视野内缩放. 'fit' 保持整个视频可见, 'fill' 覆盖风景和收成 溢出轴。 纵宽比总是被保留下来,而网页覆盖总是填满了视图. 更改此道具将创建一个新玩家 . |
onEvent | (e) => void | —— 说 | 两者 | 玩家发布了自定义事件 。 见 有效载荷。 。 。 . |
onStatus | (e) => void | —— 说 | 两者 | 播放状态已更改 . |
onProgress | (e) => void | —— 说 | 两者 | 定期提供最新进展情况. |
onError | (e) => void | —— 说 | 两者 | 发生了错误 . |
onPiPStateChanged | (e) => void | —— 说 | 两者 | 图片入相状态已改变. |
onThumbnailTapped | (e) => void | —— 说 | 仅iOS | 用户监听了视频缩略图(前作). 回放自动从自来水龙头开始,匹配Android的自来水龙头到玩;回放是信息. |
⚠️ 纪念
configuration。通过每个参数上的新对象字节重建玩家。 使用useMemo,模块级常数,或状态稳定对象.
查找方法
const playerRef = useRef<BambuserVideoViewRef>(null);
| 方法 | 签署 | 页:1 |
|---|---|---|
play() | () => void | 继续播放. |
pause() | () => void | 暂停播放. |
mute() | () => void | 哑声. |
unMute() | () => void | 解密相声. |
seek(seconds) | (number) => void | 寻求 seconds。对现场广播没有影响;只能购买/存档. |
setMode(mode) | (BambuserShoppableMode) => Promise<void> | 在两者之间切换可选播放器 'preview' 财务报告和审定财务报表 'fullExperience'。当模式变化完成时决定;如果失败或玩家尚未准备好,则拒绝. |
resetPlayer() | () => void | 重置可购物播放器进行预览,倒放到0,再显示缩略图. 仅iOS ——Android是一无所取(重置). |
startPiP() | () => void | 输入 Picture . |
stopPiP() | () => void | 退出相册. |
setPiPEnabled(enabled) | (boolean) => void | 启用/ 禁用 PiP 特性 。 默认为 true。 。 。 . |
invoke(fn, args) | (string, string) => Promise<any> | 调用玩家侧功能 。 见 玩家桥。 。 。 . |
notify(callbackKey, info) | (string, NotifyInfo) => void | 对召回事件的答复通过 onEvent。 。 。 . |
getCurrentPlayerState() | () => Promise<BambuserPlayerState> | 读取最后已知的玩家状态 . |
getNativeTag() | () => number | null | 地底原景标签. 逃生舱门——很少需要. |
cleanup() | () => void | 撕下玩家并释放出本土资源. 不可逆转 看到了吗 生命周期。 。 。 . |
BambuserSDK
对于不需要玩家视图的 SDK 级操作:分析跟踪和可商店收藏搜索.
import { BambuserSDK } from '@bambuser/react-native-commerce-sdk';
const sdk = new BambuserSDK({ server: 'US' });
await sdk.track('purchase', {
orderId: 'order-123',
total: 99.99,
currency: 'USD',
});
| 方法 | 签署 | 说明 |
|---|---|---|
track | (event: string, data: Record<string, any>) => Promise<Record<string, any> | null> | 将跟踪数据发送给班布瑟分析师. 决定反应有效载荷,或 null。 。 。 . |
fetchShoppableCollection | (request: BambuserShoppableCollectionRequest) => Promise<BambuserShoppableCollectionPage> | 从播放列表, SKU 或群集中获取可购物视频ID的页面 。 见 可商店视频。 。 。 . |
fetchShoppableCollectionMetadata | (request: BambuserShoppableCollectionMetadataRequest) => Promise<BambuserShoppableCollectionMetadataPage> | 获取可购买视频页面的元数据(标题、海报 URL、持续时间、音频旗帜)。 不创建玩家; 在安装任何玩家前提供轻量级缩略图的理想 . |
clearShoppableCache | () => void | 释放当前未挂载的预选可购玩家 。 离开可购物屏幕时打电话 在没有本地缓存的平台上禁用 . |
可商店视频
可商店(点播)视频被看成是收藏品,然后由ID提供. 流动是:
- 打电话
sdk.fetchShoppableCollection(...)获取页面videoIds在 iOS 上,这也创建了这些ID的后面的玩家,所以它必须在渲染前运行. - 将每个ID显示为
<BambuserVideoView mode="shoppable" id={...} />。 。 。 . - 可选择在预览和充分经验之间切换玩家
setMode,或重设为resetPlayer。 。 。 . - 可选调用
sdk.clearShoppableCache()完全离开可购买的内容。 在 iOS 上,它会摧毁被获取的ID的后方的玩家,所以只有在重新获取后才能再次完成;在下一次获取时,缓存也会被自动冲出. 不准对Android开枪.
身份证是上面的符文:放入状态,并制作每个符文。 同一代码在两个平台上都有效;iOS附加了玩家已经创建的取取,而Android在挂载上建取.
需要真实的视频数据,真实的视频标识,标题,持续时间,海报URL? 就这样 fetchShoppableCollectionMetadata 用于; 它返回稳定的视频标识并显示字段,而不创建任何玩家.
⚠️ 处理
videoIds作为临时手柄,不是稳定的标识符. 两个平台返回同一字段后面的不同事物:在Android上,它们是真实的视频ID,在iOS上,它们识别玩家实例刚刚创建的取来. 实际上:
- 总是在渲染前获取, 并且只从您的最新获取中获取 ID 。 新获取或
clearShoppableCache()使旧的无效( 在 iOS 上, stale id 失败通过onError) (中文(简体) ).- 别把身份证藏起来,或送去任何地方;它们不会稳定地穿过取来.
- 别把他们和身份证比起来
fetchShoppableCollectionMetadata在iOS上,它们不会匹配。 两人都按同顺序调回所收相册,因此按位置对相册.
对于不创建任何播放器的轻量级预览( 标题、 持续时间、 海报 URL) <Image> 缩略图,使用 fetchShoppableCollectionMetadata 具有相同的播放列表/SKU/组源.
一个收藏来自 播放列表 (单位:千美元)orgId + 键 componentId页:1 斯库 (单位:千美元)orgId + 键 sku),或 a 组 (单位:千美元)orgId + 键 groupId:
import { useEffect, useMemo, useRef, useState } from 'react';
import {
BambuserSDK,
BambuserVideoView,
type BambuserVideoViewRef,
} from '@bambuser/react-native-commerce-sdk';
// Memoize — must match the view's `configuration` prop (iOS caches players by config).
// Note: shoppable players never autoplay; playback starts on tap or via play().
const SHOPPABLE_CONFIG = {
thumbnail: { enabled: true },
currency: 'USD',
locale: 'en-US',
};
export function ShoppableScreen() {
const sdk = useMemo(() => new BambuserSDK({ server: 'US' }), []);
const [videoIds, setVideoIds] = useState<string[]>([]);
// One ref per video id; a single shared ref would always point at the
// last-mounted player.
const playerRefs = useRef<Record<string, BambuserVideoViewRef | null>>({});
useEffect(() => {
sdk
.fetchShoppableCollection({
source: 'playlist',
orgId: 'your-org-id',
componentId: 'your-component-id',
page: 1,
pageSize: 15,
configuration: SHOPPABLE_CONFIG,
})
.then((res) => setVideoIds(res.videoIds))
.catch((e) => console.error(e));
// Release prefetched players when leaving the screen. Only clear when
// no shoppable views are mounted; a view whose cached player was cleared
// has nothing to attach to.
return () => sdk.clearShoppableCache();
}, [sdk]);
return (
<>
{videoIds.map((id) => (
<BambuserVideoView
key={id}
ref={(r) => {
playerRefs.current[id] = r;
}}
mode="shoppable"
id={id}
server="US"
style={{ flex: 1 }}
configuration={SHOPPABLE_CONFIG}
/>
))}
</>
);
}
SKU-和以组为基础的集合使用同一个调用不同来源:
await sdk.fetchShoppableCollection({
source: 'sku',
orgId: 'your-org-id',
sku: 'your-sku',
configuration: SHOPPABLE_CONFIG,
});
await sdk.fetchShoppableCollection({
source: 'group',
orgId: 'your-org-id',
groupId: 'your-group-id',
configuration: SHOPPABLE_CONFIG,
});
请求 (单位:千美元)BambuserShoppableCollectionRequest:
| 外地 | 类型 | 默认 | 页:1 |
|---|---|---|---|
source | 'playlist' | 'sku' | 'group' | 所需经费 | 收藏类型. |
orgId | string | 所需经费 | 组织标识. |
componentId | string | 所需经费 (游戏列表) | 播放列表组件 ID. 仅播放列表来源 . |
sku | string | 所需经费 (须弥 | 产品SKU. 只有SKU来源. |
groupId | string | 所需经费 (组) | 影视集团ID. 仅限群源. |
page | number | 1 | 页面取取. |
pageSize | number | 15 | 每页项目. |
configuration | Record<string, any> | {} | 预选玩家配置 。 一定和风景相符 configuration pro(iOS缓存玩家). |
videoScaleMode | 'fit' | 'fill' | 'fit' | 预选玩家的缩放模式 。 一定和风景相符 videoScaleMode pro(iOS缓存玩家). |
回应 (单位:千美元)BambuserShoppableCollectionPage:
{
videoIds: string[];
pagination: {
page: number | null;
pageSize: number | null;
total: number | null;
totalPages: number | null;
};
}
开始重播
可商店玩家从不自动玩. 当用户点击缩略图时, 或在程序上通过 play(). 呼吁 play() 在玩家报告前 'ready' 通过 onStatus 被忽略,所以触发一个初始 play() 从你的 onStatus 处理者.
预览 v 完整体验
可购物玩家开始预览 。 切换到完整的体验(和返回) setMode数字 :
await playerRef.current?.setMode('fullExperience');
await playerRef.current?.setMode('preview');
resetPlayer() 强迫玩家返回到预览,倒回到0,并重新显示缩略图. 这是 仅iOS;在Android上,重新挂载视图(例如更改) key)来重置.
有效载荷
所有召回器都收到一个合成事件,其有效载荷下有: e.nativeEvent。 。 。 .
onStatus
{ id: string; state: BambuserPlayerState }
state 这是:
'ready' • 妇女 'loading' • 妇女 'playing' • 妇女 'paused' • 妇女 'stopped' • 妇女 'completed' • 妇女 'error' • 妇女 'idle' • 妇女 'buffering'
onProgress
{ id: string; duration: number; currentTime: number }
两个值都是秒.
onError
{ id: string; message: string }
onEvent
{ id: string; type: string; data: any }
玩家发布的自定义事件( 添加到cart, 愿望列表, 共享等) 。 这个 data 形状取决于事件 type ——见: Bambuser 文档 整个活动目录.
平台差异 -
callbackKey数字 : 对于需要回应的事件,召回的关键生活于data.callbackKeyiOS和顶层(e.nativeEvent.callbackKey) 在Android上. 读两句:const callbackKey = e.nativeEvent.callbackKey ?? e.nativeEvent.data?.callbackKey;
平台差异-事件数据形状: 一些事件有效载荷将数据嵌入
data.event在iOS和Android的顶级。 例如,一个add-to-wishlistSKU已经到了data.event.sku(iOS)或 (iOS) 或 (iOS)data.sku(Android) (英语).
onPiPStateChanged
{ id: string; state: BambuserPiPState }
state 这是:
| 状态 | 当火 | 平台 |
|---|---|---|
'willStart' | 就在PiP开始前. | 两者 |
'started' | PiP活动. | 两者 |
'willStop' | 在 PiP 结束前右侧( 程序停止) . | 两者 |
'stopped' | PiP结束. | 两者 |
'restored' | 用户从 Pip 窗口中调取了"去全屏" . | 仅iOS |
onThumbnailTapped (iOS) (中文(简体) )
{ id: string }
玩家桥 : invoke 打开 notify
Bambuerser 播放器在网络视图内部运行 。 两个原始人桥 JS 玩家:
-
invoke(fn, args)——调用玩家的功能. 返回承诺。 使用此来驱动UI命令(例如显示/隐藏覆盖).await playerRef.current?.invoke('hideUI', ''); await playerRef.current?.invoke('showUI', ''); -
notify(callbackKey, info)——回应玩家通过浮出水面的回调事件onEvent编辑callbackKey源自事件有效载荷;info这是你的反应.function onEvent(e) { const { type, data } = e.nativeEvent; const callbackKey = e.nativeEvent.callbackKey ?? data?.callbackKey; if (type === 'add-to-wishlist' && callbackKey) { const sku = Platform.OS === 'ios' ? data?.event?.sku : data?.sku; // ... your wishlist logic playerRef.current?.notify(callbackKey, { success: true, sku }); } }
info 接受布尔、数字、字符串、平方对象/阵列,或 null已经看起来像联署材料的字符串({...}, (中文(简体) ), [...]数字, true编号 :false编号 :null)是经过的;其他的都是JSON编码的.
图片插图
PiP 默认启用 。 禁用每个组件 setPiPEnabled(false),或手动触发 startPiP() 编号 : stopPiP()。 。 。 .
playerRef.current?.startPiP();
playerRef.current?.stopPiP();
playerRef.current?.setPiPEnabled(false);
平台行为
-
iOS系统 - PiP是,我们.. 视图级别。只有视频浮出水面;其余的应用程序没有受到影响。 由SDK提供
pipController。 。 。 . -
机器人 - PiP是,我们.. 活动层面。整个主机活动会收缩到 PIP 窗口。 您应该隐藏非视频 UI 进入 Pip 时, 并在退出时恢复它 :
const [inPiP, setInPiP] = useState(false); <BambuserVideoView onPiPStateChanged={(e) => setInPiP(e.nativeEvent.state === 'started')} ... /> {!inPiP && <YourAppChrome />}
状态词汇
用于类型安全状态处理:
import type {
BambuserPlayerState,
BambuserPiPState,
} from '@bambuser/react-native-commerce-sdk';
function describe(state: BambuserPlayerState) {
switch (state) {
case 'playing': return 'Now playing';
case 'buffering': return 'Buffering…';
case 'paused': return 'Paused';
// ...
}
}
寿命周期和清理
玩家在组件卸载时自动释放本地资源. 你通常不需要打电话 cleanup() 你自己来.
打电话 cleanup() 明确:
- 你即将导航 并想立即释放资源,或
- 您想要在卸载前停止视频( 例如用户通过自定义手势备份) .
⚠️
cleanup()无可挽回的. 一旦呼叫,玩家就不见了. 要再次播放, 卸载并重载组件( 或更改)id以强迫重建.
useEffect(() => () => playerRef.current?.cleanup(), []);
配置参考
configuration 被传送到基本的SDK。 共同选项 :
configuration={{
autoplay: true,
currency: 'USD',
locale: 'en-US',
buttons: { dismiss: 'none' },
ui: { hideShareButton: true, hideEmojiOverlay: true },
}}
完整的支持密钥列表(每件事件,每个地块)请查看 Bambuser 现场视频文件。 。 。 .
类型
type SafeAreaEdge = 'all' | 'top' | 'bottom' | 'leading' | 'trailing';
type BambuserVideoScaleMode = 'fit' | 'fill';
type BambuserPlayerState =
| 'ready' | 'loading' | 'playing' | 'paused' | 'stopped'
| 'completed' | 'error' | 'idle' | 'buffering';
type BambuserPiPState =
| 'willStart' | 'willStop' | 'started' | 'stopped' | 'restored';
type BambuserSDKOptions = { server?: 'US' | 'EU' };
type BambuserShoppableMode = 'preview' | 'fullExperience';
type BambuserShoppablePlaylistSource = {
source: 'playlist';
orgId: string;
componentId: string;
};
type BambuserShoppableSkuSource = {
source: 'sku';
orgId: string;
sku: string;
};
type BambuserShoppableGroupSource = {
source: 'group';
orgId: string;
groupId: string;
};
type BambuserShoppableCollectionRequest =
(BambuserShoppablePlaylistSource | BambuserShoppableSkuSource | BambuserShoppableGroupSource) & {
page?: number;
pageSize?: number;
configuration?: Record<string, any>;
videoScaleMode?: BambuserVideoScaleMode;
};
type BambuserShoppableCollectionPage = {
videoIds: string[];
pagination: {
page: number | null;
pageSize: number | null;
total: number | null;
totalPages: number | null;
};
};
type BambuserShoppableCollectionMetadataRequest =
(BambuserShoppablePlaylistSource | BambuserShoppableSkuSource | BambuserShoppableGroupSource) & {
page?: number;
pageSize?: number;
};
type BambuserShoppableVideoMetadata = {
id: string;
title: string | null;
hasAudio: boolean | null;
preview: string | null; // poster image URL
length: number | null; // seconds
};
type BambuserShoppableCollectionMetadataPage = {
videos: BambuserShoppableVideoMetadata[];
pagination: BambuserShoppableCollectionPage['pagination'];
};
type NotifyInfo =
| boolean | number | string | null | undefined
| Record<string, any> | Array<any>;
解决问题
iOS - (英语) pod install 找不到框架 .
Xcramework在包内销售. 如果舱不能解决,删除 ios/Pods 财务报告和审定财务报表 ios/Podfile.lock运行 pod install 再来一次.
Android – 构建失败,出现与Confose相关的错误.
确定在您的根中声明 Compose Kotlin 插件 build.gradle 而您的克特林版本是相容的(Kotlin QQ 2.1. 建议).
Android(英语: minSdkVersion 错误.
SDK需要API 26+. 弹出 minSdkVersion 在您的项目中 android/build.gradle。 。 。 .
玩家在每个渲染处重建.
你传了个新的 configuration (或 events)每个渲染对象字面. 记住它 useMemo 或把它升到模块范围.
onEvent 唤起火来 callbackKey 实值 undefined。 。 。 .
不同平台的位置不同 e.nativeEvent.callbackKey ?? e.nativeEvent.data?.callbackKey。 。 。 .
文档
- Bambuser 现场视频文档 ——玩家配置,事件目录,集成指南.