ovuhome_webview_flutter 0.3.11+4-bate.8

  • Readme
  • Changelog
  • Example
  • Installing
  • 54

WebView for 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 within webviews is also experimental. The above tags also surface known issues with keyboard input. Some currently known keyboard issues, as of ovuhome_webview_flutter version 0.3.10+4:

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 ovuhome_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.

0.3.11+4-bate.8 #

  • Android test WebChromeClient

0.3.11+4-bate.7 #

  • Android test WebChromeClient

0.3.11+4-bate.6 #

  • Android add dependencies

0.3.11+4-bate.5 #

  • Android test context

0.3.11+4-bate.4 #

  • iOS rename webview_flutter.podspec to ovuhome_webview_flutter.podspec

0.3.11+4-bate.3 #

  • iOS web scroll view set scrollEnabled to false

0.3.11+4-bate.2 #

  • Rename webview_flutter to ovuhome_webview_flutter

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.

example/lib/main.dart

// 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.

import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:ovuhome_webview_flutter/ovuhome_webview_flutter.dart';

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

const String kNavigationExamplePage = '''
<!DOCTYPE html><html>
<head><title>Navigation Delegate Example</title></head>
<body>
<p>
The navigation delegate is set to block navigation to the youtube website.
</p>
<ul>
<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>
</ul>
</body>
</html>
''';

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

class _WebViewExampleState extends State<WebViewExample> {
  final Completer<WebViewController> _controller =
      Completer<WebViewController>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter WebView example'),
        // This drop down menu demonstrates that Flutter widgets can be shown over the web view.
        actions: <Widget>[
          NavigationControls(_controller.future),
          SampleMenu(_controller.future),
        ],
      ),
      // 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 WebView(
          initialUrl: 'https://flutter.dev',
          javascriptMode: JavascriptMode.unrestricted,
          onWebViewCreated: (WebViewController webViewController) {
            _controller.complete(webViewController);
          },
          // TODO(iskakaushik): Remove this when collection literals makes it to stable.
          // ignore: prefer_collection_literals
          javascriptChannels: <JavascriptChannel>[
            _toasterJavascriptChannel(context),
          ].toSet(),
          navigationDelegate: (NavigationRequest request) {
            if (request.url.startsWith('https://www.youtube.com/')) {
              print('blocking navigation to $request}');
              return NavigationDecision.prevent;
            }
            print('allowing navigation to $request');
            return NavigationDecision.navigate;
          },
          onPageFinished: (String url) {
            print('Page finished loading: $url');
          },
        );
      }),
      floatingActionButton: favoriteButton(),
    );
  }

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

  Widget favoriteButton() {
    return FutureBuilder<WebViewController>(
        future: _controller.future,
        builder: (BuildContext context,
            AsyncSnapshot<WebViewController> controller) {
          if (controller.hasData) {
            return FloatingActionButton(
              onPressed: () async {
                final String url = await controller.data.currentUrl();
                Scaffold.of(context).showSnackBar(
                  SnackBar(content: Text('Favorited $url')),
                );
              },
              child: const Icon(Icons.favorite),
            );
          }
          return Container();
        });
  }
}

enum MenuOptions {
  showUserAgent,
  listCookies,
  clearCookies,
  addToCache,
  listCache,
  clearCache,
  navigationDelegate,
}

class SampleMenu extends StatelessWidget {
  SampleMenu(this.controller);

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

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<WebViewController>(
      future: controller,
      builder:
          (BuildContext context, AsyncSnapshot<WebViewController> controller) {
        return PopupMenuButton<MenuOptions>(
          onSelected: (MenuOptions value) {
            switch (value) {
              case MenuOptions.showUserAgent:
                _onShowUserAgent(controller.data, context);
                break;
              case MenuOptions.listCookies:
                _onListCookies(controller.data, context);
                break;
              case MenuOptions.clearCookies:
                _onClearCookies(context);
                break;
              case MenuOptions.addToCache:
                _onAddToCache(controller.data, context);
                break;
              case MenuOptions.listCache:
                _onListCache(controller.data, context);
                break;
              case MenuOptions.clearCache:
                _onClearCache(controller.data, context);
                break;
              case MenuOptions.navigationDelegate:
                _onNavigationDelegateExample(controller.data, context);
                break;
            }
          },
          itemBuilder: (BuildContext context) => <PopupMenuItem<MenuOptions>>[
            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.
    controller.evaluateJavascript(
        'Toaster.postMessage("User Agent: " + navigator.userAgent);');
  }

  void _onListCookies(
      WebViewController controller, BuildContext context) async {
    final String cookies =
        await controller.evaluateJavascript('document.cookie');
    Scaffold.of(context).showSnackBar(SnackBar(
      content: Column(
        mainAxisAlignment: MainAxisAlignment.end,
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          const Text('Cookies:'),
          _getCookieList(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.';
    }
    Scaffold.of(context).showSnackBar(SnackBar(
      content: Text(message),
    ));
  }

  void _onNavigationDelegateExample(
      WebViewController controller, BuildContext context) async {
    final String contentBase64 =
        base64Encode(const Utf8Encoder().convert(kNavigationExamplePage));
    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;

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

Use this package as a library

1. Depend on it

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


dependencies:
  ovuhome_webview_flutter: ^0.3.11+4-bate.8

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:ovuhome_webview_flutter/ovuhome_webview_flutter.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
16
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
80
Overall:
Weighted score of the above. [more]
54
Learn more about scoring.

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

  • Dart: 2.8.4
  • pana: 0.13.9+1
  • Flutter: 1.17.3

Analysis suggestions

Package does not support Flutter platform linux

Because of import path [package:ovuhome_webview_flutter/ovuhome_webview_flutter.dart]

Package does not support Flutter platform macos

Because of import path [package:ovuhome_webview_flutter/ovuhome_webview_flutter.dart]

Package does not support Flutter platform web

Because of import path [package:ovuhome_webview_flutter/ovuhome_webview_flutter.dart]

Package does not support Flutter platform windows

Because of import path [package:ovuhome_webview_flutter/ovuhome_webview_flutter.dart]

Package not compatible with SDK dart

because of import path [ovuhome_webview_flutter]

Maintenance issues and suggestions

Homepage URL doesn't exist. (-20 points)

At the time of the analysis the homepage field https://github.com/flutter/plugins/tree/master/packages/ovuhome_webview_flutter was unreachable.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.0.0-dev.68.0 <3.0.0
flutter 0.0.0
Transitive dependencies
collection 1.14.12 1.14.13
meta 1.1.8 1.2.0
sky_engine 0.0.99
typed_data 1.1.6 1.2.0
vector_math 2.0.8
Dev dependencies
flutter_driver
flutter_test