如何在Flutter中使用flutter_webview_plugin打开tel:与mailto:链接?并解决webview_flutter的菜单及地址栏无法隐藏问题
Hey there! Let's work through these two WebView issues you're facing—they're both solvable with a few targeted tweaks.
1. Fixing tel: and mailto: links in flutter_webview_plugin
The flutter_webview_plugin doesn't handle these special scheme links natively, so we'll need to intercept them and use the url_launcher package to open the native phone/mail apps instead. Here's how to set it up:
First, add the url_launcher dependency to your pubspec.yaml:
dependencies: flutter_webview_plugin: ^0.4.0 url_launcher: ^6.2.5 # Use the latest version available
Then, set up a listener to intercept URL changes and handle the special schemes:
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart'; import 'package:url_launcher/url_launcher.dart'; final flutterWebviewPlugin = FlutterWebviewPlugin(); void initWebView() { // Listen for URL changes in the WebView flutterWebviewPlugin.onUrlChanged.listen((String url) { if (url.startsWith('tel:') || url.startsWith('mailto:')) { // Launch the native app for the scheme _launchExternalUrl(url); // Stop the WebView from trying to load the non-web link flutterWebviewPlugin.stopLoading(); } }); } Future<void> _launchExternalUrl(String url) async { final uri = Uri.parse(url); if (!await launchUrl(uri)) { throw Exception('Could not launch $url'); } }
Now any tel: or mailto: link clicked in the WebView will open the native phone dialer or mail app instead of being ignored by the WebView.
2. Hiding top address bar and bottom menu in webview_flutter
The webview_flutter package doesn't include default top/bottom UI elements out of the box, so I assume you're either working with custom AppBar/BottomNavigationBar components, or wanting to hide system UI like the status bar. Let's cover both scenarios:
Scenario A: Hiding custom AppBar and BottomNavigationBar
If you've wrapped your WebView in a Scaffold with these custom elements, toggle their visibility using state management:
import 'package:flutter/material.dart'; import 'package:webview_flutter/webview_flutter.dart'; class WebViewScreen extends StatefulWidget { const WebViewScreen({super.key}); @override State<WebViewScreen> createState() => _WebViewScreenState(); } class _WebViewScreenState extends State<WebViewScreen> { bool _showCustomUI = false; // Controls visibility of AppBar/BottomNav @override Widget build(BuildContext context) { return Scaffold( // Show AppBar only when _showCustomUI is true appBar: _showCustomUI ? AppBar(title: const Text('WebView')) : null, // Show BottomNavigationBar only when _showCustomUI is true bottomNavigationBar: _showCustomUI ? BottomNavigationBar( items: const [ BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'), BottomNavigationBarItem(icon: Icon(Icons.settings), label: 'Settings'), ], ) : null, body: WebView( initialUrl: 'https://your-target-url.com', javascriptMode: JavascriptMode.unrestricted, onPageStarted: (url) { // Optional: Show UI while page loads setState(() => _showCustomUI = true); }, onPageFinished: (url) { // Hide UI once page finishes loading setState(() => _showCustomUI = false); }, ), ); } }
Scenario B: Hiding system status bar and navigation bar
To make the WebView full-screen (hiding system UI), use SystemChrome to adjust the system UI mode:
import 'package:flutter/services.dart'; import 'package:webview_flutter/webview_flutter.dart'; class FullScreenWebView extends StatefulWidget { const FullScreenWebView({super.key}); @override State<FullScreenWebView> createState() => _FullScreenWebViewState(); } class _FullScreenWebViewState extends State<FullScreenWebView> { @override void initState() { super.initState(); // Hide system status bar and navigation bar SystemChrome.setEnabledSystemUIMode( SystemUiMode.immersiveSticky, overlays: [], ); } @override void dispose() { // Restore system UI when leaving the screen SystemChrome.setEnabledSystemUIMode( SystemUiMode.edgeToEdge, overlays: [SystemUiOverlay.top, SystemUiOverlay.bottom], ); super.dispose(); } @override Widget build(BuildContext context) { return const WebView( initialUrl: 'https://your-target-url.com', javascriptMode: JavascriptMode.unrestricted, ); } }
Bonus: To handle tel: and mailto: links in webview_flutter, use the navigationDelegate property:
WebView( initialUrl: 'https://your-target-url.com', javascriptMode: JavascriptMode.unrestricted, navigationDelegate: (NavigationRequest request) { if (request.url.startsWith('tel:') || request.url.startsWith('mailto:')) { _launchExternalUrl(request.url); return NavigationDecision.prevent; // Block WebView from loading the link } return NavigationDecision.navigate; // Allow regular web links to load }, )
Don't forget to add the url_launcher dependency here too, just like in the first solution.
内容的提问来源于stack exchange,提问作者Smartak

