点击 H5 页面返回键没有反应

来源:12-5 基于H5容器实现H5混合开发

LGTTX

2025-03-30

老师你好,我用的仓库的 trip_flutter 项目运行的,然后点击 x 返回是正常的,但是点击
H5 的返回键时,返回不到 flutter 页面,看控制台也没报错,是出了什么 bug 么,还是因为 webView 更新导致的呢!
我用的是最新的 flutter 版本
图片描述

trip_flutter 的源码:

hi_webview.dart:
import ‘package:flutter/material.dart’;
import ‘package:trip_flutter/util/navigator_util.dart’;
import ‘package:webview_flutter/webview_flutter.dart’;

///H5容器
class HiWebView extends StatefulWidget {
final String? url;
final String? statusBarColor;
final String? title;
final bool? hideAppBar;

///禁止我的页面返回按钮
final bool? backForbid;

const HiWebView(
{super.key,
this.url,
this.statusBarColor,
this.title,
this.hideAppBar,
this.backForbid});

@override
State createState() => _HiWebViewState();
}

class _HiWebViewState extends State {
///主页代表的url
final _catchUrls = [
m.ctrip.com/’,
m.ctrip.com/html5/’,
m.ctrip.com/html5
];
String? url;
late WebViewController controller;

@override
void initState() {
super.initState();
url = widget.url;
if (url != null && url!.contains(‘ctrip.com’)) {
//fix 携程H5 http://无法打开问题
url = url!.replaceAll(“http://”, “https://”);
}
_initWebViewController();
}

@override
Widget build(BuildContext context) {
String statusBarColorStr = widget.statusBarColor ?? ‘ffffff’;
Color backButtonColor;
if (statusBarColorStr == ‘ffffff’) {
backButtonColor = Colors.black;
} else {
backButtonColor = Colors.white;
}
//处理Android物理返回键,返回H5的上一页 https://docs.flutter.dev/release/breaking-changes/android-predictive-back
return PopScope(
// canPop: false,
canPop: false,
onPopInvokedWithResult: (bool didPop, dynamic result) async {
print(‘controller.canGoBack()controller.canGoBack()′);print(′result+result{controller.canGoBack()}'); print('result+resultcontroller.canGoBack());print(result+result{result}’);
if (await controller.canGoBack()) {
//返回H5的上一页
controller.goBack();
} else {
if (context.mounted) NavigatorUtil.pop(context);
}
},
child: Scaffold(
body: Column(
children: [
_appBar(
Color(int.parse(‘0xff$statusBarColorStr’)), backButtonColor),
Expanded(
child: WebViewWidget(
controller: controller,
))
],
),
));
}

void _initWebViewController() {
controller = WebViewController()
…setJavaScriptMode(JavaScriptMode.unrestricted)
…setBackgroundColor(const Color(0x00000000))
…setNavigationDelegate(NavigationDelegate(
onProgress: (int progress) {
debugPrint(‘progress:$progress’);
},
onPageStarted: (String url) {},
onPageFinished: (String url) {
//页面加载完成之后才能执行JS
_handleBackForbid();
},
onWebResourceError: (WebResourceError error) {},
onNavigationRequest: (NavigationRequest request) {
if (_isToMain(request.url)) {
debugPrint(‘阻止跳转到 $request}’);
//返回到flutter页面
NavigatorUtil.pop(context);
return NavigationDecision.prevent;
}
debugPrint(‘允许跳转到 $request}’);
return NavigationDecision.navigate;
}))
…loadRequest(Uri.parse(url!));
}

///隐藏H5登录页的返回键
///实现思路:
/// 1. 通过观察H5我的页面的返回按钮的样式为.animationComponent.rn-view ;
/// 2. 所以通过查找页面中具有类名 .animationComponent.rn-view 的元素,然后通过将它的style.display 设置为 ‘none’来隐藏这个元素;
/// 另外:如果想隐藏的H5返回键不支持怎么办?
/// 可以按照上面因此H5我的页面的思路,在Chrome上打开这个H5页面,然后通过开发者模式找到通过查找页面中的返回按钮的样式class的元素,然后通过将它的style.display 设置为 ‘none’来隐藏这个元素;
void _handleBackForbid() {
const jsStr =
"var element = document.querySelector(’.animationComponent.rn-view’); if(element != null) element.style.display = ‘none’;";
if (widget.backForbid ?? false) {
controller.runJavaScript(jsStr);
}
}

///判断H5是否返回主页
bool _isToMain(String? url) {
bool contain = false;
for (final value in _catchUrls) {
if (url?.endsWith(value) ?? false) {
contain = true;
break;
}
}
return contain;
}

_appBar(Color backgroundColor, Color backButtonColor) {
//获取刘海屏Top安全边距
double top = MediaQuery.of(context).padding.top;
if (widget.hideAppBar ?? false) {
return Container(
color: backgroundColor,
height: top,
);
}
return Container(
color: backgroundColor,
padding: EdgeInsets.fromLTRB(0, top, 0, 10),
child: FractionallySizedBox(
widthFactor: 1,
child: Stack(
children: [_backButton(backButtonColor), _title(backButtonColor)],
),
),
);
}

_backButton(Color backButtonColor) {
return GestureDetector(
onTap: () {
NavigatorUtil.pop(context);
},
child: Container(
margin: const EdgeInsets.only(left: 10),
child: Icon(
Icons.close,
color: backButtonColor,
size: 26,
),
),
);
}

_title(Color backButtonColor) {
return Positioned(
left: 0,
right: 0,
child: Center(
child: Text(
widget.title ?? “”,
style: TextStyle(color: backButtonColor, fontSize: 20),
),
));
}
}

navigator_util.dart :
///返回上一页
static pop(BuildContext context) {
// if (Navigator.canPop(context)) {
// Navigator.pop(context);
// } else {
// //退出APP
// SystemNavigator.pop();
// }
//使用getx返回上一页
Get.back();
}

///跳转H5页面
static jumpH5(
{BuildContext? context,
String? url,
String? title,
bool? hideAppBar,
String? statusBarColor}) {
BuildContext? safeContext;
if (url == null) {
debugPrint(‘url is null jumpH5 failed.’);
return;
}
// if (context != null) {
// safeContext = context;
// } else if (_context?.mounted ?? false) {
// safeContext = _context;
// } else {
// debugPrint(‘context is null jumpH5 failed.’);
// return;
// }
// Navigator.push(
// safeContext!,
// MaterialPageRoute(
// builder: (context) => HiWebView(
// url: url,
// title: title,
// hideAppBar: hideAppBar,
// statusBarColor: statusBarColor,
// )));
//使用getx跳转到H5页面
Get.to(HiWebView(
url: url,
title: title,
hideAppBar: hideAppBar,
statusBarColor: statusBarColor,
));
}

写回答

1回答

CrazyCodeBoy

2025-03-31

跟webview无关,如果想点击H5返回到flutter可以在这个方法中通过判断url的方式来来控制,返回true代表回到flutter。

///判断H5是否返回主页
bool _isToMain(String? url) {
bool contain = false;
for (final value in _catchUrls) {
if (url?.endsWith(value) ?? false) {
contain = true;
break;
}
}
return contain;
}
0
0

慕课甄选-Flutter零基础极速入门到进阶实战

全新Flutter从入门到进阶,实战仿携程网App

661 学习 · 316 问题

查看课程