123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- // 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:webview_flutter/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();
- },
- ),
- ],
- );
- },
- );
- }
- }
|