Controller
WebViewController is the central object. A controller can be attached to one WebViewWidget at a time and delegates all work to the active platform implementation. On platforms with offscreen support, loading, navigation callbacks, JavaScript, and channels can also run before or without attaching a widget.
Construction
Section titled “Construction”Use the default constructor for common behavior:
final controller = WebViewController();Use fromPlatformCreationParams when the platform needs creation-time options:
PlatformWebViewControllerCreationParams params = const PlatformWebViewControllerCreationParams();
if (WebViewPlatform.instance is LinuxWebViewPlatform) { params = const LinuxWebViewControllerCreationParams( developerExtrasEnabled: true, pageCacheEnabled: true, );}
final controller = WebViewController.fromPlatformCreationParams(params);Use fromPlatform only when you already constructed a platform controller yourself:
final platformController = WindowsWebViewController( const WindowsWebViewControllerCreationParams( popupWindowPolicy: WindowsPopupWindowPolicy.sameWindow, ),);
final controller = WebViewController.fromPlatform(platformController);Offscreen Native Use
Section titled “Offscreen Native Use”Use an owning session when no visible WebView is needed:
import 'dart:async';
final session = await OffscreenWebViewSession.create();final controller = session.controller;final loaded = Completer<void>();
try { await controller.setJavaScriptMode(JavaScriptMode.unrestricted); await controller.setNavigationDelegate( NavigationDelegate(onPageFinished: (_) => loaded.complete()), ); await controller.loadHtmlString('<script>window.price = 42;</script>'); await loaded.future;
final price = await controller.callAsyncJavaScript('return window.price;');} finally { await session.close();}OffscreenWebViewSession.create throws UnsupportedError on OHOS and Web. Android, iOS, macOS, Windows, and Linux can operate without a widget; the owned controller may still be displayed before the session is closed. close() is idempotent and permanently releases the session resources without adding dispose() to the common controller API.
Offscreen execution still belongs to the application’s Flutter engine, platform thread, window, and process lifecycle. It is not a background service or a separate isolate, and operating-system background restrictions still apply. Do not retain or use the owned controller after close() starts.
Loading Content
Section titled “Loading Content”| Method | Purpose | Notes |
|---|---|---|
loadRequest(Uri uri, {method, headers, body}) |
Load a URL or submit a request. | uri must have a scheme. See platform limits below. |
loadFile(String absoluteFilePath) |
Load a local file from the device. | Unsupported on web. |
loadFlutterAsset(String key) |
Load an asset declared in pubspec.yaml. |
Web resolves to assets/<key>. |
loadHtmlString(String html, {String? baseUrl}) |
Load an in-memory HTML document. | baseUrl is used for relative URLs. |
Request Limits
Section titled “Request Limits”| Platform | GET headers |
POST body |
POST custom headers |
|---|---|---|---|
| Android | Supported | Supported | Not supported by Android postUrl; throws. |
| iOS | Supported | Supported | Supported by URLRequest. |
| macOS | Supported | Supported | Supported by URLRequest. |
| Windows | Supported | Supported | Supported by WebView2 request bridge. |
| Linux | Supported | Supported | Supported by WebKitGTK bridge. |
| OHOS | Supported for GET |
Supported | Not supported by ArkWeb postUrl; throws UnsupportedError. |
| Web | Supported through fetch path |
Supported through fetch path |
Subject to CORS preflight and response policies. |
Navigation State
Section titled “Navigation State”final current = await controller.currentUrl();final title = await controller.getTitle();
if (await controller.canGoBack()) { await controller.goBack();}
await controller.reload();canGoBack and canGoForward reflect the platform history state. On web, webview_all_web maintains a logical history for loads initiated through the controller.
JavaScript
Section titled “JavaScript”await controller.setJavaScriptMode(JavaScriptMode.unrestricted);await controller.runJavaScript('document.body.dataset.ready = "true";');
final result = await controller.runJavaScriptReturningResult('1 + 2');runJavaScriptReturningResult rejects null and undefined results, matching the platform interface contract. Complex JavaScript values must be serializable by the engine. The web implementation serializes through JSON.stringify.
JavaScript Channels
Section titled “JavaScript Channels”await controller.addJavaScriptChannel( 'Host', onMessageReceived: (JavaScriptMessage message) { debugPrint(message.message); },);
await controller.runJavaScript('Host.postMessage("ping")');Channel names must be valid JavaScript identifiers on native implementations that inject named objects. Avoid user-provided channel names unless you validate them.
Scrolling
Section titled “Scrolling”await controller.scrollTo(0, 0);await controller.scrollBy(0, 300);
final position = await controller.getScrollPosition();
await controller.setOnScrollPositionChange((ScrollPositionChange change) { debugPrint('${change.x}, ${change.y}');});Scrollbar visibility is guarded by supportsSetScrollBarsEnabled():
if (await controller.supportsSetScrollBarsEnabled()) { await controller.setVerticalScrollBarEnabled(false); await controller.setHorizontalScrollBarEnabled(false);}Since webview_all 1.3.2, scrollbar rendering remains engine-specific. macOS
reports this capability as unsupported because public WKWebView does not
expose its internal scroll view. Web and Windows implement visibility with
injected CSS.
Appearance and Interaction
Section titled “Appearance and Interaction”| Method | Behavior |
|---|---|
setBackgroundColor(Color color) |
Applies an engine background color where available. macOS uses a native API on 12+ and logs/no-ops on earlier versions. |
enableZoom(bool enabled) |
Toggles platform zoom behavior. macOS uses native magnification. |
setUserAgent(String? userAgent) |
Overrides the user agent where the engine allows it. Web logs once and ignores non-null overrides. |
getUserAgent() |
Returns the effective or platform-reported user agent when available. |
setOverScrollMode(WebViewOverScrollMode mode) |
Maps to native overscroll where possible or CSS overscroll-behavior on CSS-backed implementations. macOS logs/no-ops because no public API is available. |
Platform Controller Access
Section titled “Platform Controller Access”The platform field is the escape hatch for engine-specific APIs:
switch (controller.platform) { case WindowsWebViewController windows: await windows.openDevTools(); case LinuxWebViewController linux: await linux.setDeveloperExtrasEnabled(true); case OhosWebViewController ohos: await ohos.setTextZoom(110); case WebWebViewController web: await web.setIFrameReferrerPolicy('no-referrer');}Always guard casts by platform type. Flutter tests, desktop runners, and web builds can register different platform implementations.