flutter使用webview_flutter在安卓和ios上打开网页

webview_flutter仓库地址:webview_flutter | Flutter package

github地址:https://github.com/flutter/packages/tree/main/packages/webview_flutter/webview_flutter

要打开非https协议的网页,需要在安卓平台上添加权限:android:usesCleartextTraffic="true"

flutter使用webview_flutter在安卓和ios上打开网页_第1张图片

打开网页demo:

// Copyright 2013 The Flutter 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 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
// #docregion platform_imports
// Import for Android features.
import 'package:webview_flutter_android/webview_flutter_android.dart';
// Import for iOS features.
import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';
// #enddocregion platform_imports

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

const String kNavigationExamplePage = '''

Navigation Delegate Example

The navigation delegate is set to block navigation to the youtube website.

'''; const String kLocalExamplePage = ''' Load file or HTML string example

Local demo page

This is an example page used to demonstrate how to load a local file or HTML string using the Flutter webview plugin.

'''; const String kTransparentBackgroundPage = ''' Transparent background test

Transparent background test

'''; const String kLogExamplePage = ''' Load file or HTML string example

Local demo page

This page is used to test the forwarding of console logs to Dart.

'''; class WebViewExample extends StatefulWidget { const WebViewExample({super.key}); @override State createState() => _WebViewExampleState(); } class _WebViewExampleState extends State { late final WebViewController _controller; @override void initState() { super.initState(); // #docregion platform_features late final PlatformWebViewControllerCreationParams params; if (WebViewPlatform.instance is WebKitWebViewPlatform) { params = WebKitWebViewControllerCreationParams( allowsInlineMediaPlayback: true, mediaTypesRequiringUserAction: const {}, ); } else { params = const PlatformWebViewControllerCreationParams(); } final WebViewController controller = WebViewController.fromPlatformCreationParams(params); // #enddocregion platform_features controller ..setJavaScriptMode(JavaScriptMode.unrestricted) ..setBackgroundColor(const Color(0x00000000)) ..setNavigationDelegate( NavigationDelegate( onProgress: (int progress) { debugPrint('WebView is loading (progress : $progress%)'); }, onPageStarted: (String url) { debugPrint('Page started loading: $url'); }, onPageFinished: (String url) { debugPrint('Page finished loading: $url'); }, onWebResourceError: (WebResourceError error) { debugPrint(''' Page resource error: code: ${error.errorCode} description: ${error.description} errorType: ${error.errorType} isForMainFrame: ${error.isForMainFrame} '''); }, onNavigationRequest: (NavigationRequest request) { if (request.url.startsWith('https://www.youtube.com/')) { debugPrint('blocking navigation to ${request.url}'); return NavigationDecision.prevent; } debugPrint('allowing navigation to ${request.url}'); return NavigationDecision.navigate; }, onUrlChange: (UrlChange change) { debugPrint('url change to ${change.url}'); }, onHttpAuthRequest: (HttpAuthRequest request) { openDialog(request); }, ), ) ..addJavaScriptChannel( 'Toaster', onMessageReceived: (JavaScriptMessage message) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(message.message)), ); }, ) ..loadRequest(Uri.parse('http://192.168.1.171:5173/#/pad?team=red')); // #docregion platform_features if (controller.platform is AndroidWebViewController) { AndroidWebViewController.enableDebugging(true); (controller.platform as AndroidWebViewController) .setMediaPlaybackRequiresUserGesture(false); } // #enddocregion platform_features _controller = controller; } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.green, body: WebViewWidget(controller: _controller), // floatingActionButton: favoriteButton(), ); } Widget favoriteButton() { return FloatingActionButton( onPressed: () async { final String? url = await _controller.currentUrl(); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Favorited $url')), ); } }, child: const Icon(Icons.favorite), ); } Future openDialog(HttpAuthRequest httpRequest) async { final TextEditingController usernameTextController = TextEditingController(); final TextEditingController passwordTextController = TextEditingController(); return showDialog( context: context, barrierDismissible: false, builder: (BuildContext context) { return AlertDialog( title: Text('${httpRequest.host}: ${httpRequest.realm ?? '-'}'), content: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( decoration: const InputDecoration(labelText: 'Username'), autofocus: true, controller: usernameTextController, ), TextField( decoration: const InputDecoration(labelText: 'Password'), controller: passwordTextController, ), ], ), ), actions: [ // Explicitly cancel the request on iOS as the OS does not emit new // requests when a previous request is pending. TextButton( onPressed: () { httpRequest.onCancel(); Navigator.of(context).pop(); }, child: const Text('Cancel'), ), TextButton( onPressed: () { httpRequest.onProceed( WebViewCredential( user: usernameTextController.text, password: passwordTextController.text, ), ); Navigator.of(context).pop(); }, child: const Text('Authenticate'), ), ], ); }, ); } } enum MenuOptions { showUserAgent, listCookies, clearCookies, addToCache, listCache, clearCache, navigationDelegate, doPostRequest, loadLocalFile, loadFlutterAsset, loadHtmlString, transparentBackground, setCookie, logExample, basicAuthentication, } class SampleMenu extends StatelessWidget { SampleMenu({ super.key, required this.webViewController, }); final WebViewController webViewController; late final WebViewCookieManager cookieManager = WebViewCookieManager(); @override Widget build(BuildContext context) { return PopupMenuButton( key: const ValueKey('ShowPopupMenu'), onSelected: (MenuOptions value) { switch (value) { case MenuOptions.showUserAgent: _onShowUserAgent(); case MenuOptions.listCookies: _onListCookies(context); case MenuOptions.clearCookies: _onClearCookies(context); case MenuOptions.addToCache: _onAddToCache(context); case MenuOptions.listCache: _onListCache(); case MenuOptions.clearCache: _onClearCache(context); case MenuOptions.navigationDelegate: _onNavigationDelegateExample(); case MenuOptions.doPostRequest: _onDoPostRequest(); case MenuOptions.loadFlutterAsset: _onLoadFlutterAssetExample(); case MenuOptions.loadHtmlString: _onLoadHtmlStringExample(); case MenuOptions.transparentBackground: _onTransparentBackground(); case MenuOptions.setCookie: _onSetCookie(); case MenuOptions.logExample: _onLogExample(); case MenuOptions.basicAuthentication: _promptForUrl(context); case MenuOptions.loadLocalFile: // TODO: Handle this case. } }, itemBuilder: (BuildContext context) => >[ const PopupMenuItem( value: MenuOptions.showUserAgent, child: Text('Show user agent'), ), const PopupMenuItem( value: MenuOptions.listCookies, child: Text('List cookies'), ), const PopupMenuItem( value: MenuOptions.clearCookies, child: Text('Clear cookies'), ), const PopupMenuItem( value: MenuOptions.addToCache, child: Text('Add to cache'), ), const PopupMenuItem( value: MenuOptions.listCache, child: Text('List cache'), ), const PopupMenuItem( value: MenuOptions.clearCache, child: Text('Clear cache'), ), const PopupMenuItem( value: MenuOptions.navigationDelegate, child: Text('Navigation Delegate example'), ), const PopupMenuItem( value: MenuOptions.doPostRequest, child: Text('Post Request'), ), const PopupMenuItem( value: MenuOptions.loadHtmlString, child: Text('Load HTML string'), ), const PopupMenuItem( value: MenuOptions.loadLocalFile, child: Text('Load local file'), ), const PopupMenuItem( value: MenuOptions.loadFlutterAsset, child: Text('Load Flutter Asset'), ), const PopupMenuItem( key: ValueKey('ShowTransparentBackgroundExample'), value: MenuOptions.transparentBackground, child: Text('Transparent background example'), ), const PopupMenuItem( value: MenuOptions.setCookie, child: Text('Set cookie'), ), const PopupMenuItem( value: MenuOptions.logExample, child: Text('Log example'), ), const PopupMenuItem( value: MenuOptions.basicAuthentication, child: Text('Basic Authentication Example'), ), ], ); } Future _onShowUserAgent() { // Send a message with the user agent string to the Toaster JavaScript channel we registered // with the WebView. return webViewController.runJavaScript( 'Toaster.postMessage("User Agent: " + navigator.userAgent);', ); } Future _onListCookies(BuildContext context) async { final String cookies = await webViewController .runJavaScriptReturningResult('document.cookie') as String; if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Column( mainAxisAlignment: MainAxisAlignment.end, mainAxisSize: MainAxisSize.min, children: [ const Text('Cookies:'), _getCookieList(cookies), ], ), )); } } Future _onAddToCache(BuildContext context) async { await webViewController.runJavaScript( 'caches.open("test_caches_entry"); localStorage["test_localStorage"] = "dummy_entry";', ); if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar(const SnackBar( content: Text('Added a test entry to cache.'), )); } } Future _onListCache() { return webViewController.runJavaScript('caches.keys()' // ignore: missing_whitespace_between_adjacent_strings '.then((cacheKeys) => JSON.stringify({"cacheKeys" : cacheKeys, "localStorage" : localStorage}))' '.then((caches) => Toaster.postMessage(caches))'); } Future _onClearCache(BuildContext context) async { await webViewController.clearCache(); await webViewController.clearLocalStorage(); if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar(const SnackBar( content: Text('Cache cleared.'), )); } } Future _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.'; } if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text(message), )); } } Future _onNavigationDelegateExample() { final String contentBase64 = base64Encode( const Utf8Encoder().convert(kNavigationExamplePage), ); return webViewController.loadRequest( Uri.parse('data:text/html;base64,$contentBase64'), ); } Future _onSetCookie() async { await cookieManager.setCookie( const WebViewCookie( name: 'foo', value: 'bar', domain: 'httpbin.org', path: '/anything', ), ); await webViewController.loadRequest(Uri.parse( 'https://httpbin.org/anything', )); } Future _onDoPostRequest() { return webViewController.loadRequest( Uri.parse('https://httpbin.org/post'), method: LoadRequestMethod.post, headers: {'foo': 'bar', 'Content-Type': 'text/plain'}, body: Uint8List.fromList('Test Body'.codeUnits), ); } Future _onLoadFlutterAssetExample() { return webViewController.loadFlutterAsset('assets/www/index.html'); } Future _onLoadHtmlStringExample() { return webViewController.loadHtmlString(kLocalExamplePage); } Future _onTransparentBackground() { return webViewController.loadHtmlString(kTransparentBackgroundPage); } Widget _getCookieList(String cookies) { if (cookies == '""') { return Container(); } final List cookieList = cookies.split(';'); final Iterable cookieWidgets = cookieList.map((String cookie) => Text(cookie)); return Column( mainAxisAlignment: MainAxisAlignment.end, mainAxisSize: MainAxisSize.min, children: cookieWidgets.toList(), ); } Future _onLogExample() { webViewController .setOnConsoleMessage((JavaScriptConsoleMessage consoleMessage) { debugPrint( '== JS == ${consoleMessage.level.name}: ${consoleMessage.message}'); }); return webViewController.loadHtmlString(kLogExamplePage); } Future _promptForUrl(BuildContext context) { final TextEditingController urlTextController = TextEditingController(); return showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: const Text('Input URL to visit'), content: TextField( decoration: const InputDecoration(labelText: 'URL'), autofocus: true, controller: urlTextController, ), actions: [ TextButton( onPressed: () { if (urlTextController.text.isNotEmpty) { final Uri? uri = Uri.tryParse(urlTextController.text); if (uri != null && uri.scheme.isNotEmpty) { webViewController.loadRequest(uri); Navigator.pop(context); } } }, child: const Text('Visit'), ), ], ); }, ); } } class NavigationControls extends StatelessWidget { const NavigationControls({super.key, required this.webViewController}); final WebViewController webViewController; @override Widget build(BuildContext context) { return Row( children: [ IconButton( icon: const Icon(Icons.arrow_back_ios), onPressed: () async { if (await webViewController.canGoBack()) { await webViewController.goBack(); } else { if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('No back history item')), ); } } }, ), IconButton( icon: const Icon(Icons.arrow_forward_ios), onPressed: () async { if (await webViewController.canGoForward()) { await webViewController.goForward(); } else { if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('No forward history item')), ); } } }, ), IconButton( icon: const Icon(Icons.replay), onPressed: () => webViewController.reload(), ), ], ); } }

最后的效果图:

flutter使用webview_flutter在安卓和ios上打开网页_第2张图片

你可能感兴趣的:(多端开发,flutter,android,ios)