Atomic Webview
A powerful, cross-platform WebView for Flutter supporting Android, iOS, Linux, macOS, Web, and Windows with a single unified API.
Platform Support
| Platform | Support | Engine |
|---|---|---|
| Android | ✅ | Android WebView (via webview_flutter) |
| iOS | ✅ | WKWebView (via webview_flutter) |
| Linux | ✅ | WebKitGTK (webkit2gtk-4.0 or 4.1) |
| macOS | ✅ | WKWebView (native) |
| Windows | ✅ | Microsoft WebView2 |
| Web | ✅ | Browser iframe |
Features
- Unified API: One
WebViewControllerworks across all 6 platforms. - Navigation: Load URLs, go back/forward, reload, and stop loading.
- JavaScript: Evaluate JavaScript and receive results.
- Asset Loading: Load local Flutter assets directly into the WebView.
- Native Performance: Uses each platform's native web engine.
- Desktop Windows: A separate native window with an optional Flutter-based title bar.
Requirements
Windows
Microsoft WebView2 Runtime must be installed. It ships by default with Windows 11 and recent Windows 10 updates.
Linux (Ubuntu / Debian)
Install the WebKitGTK development library. The plugin automatically detects which version is available:
# Ubuntu 22.04+ (preferred)
sudo apt install libwebkit2gtk-4.1-dev
# Ubuntu 20.04 / older systems
sudo apt install libwebkit2gtk-4.0-dev
Android
Minimum SDK version 19. Enable cleartext traffic in AndroidManifest.xml if needed for non-HTTPS URLs:
<application android:usesCleartextTraffic="true" ...>
Installation
Add atomic_webview to your pubspec.yaml:
dependencies:
atomic_webview: ^0.1.2
Then run:
flutter pub get
Quick Start
import 'package:flutter/material.dart';
import 'package:atomic_webview/atomic_webview.dart';
void main() {
runApp(const MaterialApp(home: MyWebViewPage()));
}
class MyWebViewPage extends StatefulWidget {
const MyWebViewPage({super.key});
@override
State<MyWebViewPage> createState() => _MyWebViewPageState();
}
class _MyWebViewPageState extends State<MyWebViewPage> {
final WebViewController _controller = WebViewController();
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
await _controller.init(
context: context,
setState: setState,
uri: Uri.parse('https://flutter.dev'),
);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Atomic Webview'),
actions: [
IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () => _controller.goBack(),
),
IconButton(
icon: const Icon(Icons.arrow_forward),
onPressed: () => _controller.goForward(),
),
IconButton(
icon: const Icon(Icons.refresh),
onPressed: () => _controller.reload(),
),
],
),
body: WebView(controller: _controller),
);
}
}
Desktop Note: On Linux, macOS, and Windows the WebView opens as a separate native window. The
WebViewwidget in your Flutter app displays a placeholder text while the native window is open.
API Reference
Initialization
await controller.init(
context: context, // BuildContext – required
setState: setState, // Required to trigger UI rebuild after init
uri: Uri.parse('https://example.com'),
);
Navigation
// Navigate to a URL
await controller.go(uri: Uri.parse('https://example.com'));
// Synchronous variant (fire-and-forget)
controller.goSync(uri: Uri.parse('https://example.com'));
// Back / Forward
await controller.goBack();
await controller.goForward();
// Reload / Stop
await controller.reload();
await controller.stop();
Loading Local Assets
// Load a Flutter asset (e.g. assets/index.html declared in pubspec.yaml)
await controller.loadAsset('assets/index.html');
JavaScript
// Evaluate JS and get the result as a String
String? title = await controller.evaluateJavaScript('document.title');
// Run JS without needing the result
await controller.evaluateJavaScript('console.log("hello")');
State Checks
bool ready = controller.is_init; // true after init() succeeds
bool onDesktop = controller.is_desktop; // Linux / macOS / Windows
bool onMobile = controller.is_mobile; // Android / iOS / Web
Desktop-Only: Advanced WebView API
On desktop platforms, webview_desktop_controller exposes additional native capabilities:
if (controller.is_desktop && controller.is_init) {
final wv = controller.webview_desktop_controller;
// Inject a script that runs at document creation
wv.addScriptToExecuteOnDocumentCreated('window.myFlag = true;');
// Set a custom user-agent suffix
await wv.setApplicationNameForUserAgent('MyApp/1.0');
// Listen for navigation events
wv.setOnHistoryChangedCallback((canGoBack, canGoForward) {
print('canGoBack=$canGoBack canGoForward=$canGoForward');
});
// Monitor URL changes
wv.addOnUrlRequestCallback((url) => print('Navigating to $url'));
// Open browser DevTools (Windows / macOS)
await wv.openDevToolsWindow();
// Post a message to a web page
await wv.postWebMessageAsString('hello from Flutter');
// Close the native window
wv.close();
// Wait for the window to close
await wv.onClose;
}
Desktop Title Bar
On desktop, a thin Flutter-powered title bar is displayed above the WebView. You can customise it in your app's main() with runWebViewTitleBarWidget:
import 'package:atomic_webview/atomic_webview.dart';
void main(List<String> args) {
// If this process was launched as the title-bar sub-engine, handle it here.
if (runWebViewTitleBarWidget(args)) return;
runApp(const MyApp());
}
This allows your app to provide a fully custom title bar using the TitleBarWebViewController mixin and TitleBarWebViewState widget.
Troubleshooting
| Problem | Solution |
|---|---|
MissingPluginException on Windows |
Ensure WebView2 Runtime is installed. Rebuild the app after adding the plugin. |
MissingPluginException on Linux |
Install libwebkit2gtk-4.1-dev (or 4.0-dev) and rebuild. |
Linux build error (webkit_javascript_result_get_js_value) |
Update to v0.1.2+; the build system now auto-selects the correct WebKit API. |
| WebView shows placeholder on desktop | This is correct – on desktop the WebView is a separate native window. |
| Blank page on Android | Add android:usesCleartextTraffic="true" for HTTP URLs. |
Libraries
- atomic_webview
- webview_controller/webview_controller
- webview_controller/webview_controller_web
- webview_desktop/src/create_configuration
- webview_desktop/src/message_channel
- webview_desktop/src/title_bar
- webview_desktop/src/webview
- webview_desktop/src/webview_impl
- webview_desktop/webview_desktop
- webview_desktop/webview_desktop_app
- webview_desktop/webview_desktop_web
- widget/webview
- widget/widget