skip to Main Content

Can’t enter fullscreen second time(flutter UI widget on click) in web chrome:

void requestFullScreen() {
  print("entering fullscreen");
  Future<void>? future = document.documentElement?.requestFullscreen();
  future?.catchError(
    (Object obj) {
      window.alert("Can't enter full screen mode, forbidden by browser with error: ${obj.toString()}");
      return;
    },
  );
}
void exitFullScreen() {
    print("exiting fullscreen");
    document.exitFullscreen();
}

void notActualFunctionButUserClickingOnWidgetFlow() {
    requestFullScreen();
    await Future.delayed(const Duration(seconds: 2));
    exitFullScreen();
    await Future.delayed(const Duration(seconds: 2));
    requestFullScreen();
    await Future.delayed(const Duration(seconds: 2));
    exitFullScreen();
}

So the story is the following:
First ‘enterFullscreen’ works fine, exits fine, but next fullscreen call throws

Uncaught (in promise) TypeError: Permissions check failed
at [dartx.requestFullscreen] (html_dart2js.dart:13993:11)
at Object.requestFullScreen (dio_adapter_web.dart:21:29)
at dio_adapter_web.dart:52:5
at Generator.next (<anonymous>)
at async_patch.dart:45:50
at _RootZone.runUnary (zone.dart:1661:54)
at _FutureListener.thenAwait.handleValue (future_impl.dart:162:18)
at handleValueCallback (future_impl.dart:846:44)
at _Future._propagateToListeners (future_impl.dart:875:13)
at [_complete] (future_impl.dart:638:7)
at future.dart:424:15
at internalCallback (isolate_helper.dart:48:11)

Why it’s alright to enter fullscreen first time, but for next you need permission, and how to request it?

I tried to do some ‘magic’ with:

window.navigator.permissions?.request({"name": "fullscreen"})

Actually, just crashes with any param, because not every browser seems to be capable of doing this new feature(according to other SOF questions), but there is no way to request fullscreen permission any other way, unless I’m missing something.

PS. It can be some kind of ‘you need to call specific widget.onclick’ or whatever, I can create demo project on request.

2

Answers


  1. Chosen as BEST ANSWER

    So, I shot myself into leg somewhere in my own code.

    To go fullscreen you need to apply 1 rule: user MUST click somewhere on the screen before you call goFullScreen impl. That's why it worked first time and did not worked second/third on my case. This is working example:

      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            backgroundColor: Theme.of(context).colorScheme.inversePrimary,
            title: Text("Demo"),
          ),
          floatingActionButton: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              FloatingActionButton.extended(
                onPressed: () {
                  document.documentElement?.requestFullscreen();
                },
                label: const Text('Request fullscreen'),
              ),
              FloatingActionButton.extended(
                onPressed: () {
                  document.exitFullscreen();
                },
                label: const Text('Exit fullscreen'),
              ),
            ],
          ),
        );
      }
    

    If your code throws you same error- your fullscreen method call was called not form user click, in case if you DID clicked- system think your action is not user input, rethink your widget tree.


  2. To pass the browser security check the user has to interact with your website before you make a call to requestFullscreen.

    We can solve this issue by showing a overlay which waits for the user to click before attempting to make the page fullscreen. It’s not the best solution but unfortunately it’s what you have to do.

    import 'dart:html'
        as html; // universal_html should be used instead of dart:html
    
    import 'package:flutter/material.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Web Fullscreen Demo',
          theme: ThemeData(
            colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
            useMaterial3: true,
          ),
          home: const MyHomePage(
            title: 'Flutter Web Fullscreen Demo',
          ),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      const MyHomePage({super.key, required this.title});
    
      final String title;
    
      @override
      State<MyHomePage> createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      Future<void> requestFullscreen() async {
        // create two elemenets.
        html.Element overlay = html.document.createElement(
          'div',
        );
        html.Element child = html.document.createElement(
          'div',
        );
    
        // set the label to tell the user that
        // they need to confirm they want to enter
        // fullscreen mode.
        child.text = 'Click to enter fullscreen mode.';
    
        // make the overlay take up the entire screen.
        overlay.style.width = '100vw';
        overlay.style.height = '100vh';
    
        // make sure it's shown above the Flutter app.
        overlay.style.position = 'absolute';
    
        // the following lines are just to make it
        // look better.
        overlay.style.opacity = '0.7';
        overlay.style.background = 'black';
        overlay.style.color = 'white';
        overlay.style.display = 'flex';
        overlay.style.alignItems = 'center';
        overlay.style.justifyContent = 'center';
    
        // add click event listener to overlay.
        overlay.addEventListener(
          'click',
          (event) {
            // calls requestFullscreen after the user clicks
            // on the overlay to pass the browser security check.
            html.document.documentElement?.requestFullscreen().then(
              (
                _,
              ) {
                // we managed to go into fullscreen mode,
                // we remove the overlay.
                overlay.remove();
              },
            ).catchError(
              (
                Object object,
              ) {
                // oops... an error occurred.
                html.window.alert(
                  'Error while trying to enter fullscreen mode: ${object.toString()}',
                );
                // remove the overlay again.
                overlay.remove();
              },
            );
          },
        );
    
        // add the elements created to document's body.
        // eg. make them appear on the page.
        overlay.append(
          child,
        );
    
        html.document.body?.append(
          overlay,
        );
      }
    
      void exitFullscreen() {
        html.document.exitFullscreen();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            backgroundColor: Theme.of(context).colorScheme.inversePrimary,
            title: Text(
              widget.title,
            ),
          ),
          floatingActionButton: FloatingActionButton.extended(
            onPressed: () {
              requestFullscreen();
            },
            tooltip: 'Enter fullscreen mode',
            label: const Text(
              'Request fullscreen',
            ),
            icon: const Icon(
              Icons.fullscreen,
            ),
          ),
        );
      }
    }
    

    If you have any quesstions please let me know.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search