Full Screen Integration
The most common pattern: the channel takes the entire screen with a fullscreen player overlay.
Basic Setup
import React, { useRef, useState } from 'react';
import { SafeAreaView, StatusBar, StyleSheet } from 'react-native';
import {
BBChannel,
BBChannelRef,
BBFullscreenPlayer,
BBMediaInfo,
} from '@bluebillywig/react-native-channel';
function ChannelScreen() {
const channelRef = useRef<BBChannelRef>(null);
const [media, setMedia] = useState<BBMediaInfo | null>(null);
return (
<SafeAreaView style={styles.container}>
<StatusBar barStyle="light-content" />
<BBChannel
ref={channelRef}
channelUrl="https://demo.bbvms.com/ch/channel_name.json"
handleBackButton={true}
onMediaRequest={(mediaInfo) => setMedia(mediaInfo)}
style={styles.channel}
/>
<BBFullscreenPlayer
media={media}
visible={media !== null}
onClose={() => setMedia(null)}
/>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#000',
},
channel: {
flex: 1,
},
});
Loading State
Show a loading overlay while the channel initializes:
function ChannelScreen() {
const channelRef = useRef<BBChannelRef>(null);
const [media, setMedia] = useState<BBMediaInfo | null>(null);
const [loading, setLoading] = useState(true);
return (
<SafeAreaView style={styles.container}>
<StatusBar barStyle="light-content" />
<BBChannel
ref={channelRef}
channelUrl="https://demo.bbvms.com/ch/channel_name.json"
handleBackButton={true}
onReady={() => setLoading(false)}
onMediaRequest={(mediaInfo) => setMedia(mediaInfo)}
style={styles.channel}
/>
{loading && (
<View style={styles.loadingOverlay}>
<ActivityIndicator size="large" color="#fff" />
</View>
)}
<BBFullscreenPlayer
media={media}
visible={media !== null}
onClose={() => setMedia(null)}
/>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#000',
},
channel: {
flex: 1,
},
loadingOverlay: {
...StyleSheet.absoluteFillObject,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#000',
},
});
Android Back Button
Simple: Automatic Handling
The easiest approach — set handleBackButton={true} and the SDK handles everything:
<BBChannel
ref={channelRef}
channelUrl="https://demo.bbvms.com/ch/channel_name.json"
handleBackButton={true}
onMediaRequest={(mediaInfo) => setMedia(mediaInfo)}
/>
When the user presses the Android back button:
- If the fullscreen player is open, it closes
- If the channel can go back (detail page → main), it navigates back
- Otherwise, the default back behavior (exit app) runs
Advanced: Manual with Refs
For custom logic (e.g., confirming exit), handle back navigation manually using refs:
import { BackHandler } from 'react-native';
function ChannelScreen() {
const channelRef = useRef<BBChannelRef>(null);
const [media, setMedia] = useState<BBMediaInfo | null>(null);
// Use a ref to avoid stale closures in BackHandler
const canGoBackRef = useRef(false);
useEffect(() => {
const handler = BackHandler.addEventListener('hardwareBackPress', () => {
// Close player first
if (media) {
setMedia(null);
return true;
}
// Then try channel back navigation
if (canGoBackRef.current) {
channelRef.current?.goBack();
return true;
}
// Let the system handle it (exit app)
return false;
});
return () => handler.remove();
}, [media]);
return (
<SafeAreaView style={styles.container}>
<BBChannel
ref={channelRef}
channelUrl="https://demo.bbvms.com/ch/channel_name.json"
onCanGoBackChange={(canGoBack) => {
canGoBackRef.current = canGoBack;
}}
onMediaRequest={(mediaInfo) => setMedia(mediaInfo)}
/>
<BBFullscreenPlayer
media={media}
visible={media !== null}
onClose={() => setMedia(null)}
/>
</SafeAreaView>
);
}
Why refs instead of state?
BackHandler captures the state value at the time the listener is registered. If you use useState for canGoBack, rapid back presses may read a stale value. A ref always returns the current value. See Back Navigation for details.
State Persistence
Save and restore the user's position with AsyncStorage:
import AsyncStorage from '@react-native-async-storage/async-storage';
import { BBNavigationState } from '@bluebillywig/react-native-channel';
const STORAGE_KEY = '@channel_nav_state';
function ChannelScreen() {
const channelRef = useRef<BBChannelRef>(null);
const [media, setMedia] = useState<BBMediaInfo | null>(null);
const [initialState, setInitialState] = useState<BBNavigationState | undefined>();
const [ready, setReady] = useState(false);
// Load saved state on mount
useEffect(() => {
AsyncStorage.getItem(STORAGE_KEY).then((json) => {
if (json) {
setInitialState(JSON.parse(json));
}
setReady(true);
});
}, []);
if (!ready) return null;
return (
<SafeAreaView style={styles.container}>
<BBChannel
ref={channelRef}
channelUrl="https://demo.bbvms.com/ch/channel_name.json"
handleBackButton={true}
initialNavigationState={initialState}
onNavigationStateChange={(state) => {
AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(state));
}}
onMediaRequest={(mediaInfo) => setMedia(mediaInfo)}
/>
<BBFullscreenPlayer
media={media}
visible={media !== null}
onClose={() => setMedia(null)}
/>
</SafeAreaView>
);
}
Key Points
- SafeAreaView — Wrap the channel in
SafeAreaViewto avoid notches and system UI. The SDK also has built-in safe area support via thesafeAreaEdgesprop (see Safe Areas). - StatusBar — Set
barStyle="light-content"for dark channel backgrounds. - Orientation — The channel is responsive and adapts to both portrait and landscape. Lock orientation at the app level if needed. The fullscreen player handles orientation independently.
- Background color — Set the container background to match the channel theme to avoid white flashes during load.