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"

打开网页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_docsimport '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_importsvoid main() => runApp(const 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>
''';const String kLocalExamplePage = '''
<!DOCTYPE html>
<html lang="en">
<head>
<title>Load file or HTML string example</title>
</head>
<body><h1>Local demo page</h1>
<p>This is an example page used to demonstrate how to load a local file or HTMLstring using the <a href="https://pub.flutter-io.cn/packages/webview_flutter">Flutterwebview</a> plugin.
</p></body>
</html>
''';const String kTransparentBackgroundPage = '''<!DOCTYPE html><html><head><title>Transparent background test</title></head><style type="text/css">body { background: transparent; margin: 0; padding: 0; }#container { position: relative; margin: 0; padding: 0; width: 100vw; height: 100vh; }#shape { background: red; width: 200px; height: 200px; margin: 0; padding: 0; position: absolute; top: calc(50% - 100px); left: calc(50% - 100px); }p { text-align: center; }</style><body><div id="container"><p>Transparent background test</p><div id="shape"></div></div></body></html>
''';const String kLogExamplePage = '''
<!DOCTYPE html>
<html lang="en">
<head>
<title>Load file or HTML string example</title>
</head>
<body onload="console.log('Logging that the page is loading.')"><h1>Local demo page</h1>
<p>This page is used to test the forwarding of console logs to Dart.
</p><style>.btn-group button {padding: 24px; 24px;display: block;width: 25%;margin: 5px 0px 0px 0px;}
</style><div class="btn-group"><button onclick="console.error('This is an error message.')">Error</button><button onclick="console.warn('This is a warning message.')">Warning</button><button onclick="console.info('This is a info message.')">Info</button><button onclick="console.debug('This is a debug message.')">Debug</button><button onclick="console.log('This is a log message.')">Log</button>
</div></body>
</html>
''';class WebViewExample extends StatefulWidget {const WebViewExample({super.key});@overrideState<WebViewExample> createState() => _WebViewExampleState();
}class _WebViewExampleState extends State<WebViewExample> {late final WebViewController _controller;@overridevoid initState() {super.initState();// #docregion platform_featureslate final PlatformWebViewControllerCreationParams params;if (WebViewPlatform.instance is WebKitWebViewPlatform) {params = WebKitWebViewControllerCreationParams(allowsInlineMediaPlayback: true,mediaTypesRequiringUserAction: const <PlaybackMediaTypes>{},);} else {params = const PlatformWebViewControllerCreationParams();}final WebViewController controller =WebViewController.fromPlatformCreationParams(params);// #enddocregion platform_featurescontroller..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_featuresif (controller.platform is AndroidWebViewController) {AndroidWebViewController.enableDebugging(true);(controller.platform as AndroidWebViewController).setMediaPlaybackRequiresUserGesture(false);}// #enddocregion platform_features_controller = controller;}@overrideWidget 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<void> 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: <Widget>[TextField(decoration: const InputDecoration(labelText: 'Username'),autofocus: true,controller: usernameTextController,),TextField(decoration: const InputDecoration(labelText: 'Password'),controller: passwordTextController,),],),),actions: <Widget>[// 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();@overrideWidget build(BuildContext context) {return PopupMenuButton<MenuOptions>(key: const ValueKey<String>('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) => <PopupMenuItem<MenuOptions>>[const PopupMenuItem<MenuOptions>(value: MenuOptions.showUserAgent,child: Text('Show user agent'),),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'),),const PopupMenuItem<MenuOptions>(value: MenuOptions.doPostRequest,child: Text('Post Request'),),const PopupMenuItem<MenuOptions>(value: MenuOptions.loadHtmlString,child: Text('Load HTML string'),),const PopupMenuItem<MenuOptions>(value: MenuOptions.loadLocalFile,child: Text('Load local file'),),const PopupMenuItem<MenuOptions>(value: MenuOptions.loadFlutterAsset,child: Text('Load Flutter Asset'),),const PopupMenuItem<MenuOptions>(key: ValueKey<String>('ShowTransparentBackgroundExample'),value: MenuOptions.transparentBackground,child: Text('Transparent background example'),),const PopupMenuItem<MenuOptions>(value: MenuOptions.setCookie,child: Text('Set cookie'),),const PopupMenuItem<MenuOptions>(value: MenuOptions.logExample,child: Text('Log example'),),const PopupMenuItem<MenuOptions>(value: MenuOptions.basicAuthentication,child: Text('Basic Authentication Example'),),],);}Future<void> _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<void> _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: <Widget>[const Text('Cookies:'),_getCookieList(cookies),],),));}}Future<void> _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<void> _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<void> _onClearCache(BuildContext context) async {await webViewController.clearCache();await webViewController.clearLocalStorage();if (context.mounted) {ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Cache cleared.'),));}}Future<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.';}if (context.mounted) {ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(message),));}}Future<void> _onNavigationDelegateExample() {final String contentBase64 = base64Encode(const Utf8Encoder().convert(kNavigationExamplePage),);return webViewController.loadRequest(Uri.parse('data:text/html;base64,$contentBase64'),);}Future<void> _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<void> _onDoPostRequest() {return webViewController.loadRequest(Uri.parse('https://httpbin.org/post'),method: LoadRequestMethod.post,headers: <String, String>{'foo': 'bar', 'Content-Type': 'text/plain'},body: Uint8List.fromList('Test Body'.codeUnits),);}Future<void> _onLoadFlutterAssetExample() {return webViewController.loadFlutterAsset('assets/www/index.html');}Future<void> _onLoadHtmlStringExample() {return webViewController.loadHtmlString(kLocalExamplePage);}Future<void> _onTransparentBackground() {return webViewController.loadHtmlString(kTransparentBackgroundPage);}Widget _getCookieList(String cookies) {if (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(),);}Future<void> _onLogExample() {webViewController.setOnConsoleMessage((JavaScriptConsoleMessage consoleMessage) {debugPrint('== JS == ${consoleMessage.level.name}: ${consoleMessage.message}');});return webViewController.loadHtmlString(kLogExamplePage);}Future<void> _promptForUrl(BuildContext context) {final TextEditingController urlTextController = TextEditingController();return showDialog<String>(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: <Widget>[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;@overrideWidget build(BuildContext context) {return Row(children: <Widget>[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(),),],);}
}

最后的效果图:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/670279.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++ [NOIP2007 提高组] 矩阵取数游戏

有一个n行m列的矩阵&#xff0c;每个格子中有一个正整数。现在要从左上角的格子(1, 1)出发&#xff0c;每次只能向下或向右走一格&#xff0c;最后到达右下角的格子(n, m)。在走过的格子中取数&#xff0c;求取得的数的和的最大值。 输入&#xff1a; 第一行包含两个整数n和m&a…

若依整合mybatis-plus

文章目录 1.注释掉原本的MybatisConfig2. 将mybatis的配置文件改为mybatis-plus文件 ##前言 出先下列异常&#xff1a; 请求地址’/prod-api/user’,发生未知异常. org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.ruoyi.web.mapper.Us…

HP数组面试题

PHP数组面试题 问题&#xff1a; 如何创建一个空数组和一个带有初始值的数组&#xff1f; 答案&#xff1a; 创建空数组&#xff1a;可以使用array()函数或空数组语法[]来创建一个空数组&#xff0c;例如$arr array();或$arr [];。创建带有初始值的数组&#xff1a;可以在创建…

C# BackgroundWorker的使用

C# 中的 BackgroundWorker 类是 .NET Framework 提供的一个组件&#xff0c;用于在后台线程上异步执行长时间运行的操作&#xff0c;同时保持与用户界面&#xff08;UI&#xff09;的交互&#xff0c;如更新进度信息或处理取消请求。这使得可以轻松地在不冻结UI的情况下执行耗时…

003集—三调数据库添加三大类字段——arcgis

在国土管理日常统计工作中经常需要用到三大类数据&#xff08;农用地、建设用地、未利用地&#xff09;&#xff0c;而三调数据库中无三大类字段&#xff0c;因此需要手工录入三大类字段&#xff0c;并根据二级地类代码录入相关三大类名称。本代码可一键录入海量三大类名称统计…

什么是Java中的垃圾回收器,你能解释一下不同种类的垃圾回收算法吗?

什么是Java中的垃圾回收器&#xff0c;你能解释一下不同种类的垃圾回收算法吗&#xff1f; 在Java中&#xff0c;垃圾回收器是一种负责自动管理内存的机制&#xff0c;它负责检测和回收不再使用的对象&#xff0c;释放它们占用的内存空间。垃圾回收器的存在大大简化了程序员对…

数字图像处理(实践篇)四十五 OpenCV-Python 使用ORB算法(包括算法概述)检测图像上的特征点

目录 一 ORB算法 二 涉及的函数 三 实践 ORB: An efficient alternative to SIFT or SURF SIFT 和 SURF 已获得专利,使用需要付费。但是ORB并不需要。ORB 最重要的一点是它来自“

学习总结13

# 最大正方形 ## 题目描述 在一个 n* m 的只包含 0 和 1 的矩阵里找出一个不包含 0 的最大正方形&#xff0c;输出边长。 ## 输入格式 输入文件第一行为两个整数 n,m(1< n,m< 100)&#xff0c;接下来 n 行&#xff0c;每行 m 个数字&#xff0c;用空格隔开&#xff0…

【日常总结】SourceTree 1.5.2.0 更换用户名称和密码

一、场景 二、问题 三、解决方案 > 方案一&#xff1a;删除缓存文件 > 方案二&#xff1a;更新最新版本&#xff0c;可以直接修改密码&#xff08;推荐&#xff09; 方案一&#xff1a;删除缓存文件 Stage 1&#xff1a;设置显示隐藏文件 Stage 2&#xff1a;打开…

SouthernBiotech重组单克隆二抗

您是否在二抗的使用中遇到以下情况&#xff1a; 亲和力低&#xff0c;非特异性强&#xff1f; 稳定性差&#xff0c;批间差异大&#xff1f; SouthernBiotech(欣博盛生物)新推出重组单克隆二抗可避免出现以上问题&#xff01; 虽然传统多克隆二抗在实验中扮演很重要的角色&a…

linux上部署ftp服务

今天同事让帮忙部署一个ftp服务,以前折腾过几次,不过总会有奇奇怪怪的问题.今天的 话结合chatglm4,整理了一下部署. 在CentOS 7上部署FTP服务&#xff0c;可以使用VSFTP&#xff08;Very Secure FTP Daemon&#xff09;&#xff0c;这是一个安全、快速的FTP服务器。以下是部署F…

070:vue+cesium: 利用canvas设置线性渐变色材质

第070个 点击查看专栏目录 本示例的目的是介绍如何在vue+cesium中设置线性渐变色的材质,这里使用canvas的辅助方法。 直接复制下面的 vue+cesium源代码,操作2分钟即可运行实现效果. 文章目录 示例效果配置方式示例源代码(共104行)专栏目标示例效果 配置方式 1)查看基础…

题解:CF1918D(D. Blocking Elements)

题解&#xff1a;CF1918D&#xff08;D. Blocking Elements&#xff09; 一、 读题 1. 题目链接 &#xff08;1&#xff09; 洛谷链接 洛谷链接 &#xff08;2&#xff09; CF链接 CF链接 2. 题意简述 已知一个长度为 n n n 的数组 a a a&#xff0c;构造一个数组 b…

Android平台GB28181设备接入模块实现后台service按需回传摄像头数据到国标平台侧

技术背景 我们在做Android平台GB28181设备对接模块的时候&#xff0c;遇到这样的技术需求&#xff0c;开发者希望能以后台服务的形式运行程序&#xff0c;国标平台侧没有视频回传请求的时候&#xff0c;仅保持信令链接&#xff0c;有发起视频回传请求或语音广播时&#xff0c;…

数字孪生网络攻防模拟与城市安全演练

在数字化浪潮的推动下&#xff0c;网络攻防模拟和城市安全演练成为维护社会稳定的不可或缺的环节。基于数字孪生技术我们能够在虚拟环境中进行高度真实的网络攻防模拟&#xff0c;为安全专业人员提供实战经验&#xff0c;从而提升应对网络威胁的能力。同时&#xff0c;在城市安…

71.Spring和SpringMVC为什么需要父子容器?

71.Spring和SpringMVC为什么需要父子容器&#xff1f; 就功能性来说不用子父容器也可以完成&#xff08;参考&#xff1a;SpringBoot就没用子父容器&#xff09; 1、所以父子容器的主要作用应该是划分框架边界。有点单一职责的味道。service、dao层我们一般使用spring框架 来…

Qt 进程守护程序

Qt 进程守护程序 简单粗暴的监控&#xff0c;方法可整合到其他代码。 一、windows环境下 1、进程查询函数 processCount函数用于查询系统所有运行的进程中该进程运行的数量&#xff0c;比如启动了5个A进程&#xff0c;该函数查询返回的结果就为5。 windows下使用了API接口查询…

GEE数据集——全球健康地图项目Global Healthsites Mapping Project

Global Healthsites Mapping Project Healthsites.io和全球健康网站绘图项目的使命是帮助向政府、非政府组织和私营部门提供准确的最新健康设施信息。医疗机构登记簿是一个国家内运作良好的医疗信息系统的基石。准确和最新的数据提供了基础数据&#xff0c;有助于推动服务可用…

5分钟掌握接口自动化测试,4个知识点简单易学!

一. 什么是接口测试 接口测试是一种软件测试方法&#xff0c;用于验证不同软件组件之间的通信接口是否按预期工作。在接口测试中&#xff0c;测试人员会发送请求并检查接收到的响应&#xff0c;以确保接口在不同场景下都能正常工作。 就工具而言&#xff0c;常见的测试工具有…

16-Verilog实现二线制I2C CMOS串行EEPROM的读写操作

Verilog实现二线制I2C CMOS串行EEPROM的读写操作 1&#xff0c;二线制I2C CMOS串行EEPROM的简单介绍2&#xff0c;I2C总线特征介绍3&#xff0c;二线制I2C、CMOS串行EEPROM的读写操作4&#xff0c;EEPROM的Verilog HDL程序4.1&#xff0c;EEPROM的行为模型思路如下&#xff1a;…