Player API
The BambuserVideoView ref exposes an imperative API for controlling playback, Picture-in-Picture, and the JS ↔ player bridge.
const playerRef = useRef<BambuserVideoViewRef>(null);
Ref Methods
| Method | Signature | Notes |
|---|---|---|
play() | () => void | Resume playback. |
pause() | () => void | Pause playback. |
mute() | () => void | Mute audio. |
unMute() | () => void | Unmute audio. |
startPiP() | () => void | Enter Picture-in-Picture. |
stopPiP() | () => void | Exit Picture-in-Picture. |
setPiPEnabled(enabled) | (boolean) => void | Enable/disable the PiP feature. Defaults to true. |
invoke(fn, args) | (string, string) => Promise<any> | Call a player-side function. See Player Bridge. |
notify(callbackKey, info) | (string, NotifyInfo) => void | Reply to a callback event surfaced via onEvent. |
getCurrentPlayerState() | () => Promise<BambuserPlayerState> | Read the last-known player state. |
getNativeTag() | () => number | null | Underlying native view tag. Escape hatch, rarely needed. |
cleanup() | () => void | Tear down the player and release native resources. Irreversible. See Lifecycle. |
Player Bridge: invoke & notify
The Bambuser player runs in a webview internally. Two primitives bridge JS ↔ player:
invoke(fn, args)
Call a function on the player. Returns a Promise. Use this to drive UI commands such as showing or hiding overlays, or hydrating products.
await playerRef.current?.invoke('hideUI', '');
await playerRef.current?.invoke('showUI', '');
notify(callbackKey, info)
Respond to a callback event the player surfaced via onEvent. The callbackKey comes from the event payload; info is your response.
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 accepts booleans, numbers, strings, plain objects/arrays, or null. Strings that already look like JS literals ({...}, [...], numbers, true/false/null) are passed through; anything else is JSON-encoded.
Picture-in-Picture
PiP is enabled by default. Disable per-component with setPiPEnabled(false), or trigger it manually with startPiP() / stopPiP().
playerRef.current?.startPiP();
playerRef.current?.stopPiP();
playerRef.current?.setPiPEnabled(false);
Platform behavior
-
iOS: PiP is view-level. Only the video floats; the rest of your app is unaffected. Provided by the SDK's
pipController. -
Android: PiP is activity-level. The entire host activity shrinks into the PiP window. You should hide non-video UI when entering PiP and restore it on exit:
const [inPiP, setInPiP] = useState(false);
<BambuserVideoView
onPiPStateChanged={(e) => setInPiP(e.nativeEvent.state === 'started')}
...
/>
{!inPiP && <YourAppChrome />}
See Events › onPiPStateChanged for the full list of PiP states.
Lifecycle & Cleanup
The player automatically releases native resources when the component unmounts. You normally don't need to call cleanup() yourself.
Call cleanup() explicitly when:
- You're about to navigate away and want to free resources immediately, or
- You want to stop the video before unmount (e.g. the user backed out via a custom gesture).
⚠️
cleanup()is irreversible. Once called, the player is gone. To play again, unmount and remount the component (or changeidto force a rebuild).
useEffect(() => () => playerRef.current?.cleanup(), []);
Reading state imperatively
For type-safe state handling outside of callbacks:
import type { BambuserPlayerState } from '@bambuser/react-native-commerce-sdk';
const state: BambuserPlayerState | undefined =
await playerRef.current?.getCurrentPlayerState();
switch (state) {
case 'playing': /* ... */ break;
case 'buffering': /* ... */ break;
case 'paused': /* ... */ break;
}