我正在尝试使用flift中的Webview作为我的应用程序的主页。一切正常,但是单击“后退”按钮并没有将我发送到Web视图中的上一个网页,而是退出了应用程序。
import 'package:flutter/material.dart'; import 'package:webview_flutter/webview_flutter.dart'; import 'package:url_launcher/url_launcher.dart'; class _StudentPortalState extends State<StudentPortal>{ _launchURL(url) async { if (await canLaunch(url)) { await launch(url); } else { throw 'Could not launch $url'; } } Widget build (BuildContext context){ return Scaffold( body: WebView( javascriptMode: JavascriptMode.unrestricted, initialUrl: 'https://sites.google.com/ttmsa.org/ttmsa/home', navigationDelegate: (NavigationRequest request) { if(request.url.contains("intent:")) { _launchURL('https://forms.gle/XfNbn1Ph9xFdUaKeA'); return NavigationDecision.prevent; } return NavigationDecision.navigate; }, ), ); } }`
用WillPopScope包装支架,并在用户单击设备后退按钮时执行WebView Controller goback
代码片段onwillpop
@override Widget build(BuildContext context) { return WillPopScope( onWillPop: () => _exitApp(context), child: 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), ], ),
退出应用的代码段
WebViewController controllerGlobal; Future<bool> _exitApp(BuildContext context) async { if (await controllerGlobal.canGoBack()) { print("onwill goback"); controllerGlobal.goBack(); return Future.value(true); } else { Scaffold.of(context).showSnackBar( const SnackBar(content: Text("No back history item")), ); return Future.value(false); } }
完整的代码
// 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><a href="https://www.google.com/">https://nodejs.org/en</a></ul> </ul> </body> </html> '''; class WebViewExample extends StatefulWidget { @override _WebViewExampleState createState() => _WebViewExampleState(); } WebViewController controllerGlobal; Future<bool> _exitApp(BuildContext context) async { if (await controllerGlobal.canGoBack()) { print("onwill goback"); controllerGlobal.goBack(); } else { Scaffold.of(context).showSnackBar( const SnackBar(content: Text("No back history item")), ); return Future.value(false); } } class _WebViewExampleState extends State<WebViewExample> { final Completer<WebViewController> _controller = Completer<WebViewController>(); @override Widget build(BuildContext context) { return WillPopScope( onWillPop: () => _exitApp(context), child: 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; } if (request.url.startsWith('https://flutter.dev/docs')) { 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; controllerGlobal = controller; 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(); }, ), ], ); }, ); } }
工作演示。我单击桌面页面,然后按设备后退按钮,您会看到信息显示“ onwill goback”。并返回上一页