react-native-external-display

repository·master·Indexed 42 days ago

https://github.com/mybigday/react-native-external-display

A React Native library for rendering views on external displays, utilizing the Android Presentation API and iOS Multiple Scenes on iPad. It provides the <ExternalDisplay /> component, the useExternalDisplay and useScreenSize hooks, and a SceneManager API for programmatically controlling multiple windows on iPad and visionOS.

Tokens
6.6K
Snippets
19
Records
29
Agent score
54%

What's inside react-native-external-display

  1. How to implement a Headless multi-window app

    master

    If you want to build a multi-window app where every window has the same layout and you don't need a traditional 'main' scene, you can run in 'Headless' mode. In this mode, the app does not create a root view for a main scene, and you rely on <ExternalDisplay> components to render views.

    Steps:

    1. Modify AppDelegate.mm: Set the headless option to @YES in the application:configurationForConnectingSceneSession:options: method: sceneOptions:@{ @"headless": @YES }
    2. Handle Rendering: Ensure your app automatically creates new scenes and renders views using the <ExternalDisplay> component.
    3. Filter Screens: When iterating through screens, exclude the main scene by checking screen.type == SceneManager.types.EXTERNAL_DISPLAY to identify external displays.
    // In AppDelegate.mm
    UISceneConfiguration * configuration = [RNExternalAppDelegateUtil application:application
          configurationForConnectingSceneSession:connectingSceneSession
          options:options
          sceneOptions:@{
            @"headless": @YES
          }
        ];
  2. iPad Split View and External Screen compatibility

    master

    To support both iPad Split View and an external screen simultaneously, the app must be positioned as the main screen (e.g., on the left side in Split View).

    It will not work if the app is on the right side of a Split View or if it is used as a Slide Over, because in those configurations, the app does not receive the UIScreenDidConnectNotification event required to manage the external display.

  3. Enable Stage Manager on iPad Simulator

    master

    The example supports Stage Manager (available on iOS 16.0+). If you are using an iPad simulator, you can enable Stage Manager using one of the following two methods:

    Option 1: Via Settings

    1. Navigate to Home Screen & Multitasking.
    2. Tap Stage Manager at the bottom of the screen.

    Option 2: Via Command Line Run the following command to enable it directly via simctl:

    xcrun simctl spawn booted defaults write -g SBChamoisWindowingEnabled -bool true
  4. Run the RNExternalDisplayExample on iOS

    master

    To run the example project on iOS, install the CocoaPods dependencies and then launch the application using the React Native CLI.

    Simulator testing: Once the app is running on a simulator, you can simulate an external display by navigating to the menu: Hardware -> External displays.

    Real device testing: To test on a physical device, connect a second display using AirPlay or a Lightning to HDMI cable.

    $ cd ios && pod install && cd -
    $ react-native run-ios
  5. Run the RNExternalDisplayExample on Android

    master

    To run the example project on Android, use the React Native CLI.

    Simulator/Emulator testing: For debugging purposes on an emulator, you can simulate a secondary display by navigating to: Setting -> Developer options -> Simulate secondary displays.

    Real device testing: To test on a physical device, connect a second display using Chromecast or a compatible adapter.

    $ react-native run-android
  6. Setup Multiple Scenes support on iPad/visionOS

    master

    To enable Split View or Multiple Windows support on iPad and visionOS (iOS 13.0+), you must perform three configuration steps in your Xcode project:

    1. Add iPad Target: In your Xcode workspace, ensure iPad is added to the Supported Destinations.
    2. Configure Info.plist: Enable multiple scenes and disable full screen mode by adding UIApplicationSupportsMultipleScenes and UIRequiresFullScreen keys.
    3. Update AppDelegate.mm: Implement the application:configurationForConnectingSceneSession:options: method using RNExternalAppDelegateUtil to manage scene configurations.

    This setup creates two types of delegates:

    • RNExternalSceneMainDelegate: The primary app scene (ensure only one is created).
    • RNExternalSceneDelegate: Scenes for external screens (can be multiple).

    Note: The app will automatically create the main scene if it is not active, or create an external scene if connected to an external screen or if requestScene is called.

    --- Info.prev.plist
    +++ Info.plist
    @@ -37,6 +37,13 @@
     	</dict>
     	<key>NSLocationWhenInUseUsageDescription</key>
     	<string></string>
    ++	<key>UIApplicationSceneManifest</key>
    ++	<dict>
    ++		<key>UIApplicationSupportsMultipleScenes</key>
    ++		<true/>
    ++	</dict>
    ++	<key>UIRequiresFullScreen</key>
    ++	<false/>
     	<key>UILaunchStoryboardName</key>
     	<string>LaunchScreen</string>
    --- AppDelegate.prev.mm
    +++ AppDelegate.mm
    @@ -2,6 +2,9 @@
     
     #import <React/RCTBundleURLProvider.h>
     
    +// Use RNExternalAppDelegateUtil
    +#import "RNExternalDisplayUtils.h"
    +
     @implementation AppDelegate
     
     - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    @@ -14,6 +17,19 @@
       return [super application:application didFinishLaunchingWithOptions:launchOptions];
     }
     
    +- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options API_AVAILABLE(ios(13.0)) {
    +  UISceneConfiguration * configuration =
    +    [RNExternalAppDelegateUtil application:application
    +      configurationForConnectingSceneSession:connectingSceneSession
    +      options:options
    +      sceneOptions:@{
    +        @"headless": @NO
    +      }
    +    ];
    +  // You can put custom configuration here
    +  return configuration;
    +}
    +
     - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
     {
     #if DEBUG
  7. Render views on an external display

    master

    Use the ExternalDisplay component and the useExternalDisplay hook to render React Native content on a connected external screen.

    1. Call useExternalDisplay() to get an object containing available screens.
    2. Pass the desired screen identifier to the screen prop of the ExternalDisplay component.
    3. Use the fallbackInMainScreen prop to ensure content is rendered on the main screen if no external screen is selected or available.

    Note: On iOS, this leverages Apple's 'Displaying Content on a Connected Screen' capabilities. On Android, it uses the 'Presentation API'.

    import React from 'react'
    import Video from 'react-native-video'
    import ExternalDisplay, {
      useExternalDisplay,
    } from 'react-native-external-display'
    
    function App() {
      const screens = useExternalDisplay()
    
      return (
        <ExternalDisplay
          mainScreenStyle={{ flex: 1 }}
          fallbackInMainScreen
          screen={Object.keys(screens)[0]}
        >
          <Video
            source={{
              uri: 'http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4',
            }}
            style={{ flex: 1 }}
            repeat
            muted
          />
        </ExternalDisplay>
      )
    }
  8. Configure scene resizability

    master

    The ability for a scene to be resized depends on your app's orientation settings in Info.plist. Ensure you have defined the supported orientations for iPad to allow proper multitasking behavior.

    <key>UISupportedInterfaceOrientations~ipad</key>
    <array>
      <string>UIInterfaceOrientationLandscapeLeft</string>
      <string>UIInterfaceOrientationLandscapeRight</string>
      <string>UIInterfaceOrientationPortrait</string>
      <string>UIInterfaceOrientationPortraitUpsideDown</string>
    </array>
  9. Known limitations of Multiple Scenes support

    master

    When using Multiple Scenes on iPad/visionOS, be aware of the following current limitations:

    • Drag-and-Drop: Dragging an item to create a new scene is not yet supported.
    • macOS Support: Multiple scenes are currently not working on macOS (even with UIApplicationSupportsMultipleScenes enabled).
    • SafeAreaView: SafeAreaView has no effect on newly created scenes.
  10. Troubleshoot iOS and Android known issues

    master

    iOS

    • Developer Menu/Keyboard Shortcuts: These may not function correctly if the view renderer is attached to an external screen.
      • Workaround: Use the DevSettings module from React Native (e.g., via react-native-debugger) to access dev menu functions.

    Android

    • Modals: The react-native Modal component does not have good support for external displays on Android; it will always appear on the main screen.