WKWebView 中的链接随机不可点击
Posted
技术标签:
【中文标题】WKWebView 中的链接随机不可点击【英文标题】:Links in WKWebView randomly not clickable 【发布时间】:2016-01-09 12:12:50 【问题描述】:在我用 Swift 2.1 编写的 ios 应用程序中,我使用 WKWebView 加载 html 字符串,该字符串是使用 JSON 解析器从 wordpress 博客加载的。
我实现了委托方法 func webView(webView: WKWebView, decidePolicyForNavigationAction navigationAction: WKNavigationAction, decisionHandler: (WKNavigationActionPolicy) -> Void)
并将 WKWebView 的导航委托设置为 self 以处理链接按下。
现在,当我打开包含 WKWebView 的 ViewController 时,此委托方法被调用一次,这是您在加载 webView 时所期望的行为 - 所以委托似乎设置正确。
我现在的问题是大多数时候 webView 包含的链接不可点击。您通常会期望当您按下一个链接时会出现灰色背景,如下图所示。但大多数时候,当我点击一个链接时,灰色背景不会出现,所以当我触摸时,委托方法不会被调用。这个问题当然与WKNavigationDelegate
的错误配置无关,因为有时链接选择可以正常工作(大约 10 %)。
您知道为什么随机链接有时不可点击,有时可点击(10% 的情况)?
【问题讨论】:
如果您能向我们展示您的 html,那就太好了。 忘记importing QuartzCore
了吗?
【参考方案1】:
我假设您想要的是在某个地方有一些描述或文本,并允许在文本的某些部分内进行点击/点击,您想要使用 WKWebView
。
我在很久以前做的一些应用程序中也使用WKWebView
解决了这个问题,当然有几个解决方案,它只是其中一个,没有别的。
正如某些人对您所说,您可以使用loadHTMLString
函数以 JSON 格式或您想要的任何方式从您的服务器加载 HTML 字符串,但非常重要的是 HTML 格式正确且没有错误。
关于loadHTMLString
函数的一个非常重要的一点是关于您的评论...您通常会期望当您按下链接时会出现灰色背景,如下图所示,如果 HTML 没有某种 CSS 样式,则不会发生这种情况,因为如果没有,它具有任何 <a><\a>
的默认样式。
那么让我们看看下面的代码:
import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate
var wkWebView: WKWebView!
override func viewDidLoad()
super.viewDidLoad()
// The part of the HTMl you want to show
let description = "Let's start to visit the <a href=\"http://www.apple.com/\">Apple</a> website first and then if you want the <a href=\"http://www.w3schools.com\">Developer Apple</a> website."
// The default HTML with body and styles formatted and the description inside using string interpolation.
let htmlString = "<html><head><style type=\"text/css\">body font-family: \"Lato-Regular\";font-size: 35px;color: #333333;margin: 0;a text-decoration: none; color: #999;</style></head><body>\(description)</body></html>"
let preferences = WKPreferences()
preferences.javascriptEnabled = false
// Configuration for any preferences you want to set
let configuration = WKWebViewConfiguration()
configuration.preferences = preferences
wkWebView = WKWebView(frame: CGRectMake(5, 35, self.view.bounds.width, self.view.bounds.height), configuration: configuration)
if let theWebView = wkWebView
theWebView.loadHTMLString(htmlString, baseURL: NSURL())
theWebView.navigationDelegate = self
self.view.addSubview(theWebView)
override func didReceiveMemoryWarning()
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
func webView(webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!)
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!)
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
func webView(webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: NSError)
let alert = UIAlertController(title: "Error", message: error.localizedDescription, preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "Ok", style: .Default) (UIAlertAction) -> Void in
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
)
presentViewController(alert, animated: true, completion: nil)
在上面的代码中,我设置了变量description
,其中包含一些带有可点击元素的文本,并添加了两个委托方法didStartProvisionalNavigation
和didFinishNavigation
在状态栏中显示networkActivityIndicatorVisible
以显示一些进度关于点击可点击文本时页面的加载。很高兴注意到在htmlString
变量中我设置了一些样式来显示<a>
的一些颜色和字体,这取决于你。
我还添加了didFailProvisionalNavigation
函数以在某些情况下显示警报,URL 无效,例如添加的新HTTPTransportSecurityLayer
是iOS 9 仅允许https,在某些情况下您可以使用它来验证 url 并了解错误原因。
结果是普通UIViewController
中的以下文本:
当你点击任何灰色文本时,url 将被加载到同一个 WKWebView
中,当然你可以个性化它以在你做的内部浏览器或其他东西中打开,这取决于你。
然后点击Apple即可立即看到结果:
如果您改为点击 Apple 开发者,您可以看到警报在起作用,因为 http 协议在 iOS 9 中的 HTTPTransportSecurityLayer
中给出错误:
如果您需要,我已准备好将项目上传到 Github。希望对您有所帮助。
【讨论】:
感谢您的详细回答,非常感谢。不幸的是,它并没有解决我的问题,因为我已经正确配置了 WKWebView。 你能在 GitHub 上分享你的项目吗? return true 的答案成功了,所以我不需要进一步的帮助。不过还是谢谢!【参考方案2】:解决办法是去掉contentInset
的使用。不幸的是,WKWebView
不是为处理它的使用而设计的(当contentInset
为负数时),因此我们必须使用一种解决方法,只需在 htmlString 中添加一个空的div
,就像这样:
<div style='width:100%;height:100px'></div>
如果要更改底部插图而不重新加载整个页面,可以首先在底部插入一个巨大的div
,然后通过添加一个正数contentInset
来补偿它。这正是这个扩展的作用:
extension WKWebView
/// The maximum possible height of the webView bottom content inset
@nonobjc static let maxBottomHeight: CGFloat = 20000
/// Provides an easy way to set the real bottom inset of the webView. Due to a bug in WKWebView framework, we first insert an emtpy div with the size WKWebView.maxContentSize on the bottom of the webView and compensate it by setting a positive contentInset (should be positive, otherwise the bug will be there again).
func set(bottomInset inset: CGFloat)
self.scrollView.contentInset.bottom = inset - WKWebView.maxBottomHeight
不要忘记在 html 字符串的末尾添加div
:
let htmlFooter = "<div style='width:100%;height:\(String(describing: WKWebView.maxBottomHeight))px'></div></body></html>"
【讨论】:
从 Xcode 10 和 iOS 12 的第一个测试版开始,contentInsets 中的链接不可点击的问题似乎终于得到了解决。【参考方案3】:当您将内容加载到 WKWebView 时,您可能会为网页设置错误的 baseURL,这会导致链接无效,为了使其正常工作,您应该将 baseURL 设置为正确的 http 或 https URL内容,对于那些工作链接只是因为他们的 href 中有完整的 url。
这里是加载到WKWebView中的html文本来说明效果:
webView.loadHTMLString(content, baseURL: NSURL(string: ""));
内容:
<html lang="en"><head><meta name="viewport" content="width=device-width, initial-scale=1"></head>
<body>
<h1> click testing </h1>
<ul>
<li><a href="http://www.w3schools.com">Visit W3Schools</a></li>
<li><a href="/about">Un-Clickable without baseURL</a></li>
<li><a href="about://about">Clickable without baseURL</a></li>
</ul>
</body>
</html>
【讨论】:
不幸的是,它并没有解决我的问题,因为我将一个 html 字符串加载到 webView,而不是网站。 @returnfalse,当然我说的是你的html字符串,那是纯html文本,你介意分享html吗? 感谢您的回答,但这里的问题是,我无法随机打开链接,因此有时特定链接有效,有时无效。如果 baseURL 有问题,它总是不可点击的。 @returnfalse 最好发布一个您遇到问题的项目,如果您长按无效链接会发生什么? return true 的答案成功了,所以我不需要进一步的帮助。不过还是谢谢!以上是关于WKWebView 中的链接随机不可点击的主要内容,如果未能解决你的问题,请参考以下文章
WKWeb 视图。未调用 didStartProvisionalNavigation
iOS 13 beta 中 WKWebView 的内在内容大小问题