Skip to content

bluebillywig/react-native-sdk

Repository files navigation

expo-bb-player

React Native implementation of the Blue Billywig Outstream Native Player for Expo and bare React Native apps.

Installation

For Expo Managed Projects

If you're using an Expo managed project (created with create-expo-app), simply install the package:

npx expo install expo-bb-player

Then run prebuild to generate native directories:

# For iOS
npx expo prebuild -p ios

# For Android
npx expo prebuild -p android

For Bare React Native Projects

Prerequisites

This library is an Expo module, so you need to have Expo modules installed in your project first. If you haven't installed Expo modules yet, follow these steps:

  1. Automatic Setup (Recommended):
npx install-expo-modules@latest

This command will automatically configure your project to use Expo modules. For more details, see the official Expo documentation.

  1. Manual Setup:

If the automatic installation fails, follow the manual installation guide in the Expo documentation.

Installing expo-bb-player

Once Expo modules are installed in your project:

  1. Install the package:
npx expo install expo-bb-player
# or
npm install expo-bb-player
  1. For iOS, install CocoaPods dependencies:
npx pod-install
  1. For Android, the dependencies will be automatically linked through autolinking.

  2. Rebuild your app:

# For iOS
npx expo run:ios
# or
npx react-native run-ios

# For Android
npx expo run:android
# or
npx react-native run-android

Basic Usage

Here's a simple example of how to use the Blue Billywig Player:

import React, { useRef } from 'react';
import { View, StyleSheet, Button } from 'react-native';
import { ExpoBBPlayerView, type ExpoBBPlayerViewType } from 'expo-bb-player';

export default function App() {
  const playerRef = useRef<ExpoBBPlayerViewType>(null);

  return (
    <View style={styles.container}>
      <ExpoBBPlayerView
        ref={playerRef}
        jsonUrl="YOUR_BLUE_BILLYWIG_JSON_URL"
        options={{
          autoPlay: false,
          allowCollapseExpand: true,
        }}
        onDidTriggerPlay={() => {
          console.log('Player started playing');
        }}
        onDidTriggerPause={() => {
          console.log('Player paused');
        }}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
  },
});

Advanced Example

Here's a more advanced example with event handlers and player controls:

import React, { useRef, useState } from 'react';
import { View, StyleSheet, Button, Text } from 'react-native';
import { 
  ExpoBBPlayerView, 
  type ExpoBBPlayerViewType,
  type State,
  type Phase 
} from 'expo-bb-player';

export default function AdvancedPlayer() {
  const playerRef = useRef<ExpoBBPlayerViewType>(null);
  const [playerState, setPlayerState] = useState<State>('IDLE');
  const [playerPhase, setPlayerPhase] = useState<Phase>('INIT');
  const [duration, setDuration] = useState(0);

  const handleEnterFullscreen = () => {
    playerRef.current?.enterFullscreen();
  };

  const handleSeek = (position: number) => {
    playerRef.current?.seek(position);
  };

  const handleSetVolume = (volume: number) => {
    playerRef.current?.setVolume(volume);
  };

  return (
    <View style={styles.container}>
      <ExpoBBPlayerView
        ref={playerRef}
        jsonUrl="YOUR_BLUE_BILLYWIG_JSON_URL"
        options={{
          autoPlay: true,
          autoMute: false,
          allowCollapseExpand: true,
        }}
        onDidTriggerStateChange={(state) => {
          setPlayerState(state);
          console.log('State changed:', state);
        }}
        onDidTriggerPhaseChange={(phase) => {
          setPlayerPhase(phase);
          console.log('Phase changed:', phase);
        }}
        onDidTriggerDurationChange={(duration) => {
          setDuration(duration);
          console.log('Duration:', duration);
        }}
        onDidTriggerProjectLoaded={(project) => {
          console.log('Project loaded:', project);
        }}
        onDidTriggerMediaClipLoaded={(mediaClip) => {
          console.log('Media clip loaded:', mediaClip);
        }}
        onDidFailWithError={(error) => {
          console.error('Player error:', error);
        }}
        onDidTriggerAdStarted={() => {
          console.log('Ad started');
        }}
        onDidTriggerAdFinished={() => {
          console.log('Ad finished');
        }}
      />
      <View style={styles.info}>
        <Text>State: {playerState}</Text>
        <Text>Phase: {playerPhase}</Text>
        <Text>Duration: {duration.toFixed(2)}s</Text>
      </View>
      <View style={styles.controls}>
        <Button title="Fullscreen" onPress={handleEnterFullscreen} />
        <Button title="Seek to 10s" onPress={() => handleSeek(10)} />
        <Button title="Volume 50%" onPress={() => handleSetVolume(0.5)} />
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
  },
  info: {
    padding: 20,
    backgroundColor: '#f0f0f0',
  },
  controls: {
    flexDirection: 'row',
    justifyContent: 'space-around',
    padding: 20,
  },
});

API Reference

Props

Prop Type Description
jsonUrl string The Blue Billywig JSON URL for the media
options Record<string, unknown> Player configuration options passed through to the native SDK
style ViewStyle Styling for the player container
Event props See Events Subscribe to native player events (see Events section below)

Player Options

Common options you can pass to the options prop:

{
  autoPlay: boolean;           // Auto-play the video
  allowCollapseExpand: boolean; // Allow collapse/expand functionality
  autoLoop: boolean;            // Loop the video

}

Methods

Access these methods via the player ref:

// Playback controls
play(): Promise<void>
pause(): Promise<void>
seek(position: number): Promise<void>

// Volume controls
setVolume(volume: number): Promise<void>  // 0.0 - 1.0
setMuted(muted: boolean): Promise<void>

// Fullscreen controls
// Android: implemented. iOS: currently no-op.
enterFullscreen(): Promise<void>
exitFullscreen(): Promise<void>

// Expand/Collapse controls (outstream sizing)
expand(): Promise<void>
collapse(): Promise<void>

// Ad/clip data
adMediaHeight(): Promise<number | undefined>
adMediaWidth(): Promise<number | undefined>
adMediaClip(): Promise<MediaClip | undefined>
autoPlayNextCancel(): Promise<void>

// State getters
playerState(): Promise<State>
phase(): Promise<Phase>
duration(): Promise<number | undefined>
volume(): Promise<number | undefined>
muted(): Promise<boolean | undefined>
inView(): Promise<boolean | undefined>
mode(): Promise<string | undefined>
controls(): Promise<boolean | undefined> // Android only; iOS returns undefined
playoutData(): Promise<Playout | undefined>
projectData(): Promise<Project | undefined>

Platform notes:

  • iOS: enterFullscreen and exitFullscreen are currently not supported.
  • iOS: controls() is not exposed by the native SDK and will return undefined.

Events

All events below are exposed as optional props on ExpoBBPlayerView. Payload types are indicated in parentheses.

Event Payload Description
onDidFailWithError string A fatal or setup error occurred
onDidRequestCollapse - Player requested to collapse (outstream)
onDidRequestExpand - Player requested to expand (outstream)
onDidRequestOpenUrl string Player requested to open a URL
onDidSetupWithJsonUrl string Player finished initial setup with the provided JSON URL
onDidTriggerCanPlay - Player is ready; API getters should now be available
onDidTriggerPlay - Playback started
onDidTriggerPause - Playback paused
onDidTriggerPlaying - Playback is progressing
onDidTriggerEnded - Playback ended
onDidTriggerStateChange State Player state changed
onDidTriggerPhaseChange Phase Player phase changed
onDidTriggerDurationChange number Media duration changed
onDidTriggerVolumeChange number Volume changed
onDidTriggerSeeked number Seek completed to the provided position (seconds)
onDidTriggerSeeking - Seek started
onDidTriggerFullscreen - Entered fullscreen
onDidTriggerRetractFullscreen - Exited fullscreen
onDidTriggerModeChange string Player mode changed
onDidTriggerProjectLoaded Project Project loaded
onDidTriggerMediaClipLoaded MediaClip Media clip loaded
onDidTriggerMediaClipFailed - Media clip failed to load
onDidTriggerStall - Playback stalled
onDidTriggerCustomStatistics { ident: string; ev: string; aux: Record<string,string>; } Custom statistics event
onDidTriggerAutoPause Android: string (why) · iOS: void Auto-pause was triggered
onDidTriggerAutoPausePlay Android: string (why) · iOS: void Auto-pause resume was triggered
onDidTriggerAdLoadStart - Ad load started
onDidTriggerAdLoaded - Ad loaded
onDidTriggerAdStarted - Ad started
onDidTriggerAdQuartile1 - Ad reached 25%
onDidTriggerAdQuartile2 - Ad reached 50%
onDidTriggerAdQuartile3 - Ad reached 75%
onDidTriggerAdFinished - Ad finished
onDidTriggerAdNotFound - No ad was available
onDidTriggerAdError string Ad-related error
onDidTriggerAllAdsCompleted - All ads completed
onDidTriggerViewStarted - View tracking started
onDidTriggerViewFinished - View tracking finished

Platform notes:

  • Android and iOS emit the full set of events above. On iOS, onDidTriggerAutoPause and onDidTriggerAutoPausePlay do not include the why payload, while on Android the why string is provided.
  • Some events are emitted only when relevant (e.g., ad-related events only during ad playback).

Types

type State = "IDLE" | "LOADING" | "PLAYING" | "PAUSED" | "ERROR";
type Phase = "INIT" | "PRE" | "MAIN" | "POST" | "EXIT";
// Selected payload types used in events and getters
type CustomStatistics = { ident: string; ev: string; aux: Record<string, string> };
type Project = { /* see src/types.ts for full shape */ };
type MediaClip = { /* see src/types.ts for full shape */ };
type Playout = { /* see src/types.ts for full shape */ };

SDK Version Management

This package automatically uses the latest compatible version of the Blue Billywig native SDKs:

  • iOS: Version ~>8.30
  • Android: Version range [8.30,9.0)

Automatic Updates

When you run pod install (iOS) or build your Android app, the build system will automatically resolve to the latest available version within these constraints. This ensures you benefit from bug fixes and improvements in the native SDKs without manual intervention.

iOS: Uses CocoaPods pessimistic versioning (~>8.30), which allows any version from 8.30 up to (but not including) 9.0.

Android: Uses Gradle range notation ([8.30,9.0)), which allows any version from 8.30 (inclusive) to 9.0 (exclusive).

Version Constraints

The minimum version constraint of 8.30 ensures users have access to the latest features and critical fixes. When we release version 9.0, we will update this package to support it.

For Package Maintainers

The lockfiles (Podfile.lock and Gemfile.lock) are intentionally not committed to version control. This ensures that:

  1. End users always get the latest SDK versions within the specified constraints
  2. SDK updates flow through automatically without requiring package updates
  3. CI/CD builds catch any breaking changes early

Example Project

Check out the /example directory for a complete working example with:

  • Multiple player configurations
  • Event handling demonstrations
  • API usage examples

To run the example:

cd example
npm install

# For iOS
npx expo run:ios

# For Android
npx expo run:android

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 5