电话的 WKWebView 问题:链接
WKWebView issues with tel: links
我已经查看了这个问题的很多答案,但它们现在似乎已经过时了,none 的解决方案对我有用,只是给出了很多错误。
我刚开始使用 xcode 和应用程序,正在将本地 html 文件 "index.html" 加载到 WKWebView。这很好,加载正常,显示正常,但我在页面上有一些 tel: links 不起作用,我点击它们但没有任何效果。我正在为我的 html 文件使用 fraework7,并添加了 "external" class,它适用于 safari 等
更新:使用下面的代码,我可以点击 link,它会尝试调用,但随后会出现致命错误
import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate{
@IBOutlet weak var webview: WKWebView!
override func viewDidLoad() {
webview.navigationDelegate = self
super.viewDidLoad()
let htmlpath = Bundle.main.path(forResource: "index", ofType: "html")
let url = URL(fileURLWithPath: htmlpath!)
let request = URLRequest(url: url)
webview.load(request)
webview.scrollView.bounces = false
webview.configuration.dataDetectorTypes = .phoneNumber
// Do any additional setup after loading the view, typically from a nib.
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Swift.Void) {
if navigationAction.request.url?.scheme == "tel" {
UIApplication.shared.openURL(navigationAction.request.url!)
decisionHandler(.cancel)
}
decisionHandler(.allow)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
和 html 看起来像:
<tr>
<td>Police / Fire / Ambulance</td>
<td>Emergency Services</td>
<td><a href = "tel:999" class = "external">999</a></td>
</tr>
显然是更大 table 的一部分,但这就是示例。
任何指点将不胜感激,因为我已经绕了好久了。
终于找到解决办法:
import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate, WKUIDelegate{
@IBOutlet weak var webView: WKWebView!
override func viewDidLoad() {
webView.navigationDelegate = self
webView.uiDelegate = self
super.viewDidLoad()
let htmlpath = Bundle.main.path(forResource: "index", ofType: "html")
let url2 = URL(fileURLWithPath: htmlpath!)
let request = URLRequest(url: url2)
webView.load(request)
webView.scrollView.bounces = false
//webview.configuration.dataDetectorTypes = .phoneNumber
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
if navigationAction.request.url?.scheme == "tel" {
UIApplication.shared.openURL(navigationAction.request.url!)
decisionHandler(.cancel)
} else {
decisionHandler(.allow)
}
}
使用它似乎可以获取 tel: 链接,我之前在这里找到的答案没有 else 语句,因此多次触发 decisionHandler 导致错误,else 语句修复了这个问题,现在看来很好。
只需使用 WKNavigationDelegate
和 dataDetectorTypes
进行 WKWebView
配置,如下所示:
webView.navigationDelegate = self
webView.configuration.dataDetectorTypes = [.link, .phoneNumber]
extension PDFWebViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
if let requestUrl = navigationAction.request.url, requestUrl.scheme == "tel" {
UIApplication.shared.open(requestUrl, options: [:], completionHandler: nil)
decisionHandler(.cancel)
} else {
decisionHandler(.allow)
}
}
}
不仅仅是 tel:
link 不是 WKWebView 开箱即用的。其他 link 像 mailto:
和 facetime:
也没有被处理。有关此类特殊 link 的完整列表,请参阅 Apple's documentation.
您应该决定要处理哪些 Apple 的特殊 link(请参阅上面的 link),并以类似于以下的方式覆盖导航处理程序:
webView.navigationDelegate = self
...
extension ViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
guard let url = navigationAction.request.url else {
decisionHandler(.allow)
return
}
if ["tel", "sms", "facetime"].contains(url.scheme) && UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
decisionHandler(.cancel)
} else {
decisionHandler(.allow)
}
}
}
我能想到的唯一原因是 Apple 没有首先包含它,因为当您尝试在 Mobile Safari 中启动这些 links 之一时,它会显示一个对话框,例如以下:
This website has been blocked from automatically starting a call.
[Ignore] [Allow Call]
因此,他们可能希望您希望在您的应用中实现类似的功能,而不仅仅是启动调用。
但是请注意,每种 link 的行为都不同:
tel:
对话框显示带有 call/cancel 按钮的 phone 号码。
sms:
启动消息应用程序。
mailto:
启动邮件应用程序。
因此,如果您确实希望拥有某种模式,允许用户在他们不想执行该操作时取消,这取决于您支持的操作,它可能已经具有类似的行为(例如 tel:
).
虽然建议的答案工作正常 - 我建议使用白名单方法而不是黑名单。我们知道 WKWebView 只能处理 http/https link 所以我们可以优雅地处理打开任何其他类型的 link.
的错误
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
self.handleNavigationError(error)
}
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
self.handleNavigationError(error)
}
private func handleNavigationError(_ error: Error) {
if let failedUrl = (error as NSError).userInfo[NSURLErrorFailingURLErrorKey] as? URL, failedUrlScheme = failedUrl.scheme?.lowercased(), !["http", "https"].contains(failedUrlScheme) {
UIApplication.shared.open(failedUrl, completionHandler: nil)
} else {
// handle other errors if needed
}
}
在这种情况下,您将支持所有类型的外部应用 link,例如 tel:
、sms:
、faceTime:
、itms-services:
等
我已经查看了这个问题的很多答案,但它们现在似乎已经过时了,none 的解决方案对我有用,只是给出了很多错误。
我刚开始使用 xcode 和应用程序,正在将本地 html 文件 "index.html" 加载到 WKWebView。这很好,加载正常,显示正常,但我在页面上有一些 tel: links 不起作用,我点击它们但没有任何效果。我正在为我的 html 文件使用 fraework7,并添加了 "external" class,它适用于 safari 等
更新:使用下面的代码,我可以点击 link,它会尝试调用,但随后会出现致命错误
import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate{
@IBOutlet weak var webview: WKWebView!
override func viewDidLoad() {
webview.navigationDelegate = self
super.viewDidLoad()
let htmlpath = Bundle.main.path(forResource: "index", ofType: "html")
let url = URL(fileURLWithPath: htmlpath!)
let request = URLRequest(url: url)
webview.load(request)
webview.scrollView.bounces = false
webview.configuration.dataDetectorTypes = .phoneNumber
// Do any additional setup after loading the view, typically from a nib.
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Swift.Void) {
if navigationAction.request.url?.scheme == "tel" {
UIApplication.shared.openURL(navigationAction.request.url!)
decisionHandler(.cancel)
}
decisionHandler(.allow)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
和 html 看起来像:
<tr>
<td>Police / Fire / Ambulance</td>
<td>Emergency Services</td>
<td><a href = "tel:999" class = "external">999</a></td>
</tr>
显然是更大 table 的一部分,但这就是示例。
任何指点将不胜感激,因为我已经绕了好久了。
终于找到解决办法:
import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate, WKUIDelegate{
@IBOutlet weak var webView: WKWebView!
override func viewDidLoad() {
webView.navigationDelegate = self
webView.uiDelegate = self
super.viewDidLoad()
let htmlpath = Bundle.main.path(forResource: "index", ofType: "html")
let url2 = URL(fileURLWithPath: htmlpath!)
let request = URLRequest(url: url2)
webView.load(request)
webView.scrollView.bounces = false
//webview.configuration.dataDetectorTypes = .phoneNumber
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
if navigationAction.request.url?.scheme == "tel" {
UIApplication.shared.openURL(navigationAction.request.url!)
decisionHandler(.cancel)
} else {
decisionHandler(.allow)
}
}
使用它似乎可以获取 tel: 链接,我之前在这里找到的答案没有 else 语句,因此多次触发 decisionHandler 导致错误,else 语句修复了这个问题,现在看来很好。
只需使用 WKNavigationDelegate
和 dataDetectorTypes
进行 WKWebView
配置,如下所示:
webView.navigationDelegate = self
webView.configuration.dataDetectorTypes = [.link, .phoneNumber]
extension PDFWebViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
if let requestUrl = navigationAction.request.url, requestUrl.scheme == "tel" {
UIApplication.shared.open(requestUrl, options: [:], completionHandler: nil)
decisionHandler(.cancel)
} else {
decisionHandler(.allow)
}
}
}
不仅仅是 tel:
link 不是 WKWebView 开箱即用的。其他 link 像 mailto:
和 facetime:
也没有被处理。有关此类特殊 link 的完整列表,请参阅 Apple's documentation.
您应该决定要处理哪些 Apple 的特殊 link(请参阅上面的 link),并以类似于以下的方式覆盖导航处理程序:
webView.navigationDelegate = self
...
extension ViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
guard let url = navigationAction.request.url else {
decisionHandler(.allow)
return
}
if ["tel", "sms", "facetime"].contains(url.scheme) && UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
decisionHandler(.cancel)
} else {
decisionHandler(.allow)
}
}
}
我能想到的唯一原因是 Apple 没有首先包含它,因为当您尝试在 Mobile Safari 中启动这些 links 之一时,它会显示一个对话框,例如以下:
This website has been blocked from automatically starting a call.
[Ignore] [Allow Call]
因此,他们可能希望您希望在您的应用中实现类似的功能,而不仅仅是启动调用。
但是请注意,每种 link 的行为都不同:
tel:
对话框显示带有 call/cancel 按钮的 phone 号码。sms:
启动消息应用程序。mailto:
启动邮件应用程序。
因此,如果您确实希望拥有某种模式,允许用户在他们不想执行该操作时取消,这取决于您支持的操作,它可能已经具有类似的行为(例如 tel:
).
虽然建议的答案工作正常 - 我建议使用白名单方法而不是黑名单。我们知道 WKWebView 只能处理 http/https link 所以我们可以优雅地处理打开任何其他类型的 link.
的错误func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
self.handleNavigationError(error)
}
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
self.handleNavigationError(error)
}
private func handleNavigationError(_ error: Error) {
if let failedUrl = (error as NSError).userInfo[NSURLErrorFailingURLErrorKey] as? URL, failedUrlScheme = failedUrl.scheme?.lowercased(), !["http", "https"].contains(failedUrlScheme) {
UIApplication.shared.open(failedUrl, completionHandler: nil)
} else {
// handle other errors if needed
}
}
在这种情况下,您将支持所有类型的外部应用 link,例如 tel:
、sms:
、faceTime:
、itms-services:
等