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
相关产品推荐
相关产品推荐

