在 App 开发中,我们总会遇到使用 WebView 的情况, 比如 我们打开了 网页A,然后点击 A 中的链接跳转到 B。如果这个时候,我们按一下系统的返回键,预期的应该是 返回A,而不是推到一个 Native 页面。
但事实就是,如果你没有经过特殊处理,那么很有可能就不是预期的效果(B –> A)。不过还在我们只需要简单修改代码,就能解决。
再次明确一下,我们的预期
- 如果 webview 有可以回退的历史,当系统返回按键点击后,进行 webview 历史回退
- 否则执行 系统回退,返回上一个 native界面
用到的核心代码
WebViewController? _webviewController;
WillPopScope(
onWillPop: () => _exitApp(context),
child: xxx,
}
Future<bool> _exitApp(BuildContext context) async {
if (await _webviewController!.canGoBack()) {
print("onwill goback");
_webviewController!.goBack();
return Future.value(false);
} else {
debugPrint("_exit will not go back");
return Future.value(true);
}
}
- WebViewController 实例 controllerGlobal 是用来判断检测并执行 webview 历史回退。
- 使用 WillPopScope 用来监听 系统的返回键调用,并进行执行系统返回还是 回退 WebView 历史
- 这里利用 controllerGlobal!.canGoBack 来判断是否可以回退 webview 历史
- 如果需要执行 webview 回退历史,调用 controllerGlobal!.goBack(), 否则响应系统回退
完整的实例代码
class WebViewExample extends StatefulWidget {
@override
_WebViewExampleState createState() => _WebViewExampleState();
}
class _WebViewExampleState extends State<WebViewExample> {
late WebViewController _webviewController;
Future<bool> _exitApp(BuildContext context) async {
if (await _webviewController.canGoBack()) {
// 查看 history 有没有可以返回的 如果有 则返回 history
print("onwill goback");
print("进来里唯一返回的");
_webviewController.goBack(); // history 返回
return Future.value(false);
} else {
print("这里history没有返回的");
debugPrint("_exit will not go back");
return Future.value(true);
}
}
@override
void initState() {
super.initState();
_webviewController = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate(
NavigationDelegate(
onProgress: (int progress) {
// Update loading bar.
},
onPageStarted: (String url) {},
onPageFinished: (String url) {
// setState(() {
// showLoading = false;
// });
},
onWebResourceError: (WebResourceError error) {
print("打印失败");
print(error);
},
onNavigationRequest: (NavigationRequest request) {
return NavigationDecision.navigate;
},
),
)
..loadRequest(Uri.parse(
"http://droidyue.com"));
}
@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.
),
// 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 WebViewWidget(
// initialUrl: 'http://droidyue.com',
// javascriptMode: JavascriptMode.unrestricted,
// onWebViewCreated: (WebViewController webViewController) {
// _webviewController = webViewController;
// },
controller: _webviewController,
);
}),
),
);
}
}