--- name: apple-tv-troubleshooter displayName: "Apple TV Troubleshooter" description: "Expert troubleshooting for Apple TV (tvOS) React Native development. Use when users have issues with Siri Remote, focus management, TVEventHandler, TVFocusGuideView, ScrollView not scrolling, tvOS-specific problems, parallax animations, or tvOS vs Android TV differences." keywords: ["apple-tv", "tvos", "siri-remote", "focus-management", "TVEventHandler", "TVFocusGuideView", "ScrollView", "parallax", "tv-focus", "expo-tv", "react-native-tvos", "navigation", "focus-trap"] author: "Giovanni Laquidara" --- # Apple TV Troubleshooter You are an expert in Apple TV (tvOS) development with React Native. This skill activates when users encounter: - Focus management issues on Apple TV - Siri Remote event handling problems - TVEventHandler not capturing events - ScrollView/FlatList not scrolling - TVFocusGuideView configuration - tvOS vs Android TV differences - Expo TV build issues - Navigation and focus traps ## tvOS Focus Engine vs Android TV **Critical Difference:** tvOS uses a **precision-based** focus engine while Android TV uses **proximity-based**. | Aspect | Apple TV (tvOS) | Android TV | |--------|-----------------|------------| | Focus Engine | Precision-based (strict alignment) | Proximity-based (nearest element) | | Remote Input | Siri Remote touchpad (swipe + click) | D-pad directional buttons | | Focus Recovery | Attempts automatic (inconsistent) | Moves to top-left corner | | Screen Resolution | 1920x1080 (native) | 960x540 (scaled) | **Implication:** UI elements must be properly aligned on tvOS or focus won't move between them. ## Siri Remote Event Handling ### Using useTVEventHandler Hook (Recommended) ```typescript import { useTVEventHandler } from 'react-native'; function MyComponent() { useTVEventHandler((evt) => { switch (evt.eventType) { case 'up': case 'down': case 'left': case 'right': // Handle navigation break; case 'select': // Center button pressed break; case 'playPause': // Play/Pause button break; case 'longPlayPause': // Long press play/pause (tvOS only) break; } }); return {/* content */}; } ``` ### TVEventControl for Menu and Gestures ```typescript import { TVEventControl } from 'react-native'; // Enable Menu button handling (for back navigation) TVEventControl.enableTVMenuKey(); // Enable pan gesture detection on Siri Remote touchpad TVEventControl.enableTVPanGesture(); // Disable when component unmounts TVEventControl.disableTVMenuKey(); TVEventControl.disableTVPanGesture(); ``` ## Common Problems & Solutions | Problem | Cause | Solution | |---------|-------|----------| | **ScrollView won't scroll** | Regular ScrollView needs focusable items | Use `TVTextScrollView` for swipe-based scrolling | | **TVEventHandler doesn't fire** | No focusable component on screen | Add `hasTVPreferredFocus={true}` to parent View or ensure a Touchable exists | | **Event fires twice** | Press and release both trigger | Known behavior - debounce or track event state | | **InputText can't receive focus** | tvOS limitation | Use native input alternatives or custom keyboards | | **Focus leaves FlatList unexpectedly** | Virtualization removes focused item | VirtualizedList auto-wraps with TVFocusGuideView - ensure `trapFocus` enabled | | **Menu button doesn't work** | Not enabled by default | Call `TVEventControl.enableTVMenuKey()` | | **Pan/swipe not detected** | Disabled by default | Call `TVEventControl.enableTVPanGesture()` | | **Expo prebuild fails after changing EXPO_TV** | Cached native config | Always run `npx expo prebuild --clean` | | **Flipper causes build errors** | Incompatible with TV | Set Flipper to false in Podfile, run prebuild --clean | | **Wrong screen dimensions** | Platform difference | Use platform-specific StyleSheets | | **Focus doesn't move diagonally** | Precision engine limitation | Ensure UI elements are aligned vertically/horizontally | | **BackHandler doesn't work** | Different API on tvOS | Use TVEventControl.enableTVMenuKey() for menu/back | | **Parallax not working** | Missing props | Add `tvParallaxProperties` to TouchableHighlight | | **removeClippedSubviews breaks focus** | Clipped items lose focus | Set `removeClippedSubviews={false}` | ## TVFocusGuideView Configuration ```typescript import { TVFocusGuideView } from 'react-native'; // Basic usage with auto-focus memory Item 1 Item 2 // Trap focus within container {/* Focus cannot escape this container */} // Custom focus destinations {/* Guides focus to specific elements */} ``` ### Key Props | Prop | Description | |------|-------------| | `autoFocus` | Remembers last focused child, restores on revisit | | `trapFocusUp/Down/Left/Right` | Prevents focus from leaving in that direction | | `destinations` | Array of refs to guide focus toward | | `focusable` | When false, view and children not focusable | ## Platform-Specific Components ### TVTextScrollView (for scrolling content) ```typescript import { TVTextScrollView } from 'react-native'; // Use instead of ScrollView for non-focusable content Long text content that should scroll with swipe... ``` ### Parallax Animations ```typescript ``` ### Unsupported Components on tvOS These components are **disabled or suppressed** on Apple TV: - `StatusBar` - `Slider` - `Switch` - `WebView` (limited support) ## Focus Management Best Practices ### 1. Set Default Focus on Mount ```typescript Default Focused Item ``` ### 2. Use nextFocus Props for Custom Navigation ```typescript Button 1 ``` ### 3. Capture Events at Top Level ```typescript // Good: Capture at parent level function Screen() { useTVEventHandler((evt) => { // Handle all events here, delegate to children }); return {/* children */}; } // Bad: Each small component handles its own events function SmallButton() { useTVEventHandler((evt) => { /* ... */ }); // Avoid this pattern } ``` ### 4. Use React Context for Focus State ```typescript const FocusContext = createContext({ focusedId: null, setFocused: () => {} }); function FocusProvider({ children }) { const [focusedId, setFocused] = useState(null); return ( {children} ); } ``` ## Expo TV Specific Issues ### Environment Variable ```bash # Must be set BEFORE prebuild export EXPO_TV=1 # Always clean when changing this variable npx expo prebuild --clean ``` ### Common Expo TV Errors | Error | Solution | |-------|----------| | "EXPO_TV not recognized" | Ensure using Expo SDK 50+ | | Build fails after toggling EXPO_TV | Run `npx expo prebuild --clean` | | Flipper errors | Disable Flipper in ios/Podfile | | Dev menu not showing | Use SDK 54+ with RNTV 0.81 for TV dev menu support | ## Platform Detection ```typescript import { Platform } from 'react-native'; // Check if running on any TV if (Platform.isTV) { // TV-specific code } // Check specifically for Apple TV (not Android TV) if (Platform.isTVOS) { // Apple TV only code } // Platform-specific styles const styles = StyleSheet.create({ container: { padding: Platform.isTVOS ? 48 : 16, }, }); ``` ## Debugging Tips 1. **LogBox works on TV** - Error display supported after RN TV 0.76+ 2. **Use console.log liberally** - Metro bundler shows logs 3. **Test on real device** - Simulator misses Siri Remote nuances 4. **Check focus state** - Add `onFocus`/`onBlur` handlers to debug focus flow ## Resources - [react-native-tvos GitHub](https://github.com/react-native-tvos/react-native-tvos) - [React Native TV Docs](https://reactnative.dev/docs/building-for-tv) - [Expo TV Guide](https://docs.expo.dev/guides/building-for-tv/) - [TVFocusGuideView Guide](https://dev.to/amazonappdev/tv-navigation-in-react-native-a-guide-to-using-tvfocusguideview-302i) --- # Cross-Platform Troubleshooting (Also Applies to Apple TV) ## TypeError: Cannot read property 'displayName' of undefined This error affects all TV platforms including Apple TV when using Expo. **Symptoms:** - App builds successfully but crashes immediately on launch - Metro shows: `ERROR TypeError: Cannot read property 'displayName' of undefined` **Common Causes & Fixes:** 1. **Wrong import in index.js** (Most Common) ```javascript // ❌ WRONG - Named import when App uses default export import { App } from './App'; // ✅ CORRECT - Default import import App from './App'; ``` 2. **Metro cache corruption** ```bash pkill -f "expo" 2>/dev/null || true rm -rf node_modules/.cache /tmp/metro-* /tmp/haste-map-* npx expo start --clear ``` 3. **react-tv-space-navigation v6 missing configuration** - v6.0.0+ requires explicit remote control configuration - Create `src/configureRemoteControl.ts`: ```typescript import { SpatialNavigation } from 'react-tv-space-navigation'; SpatialNavigation.configureRemoteControl({ remoteControlSubscriber: (callback) => () => {}, remoteControlUnsubscriber: () => {}, }); ``` - Import at top of App.tsx: `import './src/configureRemoteControl';` ## Expo TV Build & Run Issues ### Always Use Development Builds for TV ```bash # ❌ May cause SDK version issues on TV simulators npx expo start # ✅ Correct for TV development npx expo run:ios # Apple TV npx expo run:android # Android TV # or npx expo start --dev-client ``` ### Apple TV Simulator Quick Commands ```bash # List available simulators xcrun simctl list devices available | grep -i tv # Boot Apple TV simulator xcrun simctl boot "Apple TV" # Run app npx expo run:ios --device "Apple TV" ```