You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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.

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 09:44:10