runAppGuarded function

Future<void> runAppGuarded(
  1. Future<Widget> runner(), {
  2. required void onError(
    1. Object error,
    2. StackTrace? stackTrace
    )?,
  3. bool ensureInitialized = true,
  4. bool runAppAfterSetup = false,
})

Runs the application, catches all unhandled errors and exceptions, then passes them to the onError handler.

  • runner - A function that creates an application class object. In it you can make additional settings before running the application, for example, initializing Firebase.
  • onError - Handler for all unhandled errors and exceptions. Here you can send all errors to the error monitoring service.
  • ensureInitialized - should WidgetsFlutterBinding.ensureInitialized() be called immediately before app initialization (default: yes)?
  • runAppAfterSetup - should the application be created after setting up error handlers or before (default: before)?

Implementation

Future<void> runAppGuarded(
  Future<Widget> Function() runner, {
  required void Function(Object error, StackTrace? stackTrace)? onError,
  bool ensureInitialized = true,
  bool runAppAfterSetup = false,
}) async {
  if (ensureInitialized) {
    // Initialize widget bindings if necessary
    WidgetsFlutterBinding.ensureInitialized();
  }

  Widget? app;
  if (!runAppAfterSetup) {
    // Initializing and creating the application
    app = await runner();
  }

  bool inHandler = false;

  // Save prev handlers
  final FlutterExceptionHandler? oldOnError = FlutterError.onError;
  // final ErrorWidgetBuilder oldBuilder = ErrorWidget.builder;

  // --- Set new handlers

  // Catch Flutter errors
  FlutterError.onError = (FlutterErrorDetails details) {
    // Prevent an infinite loop and fall back to the original handler.
    if (inHandler) {
      try {
        oldOnError?.call(details);
      } catch (ex) {
        // intentionally left empty.
      }
      return;
    }

    // If there's an error in the error handler, we want to know about it.
    inHandler = true;

    if (onError != null) {
      onError(details.exception, details.stack);
    } else if (oldOnError != null) {
      oldOnError(details);
    }

    inHandler = false;
  };

  // Catch Dart errors
  PlatformDispatcher.instance.onError = (error, stack) {
    final handler = onError ?? oldOnError;
    handler?.call(error, stack);
    return true;
  };

  // Catch Isolate errors
  if (!kIsWeb) {
    // Catch any errors in the main() function.
    Isolate.current.addErrorListener(
      RawReceivePort((pair) async {
        final isolateError = pair as List<dynamic>;
        final handler = onError ?? oldOnError;
        handler?.call(
          isolateError.first.toString(),
          isolateError.last.toString(),
        );
      }).sendPort,
    );
  }

  // Run the application
  if (!runAppAfterSetup) {
    runApp(app!);
  } else {
    runApp(await runner());
  }
}