如何覆盖 wkwebview 超链接操作表

Posted

技术标签:

【中文标题】如何覆盖 wkwebview 超链接操作表【英文标题】:How to override wkwebview hyperlink action sheet 【发布时间】:2015-12-14 19:45:43 【问题描述】:

当您长按 WkWebview 中的超链接时,您会得到一个操作表。我想在长按时用我自己的一组选项覆盖该操作表,但在其他情况下表现正常。我可以获得长按事件,但我不知道如何:

    阻止显示默认操作表 防止 web 视图在长按结束时导航到 URL。 获取 Web 视图直接指向的基础 href URL 或 html 标记本身和关联的属性,例如 ID。

【问题讨论】:

你控制 HTML 吗? @LouFranco 是的,我可以完全控制 html。 【参考方案1】:

取消操作表的一种简单(但激进)的方法是覆盖 presentViewController:animated:completion: 在您应用的根视图控制器中。

Swift 3 示例

override func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) 

  guard let alertController = viewControllerToPresent as? UIAlertController,
  alertController.preferredStyle == .actionSheet else 
    // Not an alert controller, present normally
    super.present(viewControllerToPresent, animated: flag, completion: completion)
    return    
  

  // Create and open your own custom alert sheet
  let customAlertController = UIAlertController(...)
  super.present(customAlertController, animated: flag, completion: completion)

您可以从alertController.title 检索链接的URL,如果您需要检索其他属性,我建议您查看this commit 到Firefox ios,它使用JS 脚本处理程序来查找单击的元素并发送其属性返回应用程序。

您还需要编写一些逻辑来防止取消除 WKWebView 之外的任何其他警报表,您的应用可能会使用这些表。

【讨论】:

我尝试了这种方法,但没有成功,因为WKActionSheet 不会(出于某种原因)总是被present() 触发。我最终使用了持续时间技术link 并实现了gestureRecognizer(gestureRecognizer:shouldRecognizeSimultaneouslyWith:)【参考方案2】:

这是覆盖菜单的有效解决方案。我仍然想获取一些 html 属性,但还不知道该怎么做。

override func loadView() 
    super.loadView()

    let contentController = WKUserContentController();
    let userScript = WKUserScript(
        source: "redHeader()",
        injectionTime: WKUserScriptInjectionTime.AtDocumentEnd,
        forMainFrameOnly: true
    )
    contentController.addUserScript(userScript)
    contentController.addScriptMessageHandler(
        self,
        name: "callbackHandler"
    )
    let config = WKWebViewConfiguration()
    config.userContentController = contentController
    self.webView = WKWebView(frame: self.view.frame, configuration: config)
    self.webView.navigationDelegate = self
    self.view = self.webView
    let lpress = UILongPressGestureRecognizer(target: self, action: "webViewLongPressed:")
    lpress.delegate = self
    self.webView.scrollView.addGestureRecognizer(lpress)


func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool 
    return true


func webViewLongPressed(sender:UILongPressGestureRecognizer!) 
    longpress = true
    if (sender.state == UIGestureRecognizerState.Ended) 
        print("Long press Ended")
        //This is where everything starts to happen
     else if (sender.state == UIGestureRecognizerState.Began) 
        print("Long press detected.")

    



func webView(webView: WKWebView, decidePolicyForNavigationAction navigationAction: WKNavigationAction, decisionHandler: ((WKNavigationActionPolicy) -> Void)) 
    if let myUrlStr : String = navigationAction.request.URL!.absoluteString 

        if myUrlStr.lowercaseString.rangeOfString("/book/") != nil 
            /* Do not allow links to be tapped */
            var parts = myUrlStr.componentsSeparatedByString("/")
            let id = Int(parts[4])
            if navigationAction.navigationType == .LinkActivated && longpress == true 

                decisionHandler(.Cancel)
                let ac = actionMenu(self, id: id!, user_id: 1)
                self.presentViewController(ac, animated: true) 

                
                longpress = false
                return
            
        
    
    decisionHandler(.Allow)


//Build action sheet
func actionMenu(sender: UIViewController, id: Int, user_id: Int) -> UIAlertController 

    let alertController = UIAlertController(title: "Title", message: "Some message.", preferredStyle: .ActionSheet)

    let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel)  (action) in

    
    alertController.addAction(cancelAction)
    let someAction = UIAlertAction(title: "Some action", style: .Default)  (action) in
        //do something, call a function etc, when this action is selected
    
    alertController.addAction(someAction)

    return alertController

【讨论】:

要获取 html 属性,请在页面上放置一个可以执行所需操作的 javascript 函数,然后使用 evaluateJavaScript: ***.com/questions/24049343/… 从 swift 调用它 @LouFranco 仅在您知道要从中获取属性的元素需要点击位置时才有效。我想您可以在长按时保存该位置,以编程方式在该位置触发触摸事件...然后您还必须创建一些自定义 javascript 并传递有关该事件的详细信息...感觉非常复杂。 =/ 这就是生活。 可以注册HTML交互触发的JavaScript可以调用的swift函数(页面可以调用你)--见WKScriptMessageHandler

以上是关于如何覆盖 wkwebview 超链接操作表的主要内容,如果未能解决你的问题,请参考以下文章

OUT 了??还没玩转报表超链接

如何通过报表单元格右键控制报表跳转到不同链接地址

在 WKWebView 中打开外部链接(不是外部)

数据结构自学笔记 链表超进化

wordpress 上超链接文本的大字体

如何使用 WKWebview 检查链接是不是损坏?