blob: e19f24103cdf4854ac11df3152a9a05320ac5176 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// TODO(yjbanov): rename this file to web_only_api.dart.
// https://github.com/flutter/flutter/issues/100394
// Rather than extending this file with new APIs, we
// should instead use js interop.
// This file contains extra web-only API that non-web engines do not have.
//
// Why have web-only API?
//
// Because all Dart code is compiled (and tree shaken) as a single compilation
// unit it only has one entry-point - the `main()` function of the Flutter
// app. The top-level `main()` is generated by Flutter tool and it needs to
// ask the engine to initialize itself before calling the handwritten `main()`
// function of the app itself. To do that, it needs something to call. The
// mobile engine doesn't provide a function like that because the application
// starts from the Java (Android) or Objective-C (iOS). Any initial
// configuration can be done in Java and the engine's C++ code prior to
// calling Dart's `main()`.
part of ui;
/// Performs one-time initialization of the web environment that supports the
/// Flutter framework.
///
/// This is only available on the Web, as native Flutter configures the
/// environment in the native embedder.
Future<void> webOnlyInitializePlatform() async {
await engine.initializeEngine();
}
/// Initializes essential bits of the engine before it fully initializes.
/// When [didCreateEngineInitializer] is set, it delegates engine initialization
/// and app startup to the programmer.
/// Else, it immediately triggers the full engine + app bootstrap.
///
/// This method is called by the flutter_tools package, from the entrypoint that
/// it generates around the main method provided by the programmer. See:
/// * https://github.com/flutter/flutter/blob/2bd3e0d914854aa8c12e933f25c5fd8532ae5571/packages/flutter_tools/lib/src/build_system/targets/web.dart#L135-L163
/// * https://github.com/flutter/flutter/blob/61fb2de52c7bdac19b7f2f74eaf3f11237e1e91d/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart#L460-L485
///
/// This function first calls [engine.initializeEngineServices] so the engine
/// can prepare the js-interop layer that is used by web apps (instead of the
/// old `ui.webOnlyFoo` methods/getters).
///
/// It then creates a JsObject that is passed to the [didCreateEngineInitializer]
/// JS callback, to delegate bootstrapping the app to the programmer.
///
/// If said callback is not defined, this assumes that the Flutter Web app is
/// initializing "automatically", as was normal before this feature was
/// introduced. This will immediately run the initEngine and runApp methods
/// (via [engine.AppBootstrap.now]).
///
/// This is the only bit of `dart:ui` that should be directly called by Flutter
/// web apps. Everything else should go through the JS-interop layer created in
/// `engine.warmup`.
///
/// This method should NOT trigger the download of any additional resources
/// (except when the app is in "autoStart" mode).
Future<void> webOnlyWarmupEngine({
Function? registerPlugins,
Function? runApp,
}) async {
// Create the object that knows how to bootstrap an app from JS and Dart.
final engine.AppBootstrap bootstrap = engine.AppBootstrap(
initEngine: () async {
await engine.initializeEngineServices();
}, runApp: () async {
if (registerPlugins != null) {
registerPlugins();
}
await engine.initializeEngineUi();
if (runApp != null) {
runApp();
}
},
);
// Should the app "autoStart"?
bool autoStart = true;
try {
autoStart = engine.didCreateEngineInitializer == null;
} catch (e) {
// Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'loader')
autoStart = true;
}
if (autoStart) {
// The user does not want control of the app, bootstrap immediately.
print('Flutter Web Bootstrap: Auto');
await bootstrap.autoStart();
} else {
// Yield control of the bootstrap procedure to the user.
print('Flutter Web Bootstrap: Programmatic');
engine.didCreateEngineInitializer!(bootstrap.prepareEngineInitializer());
}
}
/// Emulates the `flutter test` environment.
///
/// When set to true, the engine will emulate a specific screen size, and always
/// use the "Ahem" font to reduce test flakiness and dependence on the test
/// environment.
bool get debugEmulateFlutterTesterEnvironment =>
_debugEmulateFlutterTesterEnvironment;
set debugEmulateFlutterTesterEnvironment(bool value) {
_debugEmulateFlutterTesterEnvironment = value;
if (_debugEmulateFlutterTesterEnvironment) {
const Size logicalSize = Size(800.0, 600.0);
engine.window.webOnlyDebugPhysicalSizeOverride =
logicalSize * window.devicePixelRatio;
}
engine.debugDisableFontFallbacks = value;
}
bool _debugEmulateFlutterTesterEnvironment = false;
/// Provides the asset manager.
// TODO(yjbanov): this function should not return a private type. Instead, we
// should create a public interface for the returned value that's
// implemented by the engine.
// https://github.com/flutter/flutter/issues/100394
engine.AssetManager get webOnlyAssetManager => engine.assetManager;
/// Sets the handler that forwards platform messages to web plugins.
///
/// This function exists because unlike mobile, on the web plugins are also
/// implemented using Dart code, and that code needs a way to receive messages.
void webOnlySetPluginHandler(Future<void> Function(String, ByteData?, PlatformMessageResponseCallback?) handler) {
engine.pluginMessageCallHandler = handler;
}
/// A registry for factories that create platform views.
class PlatformViewRegistry {
/// Register [viewTypeId] as being creating by the given [viewFactory].
/// [viewFactory] can be any function that takes an integer and returns an
/// `HTMLElement` DOM object.
bool registerViewFactory(String viewTypeId,
Object Function(int viewId) viewFactory,
{bool isVisible = true}) {
// TODO(web): Deprecate this once there's another way of calling `registerFactory` (js interop?)
return engine.platformViewManager
.registerFactory(viewTypeId, viewFactory, isVisible: isVisible);
}
}
/// The platform view registry for this app.
final PlatformViewRegistry platformViewRegistry = PlatformViewRegistry();