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

Flutter WebViewScaffold中tel协议电话功能适配iOS/Android实现方法问询

解决Flutter WebViewScaffold处理tel://电话链接的跨平台方案

我之前开发时也碰到过完全一样的问题!用WebViewScaffold加载带电话拨号链接的网页时,直接点击会跳转到“网页不可用”的错误页面——这是因为WebView本身只认http/https这类标准网页协议,像tel://这种原生系统协议它没法处理。下面是我在iOS和Android上都验证通过的完整解决思路,一步步来:

核心思路

拦截WebView的URL加载请求,当检测到是电话链接(tel:或tel://开头)时,直接调用原生系统的拨号功能,不让WebView去尝试加载这个无效链接。

步骤1:添加必要依赖

除了你已经在用的flutter_webview_plugin,还需要引入url_launcher来跨平台处理拨号动作。在pubspec.yaml里添加:

dependencies:
  flutter_webview_plugin: ^0.4.0
  url_launcher: ^6.1.12

然后执行flutter pub get拉取依赖。

步骤2:实现URL拦截与拨号逻辑

在你的页面代码里,通过监听WebView的URL变化事件来拦截电话链接,然后调用拨号功能:

import 'package:flutter/material.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
import 'package:url_launcher/url_launcher.dart';

class WebViewPage extends StatefulWidget {
  final String url;
  const WebViewPage({Key? key, required this.url}) : super(key: key);

  @override
  State<WebViewPage> createState() => _WebViewPageState();
}

class _WebViewPageState extends State<WebViewPage> {
  final FlutterWebviewPlugin _webviewPlugin = FlutterWebviewPlugin();

  @override
  void initState() {
    super.initState();
    // 监听URL变化,拦截电话链接
    _webviewPlugin.onUrlChanged.listen((String url) {
      if (url.startsWith('tel:')) {
        // 阻止WebView加载这个无效链接
        _webviewPlugin.stopLoading();
        // 提取纯电话号码(去掉tel:或tel://前缀)
        String phoneNumber = url.replaceFirst(RegExp(r'^tel(:|://)'), '');
        // 调用拨号函数
        _makePhoneCall(phoneNumber);
      }
    });
  }

  // 跨平台拨号实现
  Future<void> _makePhoneCall(String phoneNumber) async {
    final Uri phoneUri = Uri(scheme: 'tel', path: phoneNumber);
    if (await canLaunchUrl(phoneUri)) {
      await launchUrl(phoneUri);
    } else {
      // 可以在这里加个Toast提示用户无法拨号
      debugPrint('无法拨打号码:$phoneNumber');
    }
  }

  @override
  void dispose() {
    // 记得销毁WebView实例,避免内存泄漏
    _webviewPlugin.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return WebviewScaffold(
      url: widget.url,
      appBar: AppBar(title: const Text('网页内容')),
      // 可以根据需要添加其他配置,比如支持JavaScript等
      withJavascript: true,
    );
  }
}

步骤3:平台配置(关键)

iOS端

在ios/Runner/Info.plist文件中添加允许调用电话协议的配置,否则iOS会拦截拨号请求:

<key>LSApplicationQueriesSchemes</key>
<array>
  <string>tel</string>
</array>

Android端

不需要额外申请权限——因为我们是跳转到系统自带的拨号界面让用户确认后拨打,不是直接在App内发起呼叫,所以不需要CALL_PHONE权限。如果你的需求是直接拨号(跳过用户确认),才需要在AndroidManifest.xml里添加<uses-permission android:name="android.permission.CALL_PHONE" />,不过这种场景很少见。

额外提示

  • 有些网页可能用的是tel:1231231234(没有双斜杠),所以我们的判断用url.startsWith('tel:')并配合正则替换,能覆盖两种格式的电话链接。
  • 如果你的网页还有sms://(短信)、mailto://(邮件)这类链接,也可以用同样的逻辑拦截处理,只需要修改判断条件和对应的启动协议即可。

内容的提问来源于stack exchange,提问作者PityTheFool

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 04:35:45