当前位置: 首页 > news >正文

flutter开发实战-Webview及dispose关闭背景音

flutter开发实战-Webview及dispose关闭背景音

当在使用webview的时候,dispose需要关闭网页的背景音或者音效。
在这里插入图片描述

一、webview的使用

在工程的pubspec.yaml中引入插件

  webview_flutter: ^4.4.2webview_cookie_manager: ^2.0.6

Webview的使用代码如下

初始化WebViewController

controller = WebViewController()..setJavaScriptMode(JavaScriptMode.unrestricted)..setBackgroundColor(const Color(0x00000000))..setNavigationDelegate(NavigationDelegate(onProgress: (int progress) {// Update loading bar.},onPageStarted: (String url) {},onPageFinished: (String url) {},onHttpError: (HttpResponseError error) {},onWebResourceError: (WebResourceError error) {},onNavigationRequest: (NavigationRequest request) {if (request.url.startsWith('https://www.youtube.com/')) {return NavigationDecision.prevent;}return NavigationDecision.navigate;},),)..loadRequest(Uri.parse('https://flutter.dev'));

将WebViewController传递给WebViewWidget

@override
Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Flutter Simple Example')),body: WebViewWidget(controller: controller),);
}

二、为了方便使用webview,进行封装成一个独立的widget

为了方便使用webview,进行封装成一个独立的widget

WebAppBar

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';/// 自定义Appbar
class WebAppBar extends StatefulWidget implements PreferredSizeWidget {const WebAppBar({Key? key,required this.toolbarHeight,this.elevation,this.backgroundColor,this.leadingWidget,this.trailingWidget,this.centerWidget,this.brightness,this.backgroundImageName}): super(key: key);final double toolbarHeight;final double? elevation;final Color? backgroundColor;final Widget? leadingWidget;final Widget? trailingWidget;final Widget? centerWidget;final Brightness? brightness;final String? backgroundImageName;@override// TODO: implement preferredSizeSize get preferredSize => Size(ScreenUtil().screenWidth, toolbarHeight + ScreenUtil().statusBarHeight);@overrideState<StatefulWidget> createState() => _WebAppBarState();
}class _WebAppBarState extends State<WebAppBar> {@overrideWidget build(BuildContext context) {final SystemUiOverlayStyle overlayStyle =widget.brightness == Brightness.dark? SystemUiOverlayStyle.light: SystemUiOverlayStyle.dark;Widget leadingWidget = (widget.leadingWidget ?? Container());Widget centerWidget = (widget.centerWidget ?? Container());Widget trailingWidget = (widget.trailingWidget ?? Container());return AnnotatedRegion<SystemUiOverlayStyle>(//套AnnotatedRegion是为了增加状态栏控制value: overlayStyle,child: Material(color: Colors.transparent,//套Material是为了增加elevationelevation: widget.elevation ?? 0,child: Container(padding: EdgeInsets.symmetric(horizontal: 0.0),height: widget.toolbarHeight + ScreenUtil().statusBarHeight,decoration: BoxDecoration(color: widget.backgroundColor,),child: Column(mainAxisAlignment: MainAxisAlignment.center,crossAxisAlignment: CrossAxisAlignment.center,children: [Container(height: ScreenUtil().statusBarHeight,),Expanded(child: Container(height: widget.toolbarHeight,alignment: Alignment.center,child: Row(mainAxisAlignment: MainAxisAlignment.center,crossAxisAlignment: CrossAxisAlignment.center,children: [Container(height: widget.toolbarHeight,child: leadingWidget,),Expanded(child: Container(alignment: Alignment.center,height: widget.toolbarHeight,child: centerWidget,),),Container(height: widget.toolbarHeight,child: trailingWidget,),],),),)],),),),);}
}

使用webview的Widget

import 'dart:async';
import 'dart:collection';
import 'dart:convert';
import 'dart:io';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_importsclass WebViewSkeleton extends StatefulWidget {const WebViewSkeleton({Key? key,required this.url,required this.onWebProgress,required this.onWebResourceError,required this.onLoadFinished,this.onWebTitleLoaded,required this.onWebViewCreated,this.appUserAgent,this.webViewUserAgent,}) : super(key: key);final String url;final String? appUserAgent;final String? webViewUserAgent;final Function(int progress) onWebProgress;final Function(WebResourceError error) onWebResourceError;final Function(String? url) onLoadFinished;final Function(String? webTitle)? onWebTitleLoaded;final Function(WebViewController controller) onWebViewCreated;@overrideState<WebViewSkeleton> createState() => _WebViewSkeletonState();
}class _WebViewSkeletonState extends State<WebViewSkeleton> {// WebViewControllerlate final WebViewController _webController;// 尝试3次,每次间隔2秒int _loadTitleTimes = 0;bool _isDisposed = false;@overridevoid initState() {// TODO: implement initStatesuper.initState();_isDisposed = false;initWebController();}void initWebController() {// #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))..setUserAgent(widget.webViewUserAgent)..setNavigationDelegate(NavigationDelegate(onProgress: (int progress) {debugPrint('WebView is loading (progress : $progress%)');widget.onWebProgress(progress);},onPageStarted: (String url) {debugPrint('Page started loading: $url');// 网页开始加载webPageLoadedStart();print('onPageStarted url: $url');},onPageFinished: (String url) {debugPrint('Page finished loading: $url');// 网页加载完成print('onPageFinished url: $url');// 加载完成widget.onLoadFinished(url);// 获取网页的标题getWebPageTitle(url: url);},onWebResourceError: (WebResourceError error) {debugPrint('''
Page resource error:code: ${error.errorCode}description: ${error.description}errorType: ${error.errorType}isForMainFrame: ${error.isForMainFrame}''');print("onWebResourceError:${error}");widget.onWebResourceError(error);},onNavigationRequest: (NavigationRequest request) {String url = Uri.decodeComponent(request.url);bool canNavigate = false;if (url.startsWith("http")) {canNavigate = true;}// 允许路由替换return canNavigate? NavigationDecision.navigate: NavigationDecision.prevent;},onUrlChange: (UrlChange change) {debugPrint('url change to ${change.url}');},// onHttpAuthRequest: (HttpAuthRequest request) {//   openDialog(request);// },),);// #docregion platform_featuresif (controller.platform is AndroidWebViewController) {AndroidWebViewController.enableDebugging(true);(controller.platform as AndroidWebViewController).setMediaPlaybackRequiresUserGesture(false);}// #enddocregion platform_features_webController = controller;onWebViewCreated();}void onWebViewCreated() {print("onWebViewCreated");// controller.loadUrl(url);此时也可以初始化一个url_webController.canGoBack().then((res) {// 是否能返回上一级print("controller.canGoBack res: $res");});_webController.currentUrl().then((url) {// 返回当前urlprint("controller.currentUrl url: $url");});_webController.canGoForward().then((res) {//是否能前进print("controller.canGoForward res: $res");});String filePre = "file://";if (widget.url.startsWith(filePre)) {String html = widget.url.substring(filePre.length);DefaultAssetBundle.of(context).loadString('assets/htmls/${html}').then((value) => _webController?.loadHtmlString(value));} else {if (widget.url.startsWith("http://") ||widget.url.startsWith("https://")) {_webController.loadRequest(Uri.parse(widget.url), headers: {'Referer': widget.url,});}}widget.onWebViewCreated(_webController);}@overridevoid dispose() {// TODO: implement disposeprint("_WebViewSkeletonState dispose");_isDisposed = true;webControllerDispose();super.dispose();}Future<void> webControllerDispose() async {/// dispose打开空白页面,关闭音频String url = "about:blank";await _webController?.loadRequest(Uri.parse(url), headers: {});_webController?.clearCache();_webController?.clearLocalStorage();}void webPageLoadedStart() {_loadTitleTimes = 0;}Future<void> getWebPageTitle({required String url}) async {if (_isDisposed) {return;}String? title = await _webController?.getTitle();print("getWebPageTitle:${title}");if (title != null && title.isNotEmpty) {print("webTitle a:${title}");setWebPageTitle(title);} else {try {var result = await _webController?.runJavaScriptReturningResult('window.document.title');print("webTitle document.url:${result}");if (result != null && (result is String) && result.isNotEmpty) {setWebPageTitle(result);} else {result = await _webController?.runJavaScriptReturningResult('window.document.getElementsByTagName("title")[0]');print("webTitle document.getElementsByTagName:${result}");setWebPageTitle(result);}} catch (e) {print("getWebPageTitle:${e.toString()}");// 最多尝试三次if (_loadTitleTimes < 3) {Future.delayed(Duration(seconds: 2), () {_loadTitleTimes++;getWebPageTitle(url: url);});}}}}// 设置页面标题void setWebPageTitle(data) {if (widget.onWebTitleLoaded != null) {widget.onWebTitleLoaded!(data);}}// 返回void goBack() {_webController?.canGoBack().then((res) {// 是否能返回上一级print("controller.canGoBack res: $res");if (true == res) {_webController?.goBack();}});}// 刷新void reload() {_webController?.reload();}@overrideWidget build(BuildContext context) {return buildWebView(context);}Widget buildWebView(BuildContext context) {return WebViewWidget(controller: _webController,);}
}

使用web view的页面webviewPage

class WebViewPage extends StatefulWidget {const WebViewPage({Key? key,this.arguments,}) : super(key: key);final Object? arguments;@overrideState<WebViewPage> createState() => _WebViewPageState();
}class _WebViewPageState extends State<WebViewPage> {String title = "";String? url;// WebViewControllerWebViewController? _webViewController;double webProgress = 0.0;String? webViewUserAgent;String? appUserAgent;String? webTitle;@overridevoid initState() {// TODO: implement initStateif (widget.arguments != null && widget.arguments is Map) {Map obj = widget.arguments as Map;url = obj["url"];webViewUserAgent = obj['webViewUserAgent'];appUserAgent = obj['appUserAgent'];webTitle = obj['webTitle'];}loggerInfo("_WebViewPageState arguments:${widget.arguments}");loggerInfo("_WebViewPageState url:${url}");super.initState();}@overridevoid dispose() {// TODO: implement disposesuper.dispose();}@overrideWidget build(BuildContext context) {return Scaffold(appBar: WebAppBar(toolbarHeight: 44.0,backgroundColor: Theme.of(context).primaryColor,centerWidget: Text(webTitle ?? title,textAlign: TextAlign.center,overflow: TextOverflow.ellipsis,style: TextStyle(fontSize: 17,color: ColorUtil.hexColor(0xffffff),fontWeight: FontWeight.w600,fontStyle: FontStyle.normal,decoration: TextDecoration.none,),),leadingWidget: Row(mainAxisAlignment: MainAxisAlignment.start,crossAxisAlignment: CrossAxisAlignment.center,children: [IconButton(padding: EdgeInsets.all(0.0),onPressed: () {webViewGoBack(context);},icon: Icon(Icons.arrow_back_ios,color: Colors.white,size: 24.0,),),IconButton(padding: EdgeInsets.all(0.0),onPressed: () {navigatorBack(context);},icon: Icon(Icons.close_rounded,color: Colors.white,size: 30.0,),),],),trailingWidget: Row(mainAxisAlignment: MainAxisAlignment.end,crossAxisAlignment: CrossAxisAlignment.center,children: [SizedBox(width: 28.0,),IconButton(padding: EdgeInsets.all(0.0),onPressed: () {webViewReload();},icon: Icon(Icons.refresh_outlined,color: Colors.white,size: 28.0,),),],),),body: Stack(children: [WebViewSkeleton(url: url ?? "",onWebResourceError: (WebResourceError error) {if (mounted) {// TODO onWebResourceError}},onWebProgress: (int progress) {if (mounted) {// TODO onWebProgressdouble precent = progress / 100.0;if (precent > 1.0) {precent = 1.0;}if (precent < 0.0) {precent = 0.0;}setState(() {webProgress = precent;loggerInfo("webProgress:${webProgress}");});}},onLoadFinished: (String? url) {if (mounted) {// TODO onLoadFinished}},onWebTitleLoaded: (String? webTitle) {if (mounted) {String? aWebTitle;if ('""' != webTitle) {aWebTitle = webTitle;}setState(() {title = aWebTitle ?? "";});}},onWebViewCreated: (WebViewController controller) {_webViewController = controller;},),buildProgressIndicator(context),],),);}Widget buildProgressIndicator(BuildContext context) {return (webProgress != 1.0)? LinearProgressIndicator(backgroundColor: Colors.transparent,valueColor: AlwaysStoppedAnimation(ColorUtil.hexColor(0x3b93ff)),value: webProgress,minHeight: 2,): Container();}void navigatorBack(BuildContext context) {Navigator.of(context).pop();}void webViewGoBack(BuildContext context) {_webViewController?.canGoBack().then((res) {// 是否能返回上一级loggerInfo("controller.canGoBack res: $res");if (true == res) {_webViewController?.goBack();} else {navigatorBack(context);}});}void webViewReload() {_webViewController?.reload();}
}

三、解决dispose关闭背景音乐

解决dispose关闭背景音乐的问题,当widget被dispose的时候,我们可以通过加载一个空白页面,来实现这个关闭背景音乐。
加载空白

代码如下

@overridevoid dispose() {// TODO: implement disposeprint("_WebViewSkeletonState dispose");_isDisposed = true;webControllerDispose();super.dispose();}Future<void> webControllerDispose() async {/// dispose打开空白页面,关闭音频String url = "about:blank";await _webController?.loadRequest(Uri.parse(url), headers: {});_webController?.clearCache();_webController?.clearLocalStorage();}

四、小结

flutter开发实战-Webview及dispose关闭背景音

学习记录,每天不停进步。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • c与c++ 常用的字符与字符串处理的接口介绍:
  • Xilinx FPGA:vivado关于fifo的一些零碎知识
  • 【K8s】【问题排查】k8s只能本地服务器访问服务,其他节点无法访问服务
  • crontab定时任务不执行原因排查
  • 国际网课平台Udemy上的亚马逊云科技AWS免费高分课程和创建、维护EC2动手实践
  • linux高级编程(TCP)(传输控制协议)
  • Java核心技术【二十】Java泛型的基本概念和原理详解
  • 二叉树超详细解析
  • phpstudy框架,window平台,如何开端口给局域网访问?
  • AIGC专栏12——EasyAnimateV3发布详解 支持图文生视频 最大支持960x960x144帧视频生成
  • 【QT中实现摄像头播放、以及视频录制】
  • Consul与CoreDNS的对比
  • 架构设计(2)云原生架构与实例部署
  • 【WebGIS平台】传统聚落建筑科普数字化建模平台
  • MySQL之基本查询(上)-表的增删查改
  • 【5+】跨webview多页面 触发事件(二)
  • 【前端学习】-粗谈选择器
  • 3.7、@ResponseBody 和 @RestController
  • Android 架构优化~MVP 架构改造
  • es6(二):字符串的扩展
  • es的写入过程
  • Java|序列化异常StreamCorruptedException的解决方法
  • Java新版本的开发已正式进入轨道,版本号18.3
  • JDK9: 集成 Jshell 和 Maven 项目.
  • JWT究竟是什么呢?
  • Linux CTF 逆向入门
  • MQ框架的比较
  • Quartz实现数据同步 | 从0开始构建SpringCloud微服务(3)
  • 初识 beanstalkd
  • 漂亮刷新控件-iOS
  • 突破自己的技术思维
  • 系统认识JavaScript正则表达式
  • 硬币翻转问题,区间操作
  • 栈实现走出迷宫(C++)
  • 正则与JS中的正则
  • linux 淘宝开源监控工具tsar
  • TPG领衔财团投资轻奢珠宝品牌APM Monaco
  • 选择阿里云数据库HBase版十大理由
  • ​​​​​​​​​​​​​​汽车网络信息安全分析方法论
  • # 学号 2017-2018-20172309 《程序设计与数据结构》实验三报告
  • ### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTr
  • #微信小程序(布局、渲染层基础知识)
  • (1)SpringCloud 整合Python
  • (16)Reactor的测试——响应式Spring的道法术器
  • (17)Hive ——MR任务的map与reduce个数由什么决定?
  • (cos^2 X)的定积分,求积分 ∫sin^2(x) dx
  • (MATLAB)第五章-矩阵运算
  • (附源码)python旅游推荐系统 毕业设计 250623
  • (附源码)ssm户外用品商城 毕业设计 112346
  • (论文阅读40-45)图像描述1
  • (学习日记)2024.01.09
  • (转)Oracle存储过程编写经验和优化措施
  • (转载)虚函数剖析
  • .Net CoreRabbitMQ消息存储可靠机制
  • .NET/C# 中设置当发生某个特定异常时进入断点(不借助 Visual Studio 的纯代码实现)