webview_flutter_ext 0.3.30

  • Readme
  • Changelog
  • Example
  • Installing
  • 52

Clone from Webview_flutter (Developers Preview) #

pub package

A Flutter plugin that provides a WebView widget.

On iOS the WebView widget is backed by a WKWebView; On Android the WebView widget is backed by a WebView.

Developers Preview Status #

The plugin relies on Flutter's new mechanism for embedding Android and iOS views. As that mechanism is currently in a developers preview, this plugin should also be considered a developers preview.

Known issues are tagged with the platform-views and/or webview labels.

To use this plugin on iOS you need to opt-in for the embedded views preview by adding a boolean property to the app's Info.plist file, with the key io.flutter.embedded_views_preview and the value YES.

Keyboard support - not ready for production use #

Keyboard support within webviews is experimental. The Android version relies on some low-level knobs that have not been well tested on a broad spectrum of devices yet, and therefore it is not recommended to rely on webview keyboard in production apps yet. See the webview-keyboard for known issues with keyboard input.

Setup #

iOS #

Opt-in to the embedded views preview by adding a boolean property to the app's Info.plist file with the key io.flutter.embedded_views_preview and the value YES.

Usage #

Add webview_flutter as a dependency in your pubspec.yaml file.

You can now include a WebView widget in your widget tree. See the WebView widget's Dartdoc for more details on how to use the widget.

clone from webView_flutter #

0.3.22+1 #

  • Update the setAndGetScrollPosition to use hard coded values and add a pumpAndSettle call.

0.3.22 #

  • Add support for passing a failing url.

0.3.21 #

  • Enable programmatic scrolling using Android's WebView.scrollTo & iOS WKWebView.scrollView.contentOffset.

0.3.20+2 #

  • Fix CocoaPods podspec lint warnings.

0.3.20+1 #

0.3.20 #

  • Added support for receiving web resource loading errors. See WebView.onWebResourceError.

0.3.19+10 #

  • Replace deprecated getFlutterEngine call on Android.

0.3.19+9 #

  • Remove example app's iOS workspace settings.

0.3.19+8 #

  • Make the pedantic dev_dependency explicit.

0.3.19+7 #

  • Remove the Flutter SDK constraint upper bound.

0.3.19+6 #

  • Enable opening links that target the "_blank" window (links open in same window).

0.3.19+5 #

  • On iOS, always keep contentInsets of the WebView to be 0.
  • Fix XCTest case to follow XCTest naming convention.

0.3.19+4 #

  • On iOS, fix the scroll view content inset is automatically adjusted. After the fix, the content position of the WebView is customizable by Flutter.
  • Fix an iOS 13 bug where the scroll indicator shows at random location.

0.3.19+3 #

  • Setup XCTests.

0.3.19+2 #

  • Migrate from deprecated BinaryMessages to ServicesBinding.instance.defaultBinaryMessenger.

0.3.19+1 #

  • Raise min Flutter SDK requirement to the latest stable. v2 embedding apps no longer need to special case their Flutter SDK requirement like they have since v0.3.15+3.

0.3.19 #

  • Add setting for iOS to allow gesture based navigation.

0.3.18+1 #

  • Be explicit that keyboard is not ready for production in README.md.

0.3.18 #

  • Add support for onPageStarted event.
  • Remove the deprecated author: field from pubspec.yaml
  • Migrate to the new pubspec platforms manifest.
  • Require Flutter SDK 1.10.0 or greater.

0.3.17 #

  • Fix pedantic lint errors. Added missing documentation and awaited some futures in tests and the example app.

0.3.16 #

  • Add support for async NavigationDelegates. Synchronous NavigationDelegates should still continue to function without any change in behavior.

0.3.15+3 #

  • Re-land support for the v2 Android embedding. This correctly sets the minimum SDK to the latest stable and avoid any compile errors. WARNING: the V2 embedding itself still requires the current Flutter master channel (flutter/flutter@1d4d63a) for text input to work properly on all Android versions.

0.3.15+2 #

  • Remove AndroidX warnings.

0.3.15+1 #

  • Revert the prior embedding support add since it requires an API that hasn't rolled to stable.

0.3.15 #

  • Add support for the v2 Android embedding. This shouldn't affect existing functionality. Plugin authors who use the V2 embedding can now register the plugin and expect that it correctly responds to app lifecycle changes.

0.3.14+2 #

  • Define clang module for iOS.

0.3.14+1 #

  • Allow underscores anywhere for Javascript Channel name.

0.3.14 #

  • Added a getTitle getter to WebViewController.

0.3.13 #

  • Add an optional userAgent property to set a custom User Agent.

0.3.12+1 #

  • Temporarily revert getTitle (doing this as a patch bump shortly after publishing).

0.3.12 #

  • Added a getTitle getter to WebViewController.

0.3.11+6 #

  • Calling destroy on Android webview when flutter webview is getting disposed.

0.3.11+5 #

  • Reduce compiler warnings regarding iOS9 compatibility by moving a single method back into a @available block.

0.3.11+4 #

  • Removed noisy log messages on iOS.

0.3.11+3 #

  • Apply the display listeners workaround that was shipped in 0.3.11+1 on all Android versions prior to P.

0.3.11+2 #

  • Add fix for input connection being dropped after a screen resize on certain Android devices.

0.3.11+1 #

  • Work around a bug in old Android WebView versions that was causing a crash when resizing the webview on old devices.

0.3.11 #

  • Add an initialAutoMediaPlaybackPolicy setting for controlling how auto media playback is restricted.

0.3.10+5 #

  • Add dependency on androidx.annotation:annotation:1.0.0.

0.3.10+4 #

  • Add keyboard text to README.

0.3.10+3 #

  • Don't log an unknown setting key error for 'debuggingEnabled' on iOS.

0.3.10+2 #

  • Fix InputConnection being lost when combined with route transitions.

0.3.10+1 #

  • Add support for simultaenous Flutter TextInput and WebView text fields.

0.3.10 #

  • Add partial WebView keyboard support for Android versions prior to N. Support for UIs that also have Flutter TextInput fields is still pending. This basic support currently only works with Flutter master. The keyboard will still appear when it previously did not when run with older versions of Flutter. But if the WebView is resized while showing the keyboard the text field will need to be focused multiple times for any input to be registered.

0.3.9+2 #

  • Update Dart code to conform to current Dart formatter.

0.3.9+1 #

  • Add missing template type parameter to invokeMethod calls.
  • Bump minimum Flutter version to 1.5.0.
  • Replace invokeMethod with invokeMapMethod wherever necessary.

0.3.9 #

  • Allow external packages to provide webview implementations for new platforms.

0.3.8+1 #

0.3.8 #

  • Add debuggingEnabled property.

0.3.7+1 #

  • Fix an issue where JavaScriptChannel messages weren't sent from the platform thread on Android.

0.3.7 #

  • Fix loadUrlWithHeaders flaky test.

0.3.6+1 #

  • Remove un-used method params in webview_flutter

0.3.6 #

  • Add an optional headers field to the controller.

0.3.5+5 #

  • Fixed error in documentation of javascriptChannels.

0.3.5+4 #

  • Fix bugs in the example app by updating it to use a StatefulWidget.

0.3.5+3 #

  • Make sure to post javascript channel messages from the platform thread.

0.3.5+2 #

  • Fix crash from NavigationDelegate on later versions of Android.

0.3.5+1 #

  • Fix a bug where updates to onPageFinished were ignored.

0.3.5 #

  • Added an onPageFinished callback.

0.3.4 #

  • Support specifying navigation delegates that can prevent navigations from being executed.

0.3.3+2 #

  • Exclude LongPress handler from semantics tree since it does nothing.

0.3.3+1 #

  • Fixed a memory leak on Android - the WebView was not properly disposed.

0.3.3 #

  • Add clearCache method to WebView controller.

0.3.2+1 #

  • Log a more detailed warning at build time about the previous AndroidX migration.

0.3.2 #

  • Added CookieManager to interface with WebView cookies. Currently has the ability to clear cookies.

0.3.1 #

  • Added JavaScript channels to facilitate message passing from JavaScript code running inside the WebView to the Flutter app's Dart code.

0.3.0 #

  • Breaking change. Migrate from the deprecated original Android Support Library to AndroidX. This shouldn't result in any functional changes, but it requires any Android apps using this plugin to also migrate if they're using the original support library.

0.2.0 #

  • Added a evaluateJavascript method to WebView controller.
  • (BREAKING CHANGE) Renamed the JavaScriptMode enum to JavascriptMode, and the WebView javasScriptMode parameter to javascriptMode.

0.1.2 #

  • Added a reload method to the WebView controller.

0.1.1 #

  • Added a currentUrl accessor for the WebView controller to look up what URL is being displayed.

0.1.0+1 #

  • Fix null crash when initialUrl is unset on iOS.

0.1.0 #

  • Add goBack, goForward, canGoBack, and canGoForward methods to the WebView controller.

0.0.1+1 #

  • Fix case for "FLTWebViewFlutterPlugin" (iOS was failing to buld on case-sensitive file systems).

0.0.1 #

  • Initial release.


// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// ignore_for_file: public_member_api_docs

import 'dart:async';
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';

void main() => runApp(MaterialApp(home: WebViewExample()));

const String kNavigationExamplePage = '''
<!DOCTYPE html><html>
<head><title>Navigation Delegate Example</title></head>
The navigation delegate is set to block navigation to the youtube website.
<ul><a href="https://www.youtube.com/">https://www.youtube.com/</a></ul>
<ul><a href="https://www.google.com/">https://www.google.com/</a></ul>

class WebViewExample extends StatefulWidget {
  _WebViewExampleState createState() => _WebViewExampleState();

String text = """

class SwitchWidget extends StatefulWidget {
  State<StatefulWidget> createState() {
    return SwitchWidgetState();

class SwitchWidgetState extends State<SwitchWidget> {
  bool play;

  void initState() {
    play = false;

  Widget _getChild() {
    if (play) {
      final Completer<WebViewController> _controller =
      return WebView(
        initialUrl: 'about:blank',
        initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
        supportVideoFullScreen: true,
        javascriptMode: JavascriptMode.unrestricted,
        onWebViewCreated: (WebViewController webViewController) {
        debuggingEnabled: false,
        onPageStarted: (String url) {
//            print('Page started loading: $url');
        onPageFinished: (String url) {
              (value) => value.evaluateJavascript('javascript:playVideo()'));
        gestureNavigationEnabled: true,
    return InkWell(
        onTap: () {
          setState(() {
            play = true;
        child: Center(
          child: Icon(
            color: Colors.black,

  Widget build(BuildContext context) {
    return AspectRatio(
      aspectRatio: 16 / 9,
      child: _getChild(),

class _WebViewExampleState extends State<WebViewExample> {
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter WebView example'),
      // We're using a Builder here so we have a context that is below the Scaffold
      // to allow calling Scaffold.of(context) so we can show a snackbar.
      body: Builder(builder: (BuildContext context) {
        return ListView.builder(
          itemBuilder: (context, index) {
            return SwitchWidget();
          itemCount: 30,

  JavascriptChannel _toasterJavascriptChannel(BuildContext context) {
    return JavascriptChannel(
        name: 'Toaster',
        onMessageReceived: (JavascriptMessage message) {
            SnackBar(content: Text(message.message)),


enum MenuOptions {

class SampleMenu extends StatelessWidget {

  final Future<WebViewController> controller;
  final CookieManager cookieManager = CookieManager();

  Widget build(BuildContext context) {
    return FutureBuilder<WebViewController>(
      future: controller,
          (BuildContext context, AsyncSnapshot<WebViewController> controller) {
        return PopupMenuButton<MenuOptions>(
          onSelected: (MenuOptions value) {
            switch (value) {
              case MenuOptions.showUserAgent:
                _onShowUserAgent(controller.data, context);
              case MenuOptions.listCookies:
                _onListCookies(controller.data, context);
              case MenuOptions.clearCookies:
              case MenuOptions.addToCache:
                _onAddToCache(controller.data, context);
              case MenuOptions.listCache:
                _onListCache(controller.data, context);
              case MenuOptions.clearCache:
                _onClearCache(controller.data, context);
              case MenuOptions.navigationDelegate:
                _onNavigationDelegateExample(controller.data, context);
          itemBuilder: (BuildContext context) => <PopupMenuItem<MenuOptions>>[
              value: MenuOptions.showUserAgent,
              child: const Text('Show user agent'),
              enabled: controller.hasData,
            const PopupMenuItem<MenuOptions>(
              value: MenuOptions.listCookies,
              child: Text('List cookies'),
            const PopupMenuItem<MenuOptions>(
              value: MenuOptions.clearCookies,
              child: Text('Clear cookies'),
            const PopupMenuItem<MenuOptions>(
              value: MenuOptions.addToCache,
              child: Text('Add to cache'),
            const PopupMenuItem<MenuOptions>(
              value: MenuOptions.listCache,
              child: Text('List cache'),
            const PopupMenuItem<MenuOptions>(
              value: MenuOptions.clearCache,
              child: Text('Clear cache'),
            const PopupMenuItem<MenuOptions>(
              value: MenuOptions.navigationDelegate,
              child: Text('Navigation Delegate example'),

  void _onShowUserAgent(
      WebViewController controller, BuildContext context) async {
    // Send a message with the user agent string to the Toaster JavaScript channel we registered
    // with the WebView.
    await controller.evaluateJavascript(
        'Toaster.postMessage("User Agent: " + navigator.userAgent);');

  void _onListCookies(
      WebViewController controller, BuildContext context) async {
    final String cookies =
        await controller.evaluateJavascript('document.cookie');
      content: Column(
        mainAxisAlignment: MainAxisAlignment.end,
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          const Text('Cookies:'),

  void _onAddToCache(WebViewController controller, BuildContext context) async {
    await controller.evaluateJavascript(
        'caches.open("test_caches_entry"); localStorage["test_localStorage"] = "dummy_entry";');
    Scaffold.of(context).showSnackBar(const SnackBar(
      content: Text('Added a test entry to cache.'),

  void _onListCache(WebViewController controller, BuildContext context) async {
    await controller.evaluateJavascript('caches.keys()'
        '.then((cacheKeys) => JSON.stringify({"cacheKeys" : cacheKeys, "localStorage" : localStorage}))'
        '.then((caches) => Toaster.postMessage(caches))');

  void _onClearCache(WebViewController controller, BuildContext context) async {
    await controller.clearCache();
    Scaffold.of(context).showSnackBar(const SnackBar(
      content: Text("Cache cleared."),

  void _onClearCookies(BuildContext context) async {
    final bool hadCookies = await cookieManager.clearCookies();
    String message = 'There were cookies. Now, they are gone!';
    if (!hadCookies) {
      message = 'There are no cookies.';
      content: Text(message),

  void _onNavigationDelegateExample(
      WebViewController controller, BuildContext context) async {
    final String contentBase64 =
        base64Encode(const Utf8Encoder().convert(kNavigationExamplePage));
    await controller.loadUrl('data:text/html;base64,$contentBase64');

  Widget _getCookieList(String cookies) {
    if (cookies == null || cookies == '""') {
      return Container();
    final List<String> cookieList = cookies.split(';');
    final Iterable<Text> cookieWidgets =
        cookieList.map((String cookie) => Text(cookie));
    return Column(
      mainAxisAlignment: MainAxisAlignment.end,
      mainAxisSize: MainAxisSize.min,
      children: cookieWidgets.toList(),

class NavigationControls extends StatelessWidget {
  const NavigationControls(this._webViewControllerFuture)
      : assert(_webViewControllerFuture != null);

  final Future<WebViewController> _webViewControllerFuture;

  Widget build(BuildContext context) {
    return FutureBuilder<WebViewController>(
      future: _webViewControllerFuture,
          (BuildContext context, AsyncSnapshot<WebViewController> snapshot) {
        final bool webViewReady =
            snapshot.connectionState == ConnectionState.done;
        final WebViewController controller = snapshot.data;
        return Row(
          children: <Widget>[
              icon: const Icon(Icons.arrow_back_ios),
              onPressed: !webViewReady
                  ? null
                  : () async {
                      if (await controller.canGoBack()) {
                        await controller.goBack();
                      } else {
                          const SnackBar(content: Text("No back history item")),
              icon: const Icon(Icons.arrow_forward_ios),
              onPressed: !webViewReady
                  ? null
                  : () async {
                      if (await controller.canGoForward()) {
                        await controller.goForward();
                      } else {
                          const SnackBar(
                              content: Text("No forward history item")),
              icon: const Icon(Icons.replay),
              onPressed: !webViewReady
                  ? null
                  : () {

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:

  webview_flutter_ext: ^0.3.30

2. Install it

You can install packages from the command line:

with Flutter:

$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:

import 'package:webview_flutter_ext/platform_interface.dart';
import 'package:webview_flutter_ext/webview_flutter.dart';
Describes how popular the package is relative to other packages. [more]
Code health derived from static analysis. [more]
Reflects how tidy and up-to-date the package is. [more]
Weighted score of the above. [more]
Learn more about scoring.

We analyzed this package on Jul 14, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.8.4
  • pana: 0.13.15
  • Flutter: 1.17.5

Analysis suggestions

Package does not support Flutter platform Linux


  • package:webview_flutter_ext/platform_interface.dart that declares support for platforms: Android, iOS

Package does not support Flutter platform Web


  • package:webview_flutter_ext/platform_interface.dart that declares support for platforms: Android, iOS

Package does not support Flutter platform Windows


  • package:webview_flutter_ext/platform_interface.dart that declares support for platforms: Android, iOS

Package does not support Flutter platform macOS


  • package:webview_flutter_ext/platform_interface.dart that declares support for platforms: Android, iOS

Package not compatible with SDK dart


  • webview_flutter_ext that is a package requiring null.

Health suggestions

Format lib/src/webview_method_channel.dart.

Run flutter format to format lib/src/webview_method_channel.dart.

Format lib/webview_flutter.dart.

Run flutter format to format lib/webview_flutter.dart.


Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.7.0 <3.0.0
flutter 0.0.0
Transitive dependencies
collection 1.14.12 1.14.13
meta 1.1.8 1.2.2
sky_engine 0.0.99
typed_data 1.1.6 1.2.0
vector_math 2.0.8 2.1.0-nullsafety
Dev dependencies
pedantic ^1.8.0