@bluebillywig/react-native-channel
v1.1.0
Published
Blue Billywig Channel SDK for React Native - Embed video channels in your React Native apps
Readme
Blue Billywig React Native Channel SDK
Embed Blue Billywig video channels in your React Native app with full navigation, authentication, and player control support.
Installation
npm install @bluebillywig/react-native-channel react-native-webviewiOS Setup
cd ios && pod installAndroid Setup
No additional setup required.
Quick Start
import { BBChannel } from '@bluebillywig/react-native-channel';
function App() {
return (
<BBChannel
channelUrl="https://demo.bbvms.com/ch/123.json"
onReady={() => console.log('Channel loaded')}
onMediaPlay={(media) => console.log('Playing:', media.title)}
/>
);
}BBChannel Component
The main component for embedding a video channel.
Props
Required
| Prop | Type | Description |
|------|------|-------------|
| channelUrl | string | URL to the channel JSON configuration |
Configuration Options
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| options.autoPlay | boolean | true | Enable/disable autoplay |
| options.searchBar | boolean | true | Show/hide search bar |
| options.noStats | boolean | false | Disable analytics |
| options.jwt | string | - | JWT token for authenticated content |
| options.rpcToken | string | - | RPC token for authenticated content |
| options.playout | string | - | Custom playout configuration name |
| options.contentId | string | - | Initial content ID to display |
| options.contentType | 'mediaclip' \| 'mediacliplist' | - | Type of initial content |
| options.bundleUrl | string | CDN URL | Custom bundle URL (must be *.bluebillywig.com) |
| options.fullscreenMode | 'fullscreen' \| 'landscape' | 'landscape' | Fullscreen behavior |
Lifecycle Events
| Prop | Type | Description |
|------|------|-------------|
| onReady | () => void | Called when channel is fully loaded |
| onError | (error: BBErrorEvent) => void | Called on errors |
Navigation Events
| Prop | Type | Description |
|------|------|-------------|
| onNavigate | (event: BBNavigationEvent) => void | Called on navigation changes |
| onNavigationStateChange | (state: BBNavigationState) => void | Called when navigation state changes |
| onCanGoBackChange | (canGoBack: boolean) => void | Called when back navigation availability changes |
| initialNavigationState | BBNavigationState | Initial state for deep linking |
Search Events
| Prop | Type | Description |
|------|------|-------------|
| onSearch | (event: BBSearchEvent) => void | Called when a search is performed |
Media Events
| Prop | Type | Description |
|------|------|-------------|
| onMediaPlay | (media: BBMediaInfo) => void | Called when media starts playing |
| onMediaPause | (media: BBMediaInfo) => void | Called when media is paused |
| onMediaEnd | (media: BBMediaInfo) => void | Called when media ends |
| onFirstPlayerMedia | (media: BBMediaInfo) => void | Called when first player media is identified |
Player Events
| Prop | Type | Description |
|------|------|-------------|
| onPlayerStateChange | (state: BBPlayerState) => void | Called on player state changes |
| onPlayerEvent | (event: BBPlayerEvent) => void | Called on any player event |
| onTimeUpdate | (data: BBTimeUpdateEvent) => void | Called frequently during playback |
| onClipLoaded | (data: BBClipLoadedEvent) => void | Called when a clip is loaded |
| onAdStart | (data: BBAdEvent) => void | Called when an ad starts |
| onAdEnd | (data: BBAdEvent) => void | Called when an ad ends |
Ref Methods
Access methods via ref:
const channelRef = useRef<BBChannelRef>(null);
// Later...
channelRef.current?.play();
channelRef.current?.setJwt('new-token');Authentication Methods
| Method | Description |
|--------|-------------|
| setJwt(jwt: string \| null) | Update JWT token for authenticated content |
| setRpcToken(token: string \| null) | Update RPC token |
Navigation Methods
| Method | Description |
|--------|-------------|
| navigateTo(page: 'main' \| 'search') | Navigate to a page |
| goBack() | Navigate back |
| search(query: string) | Perform a search |
| reload() | Reload the channel |
| playVideo(videoId: string, type?) | Play a specific video |
| navigateToEntity(entityId, entityType, options?) | Navigate to entity detail page |
| navigateToSubChannel(subChannelId: string) | Navigate to sub-channel |
| resetNavigation() | Clear history and go to main |
| setNavigationState(state: BBNavigationState) | Restore navigation state |
| getNavigationState(): Promise<BBNavigationState> | Get current navigation state |
| canGoBack(): Promise<boolean> | Check if back navigation is possible |
Player Control Methods
| Method | Description |
|--------|-------------|
| play() | Start or resume playback |
| pause() | Pause playback |
| seek(seconds: number) | Seek to position |
| setVolume(volume: number) | Set volume (0.0 - 1.0) |
| setMuted(muted: boolean) | Mute or unmute |
| enterFullscreen() | Enter fullscreen mode |
| exitFullscreen() | Exit fullscreen mode |
| getPlayerState(): Promise<BBPlayerState \| null> | Get current player state |
Types
BBMediaInfo
Information about a media clip.
interface BBMediaInfo {
jsonUrl: string; // URL for loading in native player
playoutId: string; // Playout configuration ID
autoplay: boolean; // Whether to autoplay
thumbnailUrl?: string; // Thumbnail URL
title?: string; // Media title
mediaType?: 'video' | 'audio'; // Content type
}BBNavigationState
Full navigation state for deep linking and state persistence.
interface BBNavigationState {
pageType: 'main' | 'detailPage' | 'overviewPage' | 'searchPage';
contentId?: string; // Entity ID
contentType?: 'mediaclip' | 'mediacliplist';
searchQuery?: string;
clickedSearchResult?: boolean;
blockId?: string;
contextId?: string;
playout?: string;
collectionId?: string;
subChannelId?: string;
}BBPlayerState
Current player state.
interface BBPlayerState {
isPlaying: boolean;
currentTime?: number; // In seconds
duration?: number; // In seconds
volume?: number; // 0.0 - 1.0
isMuted?: boolean;
isFullscreen?: boolean;
}BBPlayerEvent
Union type for all player events. Use with onPlayerEvent for fine-grained control.
// Event types:
// 'play', 'pause', 'ended', 'canplay', 'waiting',
// 'seeking', 'seeked', 'timeupdate', 'durationchange', 'progress',
// 'volumechange', 'fullscreenchange', 'loadstart', 'loadedmetadata', 'loadeddata',
// 'cliploaded', 'clipfailed', 'cliplistloaded',
// 'adstart', 'adend', 'adskip', 'aderror', 'error'BBTimeUpdateEvent
Time update data sent frequently during playback.
interface BBTimeUpdateEvent {
timestamp: number;
clipId?: string;
title?: string;
currentTime: number; // In seconds
duration: number; // In seconds
progress: number; // 0-100 percentage
}BBClipLoadedEvent
Clip loaded event data.
interface BBClipLoadedEvent {
timestamp: number;
clipId: string;
title: string;
duration: number; // In seconds
thumbnailUrl?: string;
isLive?: boolean;
}BBAdEvent
Advertisement event data.
interface BBAdEvent {
timestamp: number;
position?: 'pre' | 'mid' | 'post';
duration?: number; // In seconds
remainingTime?: number; // In seconds
skippable?: boolean;
skipOffset?: number; // Seconds until skip available
}BBErrorEvent
Error event data.
interface BBErrorEvent {
code: string;
message: string;
details?: unknown;
}BBSearchEvent
Search event data.
interface BBSearchEvent {
query: string;
resultCount: number;
}Examples
Authentication
function AuthenticatedChannel() {
const channelRef = useRef<BBChannelRef>(null);
const [token, setToken] = useState<string | null>(null);
// Update token when it changes
useEffect(() => {
channelRef.current?.setJwt(token);
}, [token]);
return (
<BBChannel
ref={channelRef}
channelUrl="https://demo.bbvms.com/ch/123.json"
options={{ jwt: token ?? undefined }}
/>
);
}Player Progress Tracking
function ProgressTrackingChannel() {
const [progress, setProgress] = useState(0);
return (
<>
<ProgressBar value={progress} />
<BBChannel
channelUrl="https://demo.bbvms.com/ch/123.json"
onTimeUpdate={(data) => setProgress(data.progress)}
onPlayerEvent={(event) => {
if (event.type === 'ended') {
console.log('Video finished!');
}
}}
/>
</>
);
}Deep Linking
function DeepLinkChannel() {
const channelRef = useRef<BBChannelRef>(null);
// Handle deep link
useEffect(() => {
const url = Linking.getInitialURL();
if (url?.includes('video=')) {
const videoId = extractVideoId(url);
channelRef.current?.navigateToEntity(videoId, 'mediaclip', { autoPlay: true });
}
}, []);
// Save state for restoration
const handleNavigationChange = (state: BBNavigationState) => {
AsyncStorage.setItem('channelState', JSON.stringify(state));
};
return (
<BBChannel
ref={channelRef}
channelUrl="https://demo.bbvms.com/ch/123.json"
onNavigationStateChange={handleNavigationChange}
/>
);
}Android Back Button
function BackButtonChannel() {
const channelRef = useRef<BBChannelRef>(null);
const [canGoBack, setCanGoBack] = useState(false);
useEffect(() => {
const backHandler = BackHandler.addEventListener('hardwareBackPress', () => {
if (canGoBack) {
channelRef.current?.goBack();
return true;
}
return false;
});
return () => backHandler.remove();
}, [canGoBack]);
return (
<BBChannel
ref={channelRef}
channelUrl="https://demo.bbvms.com/ch/123.json"
onCanGoBackChange={setCanGoBack}
/>
);
}Player Controls
function PlayerControlsChannel() {
const channelRef = useRef<BBChannelRef>(null);
const handlePlayPause = async () => {
const state = await channelRef.current?.getPlayerState();
if (state?.isPlaying) {
channelRef.current?.pause();
} else {
channelRef.current?.play();
}
};
return (
<>
<TouchableOpacity onPress={handlePlayPause}>
<Text>Play/Pause</Text>
</TouchableOpacity>
<BBChannel
ref={channelRef}
channelUrl="https://demo.bbvms.com/ch/123.json"
/>
</>
);
}BBChannelWithPlayer Component
A channel component with integrated native video player. Combines BBChannel (WebView) with BBPlayerView (native player) for optimal video playback. Requires @bluebillywig/react-native-bb-player as a peer dependency.
import { BBChannelWithPlayer } from '@bluebillywig/react-native-channel';
function App() {
return (
<BBChannelWithPlayer
channelUrl="https://demo.bbvms.com/ch/123.json"
playerMode="inline"
onNativePlayerStateChange={(state) => console.log('Player:', state)}
/>
);
}Props (in addition to BBChannel props)
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| playerMode | 'inline' \| 'fullscreen' | 'inline' | Player display mode |
| playerHeight | number | - | Fixed height for inline player (uses aspectRatio if not set) |
| playerAspectRatio | number | 16/9 | Aspect ratio for inline player |
| showBackArrow | boolean | true | Show close button over inline player |
| jwt | string | - | JWT token for both channel and player |
| onNativePlayerStateChange | (state) => void | - | Called on player state changes |
| onNativePlayerError | (error) => void | - | Called on player errors |
Troubleshooting
WebView not rendering
Make sure react-native-webview is properly installed and linked:
npm install react-native-webview
cd ios && pod installVideo not playing on iOS
Ensure your app has the proper permissions:
<!-- ios/YourApp/Info.plist -->
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>Channel not loading
- Verify the channel URL is accessible
- Check network connectivity
- Ensure CORS is properly configured on your publication
Authentication errors
- Verify JWT/RPC tokens are valid and not expired
- Check that tokens have the correct permissions
Support
- Documentation: https://support.bluebillywig.com
- Email: [email protected]
License
Proprietary software © Blue Billywig. Use is permitted only under a current written agreement with Blue Billywig covering the use of Blue Billywig channels. See LICENSE.md for details.
