presentation_displays_hig 2.0.0 copy "presentation_displays_hig: ^2.0.0" to clipboard
presentation_displays_hig: ^2.0.0 copied to clipboard

Flutter plugin supports to run on two screens. It's basically a tablet connected to another screen via an HDMI or Wireless

presentation_displays #

A Flutter plugin to manage and display content on secondary screens (HDMI, Wireless, AirPlay).

This plugin creates a separate FlutterEngine for the secondary display, allowing you to render a completely independent UI on the external screen while communicating with the main application via Method Channels.

Features #

  • Multi-Screen Support: Run a separate Flutter widget tree on an external display.
  • Plug & Play: Automatically detects connected displays.
  • Data Transfer: Send data objects (Map/JSON) from the main screen to the secondary screen.
  • Cross-Platform: Supports Android and iOS.

1. Flutter Setup (Entry Points) #

To run a UI on a secondary screen, you must define a specific entry point called secondaryDisplayMain. This acts as the "main" function for your external display.

In your lib/main.dart (or wherever your entry points are defined):

import 'package:flutter/material.dart';

// 1. The Main Entry Point
void main() {
  debugPrint('first main');
  runApp(const MyApp());
}

// 2. The Secondary Entry Point
// IMPORTANT: This must be named 'secondaryDisplayMain' and annotated with @pragma('vm:entry-point')
@pragma('vm:entry-point')
void secondaryDisplayMain() {
  debugPrint('second main');
  runApp(const MySecondApp());
}

// 3. Your Secondary App Widget
class MySecondApp extends StatelessWidget {
  const MySecondApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      // Define specific routes for the secondary screen
      onGenerateRoute: generateRoute, 
      initialRoute: 'presentation',
    );
  }
}

// 4. Your Main App Widget
class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      onGenerateRoute: generateRoute,
      initialRoute: '/',
    );
  }
}


2. Android Setup #

No special configuration is required for Android. Ensure your minSdkVersion is compatible with Flutter defaults.


3. iOS Setup #

⚠️ Critical: This plugin requires iOS 13.0+ and the adoption of the UIScene Lifecycle. If your app is still using the legacy UIWindow logic without Scenes, it must be migrated.

Step A: Update Info.plist #

Open ios/Runner/Info.plist and add the UIApplicationSceneManifest. This configures the app to handle both the main application screen and the external display role.

<key>UIApplicationSceneManifest</key>
<dict>
    <key>UIApplicationSupportsMultipleScenes</key>
    <false/>
    <key>UISceneConfigurations</key>
    <dict>
        <key>UIWindowSceneSessionRoleApplication</key>
        <array>
            <dict>
                <key>UISceneClassName</key>
                <string>UIWindowScene</string>
                <key>UISceneDelegateClassName</key>
                <string>FlutterSceneDelegate</string>
                <key>UISceneConfigurationName</key>
                <string>flutter</string>
                <key>UISceneStoryboardFile</key>
                <string>Main</string>
            </dict>
        </array>
        
        <key>UIWindowSceneSessionRoleExternalDisplay</key>
        <array>
            <dict>
                <key>UISceneClassName</key>
                <string>UIWindowScene</string>
                <key>UISceneConfigurationName</key>
                <string>External Display</string>
                <key>UISceneDelegateClassName</key>
                <string>FlutterSceneDelegate</string>
            </dict>
        </array>
    </dict>
</dict>

Step B: Update AppDelegate.swift #

You must adopt the FlutterImplicitEngineDelegate protocol to handle plugin registration for the main engine, and hook into SwiftPresentationDisplaysPlugin to register plugins for the secondary engine.

Replace your AppDelegate.swift content with:

import UIKit
import Flutter
import presentation_displays_hig

@main
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
  
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }

  // MARK: - FlutterImplicitEngineDelegate
  // This method is called when the main Flutter engine is initialized
  func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
    // Register plugins for the MAIN engine
    GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
    
    // Assign the callback for when the SECONDARY controller is added
    SwiftPresentationDisplaysPlugin.controllerAdded = controllerAdded
  }

  // This method is called by the plugin when the secondary display is connected
  func controllerAdded(controller: FlutterViewController) {
    // Register plugins for the SECONDARY engine
    GeneratedPluginRegistrant.register(with: controller)
  }
}


Usage #

1. Initialize Display Manager #

import 'package:presentation_displays_hig/displays_manager.dart';

DisplayManager displayManager = DisplayManager();

2. List Connected Displays #

List<Display> displays = [];

Future<void> getDisplays() async {
    final values = await displayManager.getDisplays();
    if (values != null) {
        setState(() {
            displays = values;
        });
    }
}

3. Show Presentation #

Use the displayId from the list above and the routerName defined in your MySecondApp widget.

// Index 0 is usually the built-in screen, Index 1 is the external display
if (displays.length > 1) {
    await displayManager.showSecondaryDisplay(
        displayId: displays[1].displayId!, 
        routerName: "presentation"
    );
}

4. Transfer Data #

You can send Map or JSON data to the secondary screen.

await displayManager.transferDataToPresentation({
    "title": "Customer Order",
    "total": 150.00,
    "items": ["Apple", "Banana"]
});

5. Receive Data (Secondary Screen) #

In the widget running on the secondary screen (e.g., SecondaryDisplay), use the callback to receive data.

@override
Widget build(BuildContext context) {
  return SecondaryDisplay(
    callback: (argument) {
      // argument contains the Map/Data sent from the main screen
      setState(() {
        receivedData = argument;
      });
    },
    child: YourCustomWidget(data: receivedData),
  );
}

6. Hide Presentation #

await displayManager.hideSecondaryDisplay(displayId: displays[1].displayId!);

0
likes
160
points
--
downloads

Publisher

verified publisherhig.dev

Flutter plugin supports to run on two screens. It's basically a tablet connected to another screen via an HDMI or Wireless

Repository (GitHub)
View/report issues
Contributing

Documentation

API reference

License

BSD-2-Clause (license)

Dependencies

flutter

More

Packages that depend on presentation_displays_hig

Packages that implement presentation_displays_hig