flutter_linux_webview
A Linux Desktop implementation for the webview_flutter (v3.0.4) plugin, powered by CEF (Chromium Embedded Framework).
webview_flutter is a federated package, consisting of an app-facing package, platform interface package, and platform implementation packages.
This plugin package provides the Linux implementation for webview_flutter (v3.0.4) using CEF.
Depending on the architecture, the following CEF binary distribution provided at https://cef-builds.spotifycdn.com/index.html is downloaded in the source directory of the plugin at the first build time:
- for x86_64: cef_binary_96.0.18+gfe551e4+chromium-96.0.4664.110_linux64_minimal
- for arm64: cef_binary_96.0.18+gfe551e4+chromium-96.0.4664.110_linuxarm64_minimal
Supported Platforms
We have confirmed that this plugin works on some platforms but hangs or crashes on others.
See validation_report.md for details on how the plugin was validated on different platforms.
As the report results show, there are stability issues:
- WebView creation appears to be somewhat unstable.
- Using Flutter 3.16.3 (latest as of 2023-12-13), the plugin test hangs on all platforms.
We should fix these issues.
Update: We have recognized that the cause of these issues is likely accessing the same GL Context from multiple threads.
Run the example project
Go to example/
.
Usage
1. Depend on it
Add flutter_linux_webview:^0.1.0
and webview_flutter:^3.0.4
as dependencies in your pubspec.yaml file.
Run these commands:
$ flutter pub add flutter_linux_webview:'^0.1.0'
$ flutter pub add webview_flutter:'^3.0.4'
This will add lines like this to your package's pubspec.yaml (and run an implicit flutter pub get):
dependencies:
webview_flutter: ^3.0.4
flutter_linux_webview: ^0.1.0
2. Modify linux/CMakeLists.txt of your application
You need to add the following command to linux/CMakeLists.txt
in your app:
include(flutter/ephemeral/.plugin_symlinks/flutter_linux_webview/linux/cmake/link_to_cef_library.cmake)
but must be placed after the following string:
add_executable(${BINARY_NAME})
The plugin will hang if above configuration is not added.
3. Import and Setup
Now in your Dart code, import these:
import 'package:webview_flutter/webview_flutter.dart';
import 'package:flutter_linux_webview/flutter_linux_webview.dart';
Before creating the first WebView, you must call LinuxWebViewPlugin.initialize.
You must also set "WebView.platform = LinuxWebView();" to configure WebView to use the Linux implementation.
After that, you can use a WebView widget.
In Flutter 3.10 or later (as of Flutter 3.13), you must call
LinuxWebViewPlugin.terminate when the application exits.
Prior to Flutter 3.10, you do not need to call LinuxWebViewPlugin.terminate because this plugin automatically exits.
See the example below.
Example
import 'dart:async';
// Required to use AppExitResponse for Fluter 3.10 or later
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:flutter_linux_webview/flutter_linux_webview.dart';
void main() {
// ensureInitialized() is required if the plugin is initialized before runApp()
WidgetsFlutterBinding.ensureInitialized();
// Run `LinuxWebViewPlugin.initialize()` first before creating a WebView.
LinuxWebViewPlugin.initialize(options: <String, String?>{
'user-agent': 'UA String',
'remote-debugging-port': '8888',
'autoplay-policy': 'no-user-gesture-required',
});
// Configure [WebView] to use the [LinuxWebView].
WebView.platform = LinuxWebView();
runApp(const MaterialApp(home: _WebViewExample()));
}
class _WebViewExample extends StatefulWidget {
const _WebViewExample({Key? key}) : super(key: key);
@override
_WebViewExampleState createState() => _WebViewExampleState();
}
class _WebViewExampleState extends State<_WebViewExample>
with WidgetsBindingObserver {
final Completer<WebViewController> _controller =
Completer<WebViewController>();
/// Prior to Flutter 3.10, comment out the following code since
/// [WidgetsBindingObserver.didRequestAppExit] does not exist.
// ===== begin: For Flutter 3.10 or later =====
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
Future<AppExitResponse> didRequestAppExit() async {
await LinuxWebViewPlugin.terminate();
return AppExitResponse.exit;
}
// ===== end: For Flutter 3.10 or later =====
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('flutter_linux_webview example'),
),
body: WebView(
initialUrl: 'https://flutter.dev',
initialCookies: const [
WebViewCookie(name: 'mycookie', value: 'foo', domain: 'flutter.dev')
],
onWebViewCreated: (WebViewController webViewController) {
_controller.complete(webViewController);
},
javascriptMode: JavascriptMode.unrestricted,
),
floatingActionButton: favoriteButton(),
);
}
Widget favoriteButton() {
return FutureBuilder<WebViewController>(
future: _controller.future,
builder: (BuildContext context,
AsyncSnapshot<WebViewController> controller) {
if (controller.hasData) {
return FloatingActionButton(
onPressed: () async {
final String useragent = (await controller.data!
.runJavascriptReturningResult('navigator.userAgent'));
final String title = (await controller.data!.getTitle())!;
final String url = (await controller.data!.currentUrl())!;
final String cookies = await (controller.data!
.runJavascriptReturningResult('document.cookie'));
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'userAgent: $useragent, title: $title, url: $url, cookie: $cookies'),
),
);
},
child: const Icon(Icons.favorite),
);
}
return Container();
});
}
}
The WebView behavior on Linux
On Linux, the behavior of some properties of WebView and some methods of WebViewController is different from that on Android/iOS due to limitations of the underlying browser or because some features have not yet been implemented.
Specification of properties of WebView on Linux
bool
allowsInlineMediaPlayback
This only works on iOS.
On Linux, same as Android, this setting is ignored.
See WebView.allowsInlineMediaPlayback
and WebSettings.allowsInlineMediaPlayback
for the original description.
Color?
backgroundColor
See WebView.backgroundColor
and CreationParams.backgroundColor
for the original description.
The color is used for the browser before a document is loaded and when no document color is specified. When the color is null the background is transparent. When the color is specified the alpha component must be either fully opaque (0xFF) or fully transparent (0x00). If the alpha component is fully opaque then the RGB components will be used as the background color. If the alpha component is fully transparent then transparent painting will be enabled.
bool?
debuggingEnabled
This property is not supported due to CEF incompatibility* and is ignored on Linux.
Alternatively, --remote-debugging-port
command line argument can be set
at CEF startup using LinuxWebViewPlugin.initialize.
See WebView.debuggingEnabled
and WebSettings.debuggingEnabled
for the original description.
*CEF Incompatibility:
In Android webview_flutter
, debuggingEnabled
can be dynamically
toggled enabled/disabled. However, in CEF, --remote-debugging-port
cannot be changed later once CEF has started.
bool?
gestureNavigationEnabled
This only works on iOS.
On Linux, same as Android, this setting is ignored.
See WebView.gestureNavigationEnabled
and WebSettings.gestureNavigationEnabled
for the original description.
Set<Factory<OneSequenceGestureRecognizer>>?
gestureRecognizers
This property is not implemented and it is not clear if it could be implemented.
See WebView.gestureRecognizers for the original description.
Note: This is not a WebView feature, but a PlatformViews feature. Also note that this plugin does not currently support touch devices.
List<WebViewCookie>
initialCookies
See WebView.initialCookies
and CreationParams.cookies
.
AutoMediaPlaybackPolicy
initialMediaPlaybackPolicy
This property is not supported due to CEF incompatibility* and is ignored on Linux.
Alternatively, --autoplay-policy=no-user-gesture-required
command line
argument can be set at CEF startup using LinuxWebViewPlugin.initialize.
See WebView.initialMediaPlaybackPolicy
and CreationParams.autoMediaPlaybackPolicy
for the original desciption.
*CEF Incompatibility:
In Android webview_flutter
, initialMediaPlaybackPolicy
is applied to
each WebView at its creation. However, in CEF,
--autoplay-policy=no-user-gesture-required
applies to all browsers once
CEF has started and cannot be changed later.
String?
initialUrl
See WebView.initialUrl
or CreationParams.initialUrl
.
On Linux, when it is null the webview will be created with loading "about:blank".
Set<JavascriptChannel>?
javascriptChannels
This property has not yet been implemented and is ignored on Linux.
TODO(Ino): implement javascriptChannels
.
See WebView.javascriptChannels
and CreationParams.javascriptChannelNames
for the original description.
JavascriptMode?
javascriptMode
This property has not yet been implemented and is ignored on Linux.
TODO(Ino): implement javascriptMode
.
See WebView.javascriptMode
and WebSettings.javascriptMode
for the original description.
Note: This property cannot be fully supported due to CEF incompatibility.
In Android webview_flutter
, javscriptMode
can be changed dynamically.
However, in CEF, once a browser is created, it is not possible to change
whether javascript is enabled or disabled unless the browser is recreated.
bool?
navigationDelegate
This property has not yet been implemented and is ignored on Linux.
TODO(Ino): implement navigationDelegate
.
See WebView.navigationDelegate
and WebSettings.hasNavigationDelegate
for the original description.
PageFinishedCallback?
onPageFinished
PageStartedCallback?
onPageStarted
bool?
onProgress
See WebView.onProgress.
WebResourceErrorCallback?
onWebResourceError
See WebView.onWebResourceError.
On Linux, currently only errorCode
and description
are supported.
domain
, failingUrl
and errorType
are not yet supported.
TODO(Ino): improve onWebResourceError
support.
WebViewCreatedCallback?
onWebViewCreated
This is the only interface to get WebViewController.
String?
userAgent
This property is not supported due to CEF incompatibility* and is ignored on Linux.
Alternatively, --user-agent="UA string"
command line argument can be set
at CEF startup using LinuxWebViewPlugin.initialize.
See WebView.userAgent
and CreationParams.userAgent
for the original description.
*CEF Incompatibility:
In Android webview_flutter
, userAgent
can be set for each WebView and
can be changed dynamically. However, in CEF, --user-agent
applies to all
browsers once CEF has started and cannot be changed later.
bool?
zoomEnabled
This property is not supported due to CEF incompatibility* and is ignored on Linux.
Alternatively, --disable-pinch
command line argument can be set at CEF
startup using LinuxWebViewPlugin.initialize.
See WebView.zoomEnabled
and WebSettings.zoomEnabled
for the original description.
*CEF Incompatibility:
In Android webview_flutter
, zoomEnabled
can be set for each WebView
and can be changed dynamically. However, in CEF, --disable-pinch
applies
to all browsers once CEF has started and cannot be changed later.
Note: This plugin does not currently support touch devices.
Specification of methods of WebViewController on Linux
The following methods are the same for Android/iOS.
Future<bool>
canGoBack()Future<void>
goBack()Future<bool>
canGoForward()Future<void>
goForward()Future<String?>
currentUrl()Future<String?>
getTitle()Future<void>
reload()Future<String>
runJavascriptReturningResult(String javaScriptString)Future<void>
runJavascript(String javaScriptString)Future<String>
evaluateJavascript(String javascriptString)
Some methods are not implemented or behave differently from Android/iOS:
Future<void>
loadUrl(String url, {Map<String, String>? headers})
See WebViewLinuxPlatformController.loadUrl for details.
Limitations on Linux
Requests with headers
cannot be made for an origin different from the current page.
You must first navigate to the request origin (scheme + domain) using some other mechanism (WebViewController.loadUrl without headers, link click, etc).
Known bug
The timing of when Future is resolved is different from that expected on Android/iOS (see the integration test). When loadUrl
is resolved, the new URL is expected to be available in currentUrl
, but the current implementation does not do so.
Future<void>
loadRequest(WebViewRequest request)
See WebViewLinuxPlatformController.loadRequest for details.
Limitations on Linux
Requests cannot be made for an origin different from the current page. You must first navigate to the request origin (scheme + domain) using some other mechanism (WebViewController.loadUrl without headers, link click, etc).
Known bug (?)
The timing of when Future is resolved is different from Android/iOS.
Immediately after this method is resolved, the new URL cannot yet be obtained with currentUrl
.
Future<void>
loadHtmlString(String html, {String? baseUrl})
See WebViewLinuxPlatformController.loadHtmlString for details.
Limitations on Linux
baseUrl
is not supported because the underlying browser does not support baseUrl.
Known bug (?)
The timing of when Future is resolved is different from Android/iOS.
Immediately after this method is resolved, the new URL cannot yet be obtained with currentUrl
.
Future<void>
loadFile(String absoluteFilePath)
See WebViewLinuxPlatformController.loadFile for details.
Known bug (?)
The timing of when Future is resolved is different from Android/iOS.
Immediately after this method is resolved, the new URL cannot yet be obtained with currentUrl
.
Future<void>
loadFlutterAsset(String key)
See WebViewLinuxPlatformController.loadFlutterAsset for details.
Known bug (?)
The timing of when Future is resolved is different from Android/iOS.
Immediately after this method is resolved, the new URL cannot yet be obtained with currentUrl
.
Future<void>
clearCache()
Not supported because the underlying browser does not support it.
Future<int>
getScrollX()
Not implemented on Linux. Will be supported in the future.
Future<int>
getScrollY()
Not implemented on Linux. Will be supported in the future.
Future<void>
scrollBy(int x, int y)
Not implemented on Linux. Will be supported in the future.
Future<void>
scrollTo(int x, int y)
Not implemented on Linux. Will be supported in the future.
TODO
javascriptChannels
navigationDelegate
javascriptMode
onWebResourceError
supportgetScrollX
,getScrollY
,scrollBy
,scrollTo()
Contributing
Thank you for your interest in contributing.
However, currently, we are not accepting contributions, and we are unable to respond to pull requests.
License
flutter_linux_webview is licensed under the 3-Clause BSD License, see LICENSE.
Portions of flutter_linux_webview include third-party software, each of which is licensed under its respective license. See third_party_base/README.md for more information.