8

I have developed an app which shows a web page using WKWebView in Swift. I need to disable the user selection and the callout (because the web loads a graph) and I don't find any way to do this with WKWebView.

This is my code:

import UIKit
import WebKit

class ViewController: UIViewController, WKNavigationDelegate, WKUIDelegate {

    @IBOutlet weak var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let url = URL(string: "https://danfg95glucose.azurewebsites.net")
        let request = URLRequest(url: url!)
        webView.navigationDelegate = self
        webView.load(request)

    }
}

I want to do something similar with this but in Swift with WKWebView:

// Disable user selection
[webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitUserSelect='none';"];
// Disable callout
[webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitTouchCallout='none';"];

Is it possible?

This is a image showing the problem:

enter image description here

Thank you so much for your responses. And sorry for my level, I am new and I am learning programming.

p13n
  • 859
  • 8
  • 31
Daniel Fernandez
  • 241
  • 3
  • 6
  • 14

6 Answers6

16

What you're looking for is adding this css to your WKWebView programmatically.

First, on your view controller, add the WKWebView:

let webViewConfiguration = WKWebViewConfiguration()
let webView = WKWebView(frame: .zero, configuration: webViewConfiguration)
view.addSubview(webView)
webView.snp.updateConstraints { make in
    make.edges.equalTo(view)
}

webView.navigationDelegate = self
webView.load(URLRequest(url: URL(string: "https://www.google.com")!))

Then, implement the navigation delegate method

optional public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)

And inside it add this:

extension ExampleViewController: WKNavigationDelegate {
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        let javascriptStyle = "var css = '*{-webkit-touch-callout:none;-webkit-user-select:none}'; var head = document.head || document.getElementsByTagName('head')[0]; var style = document.createElement('style'); style.type = 'text/css'; style.appendChild(document.createTextNode(css)); head.appendChild(style);"
        webView.evaluateJavaScript(javascriptStyle, completionHandler: nil)
    }
}

With that, you'll add a style tag programmatically with the css that disables callouts.

Hope it helps!

Joel Márquez
  • 419
  • 5
  • 8
2

Text interaction can be disabled like this:

private let webView: WKWebView = {
    let userContentController = WKUserContentController()
    let configuration = WKWebViewConfiguration()
    configuration.userContentController = userContentController
    
    let preferences = WKPreferences()
    if #available(iOS 14.5, *) {
        preferences.isTextInteractionEnabled = false
    }
    configuration.preferences = preferences
    
    let webview = WKWebView(frame: .zero, configuration: configuration)
    return webview
}()
Michael
  • 293
  • 3
  • 12
1

The answer from Joel Marquez is correct, however I want to add that you can use the WKUserContentController instead of the delegate method:

    let selectionString = "var css = '*{-webkit-touch-callout:none;-webkit-user-select:none}';"
        + " var head = document.head || document.getElementsByTagName('head')[0];"
        + " var style = document.createElement('style'); style.type = 'text/css';" +
        " style.appendChild(document.createTextNode(css)); head.appendChild(style);"
    let selectionScript: WKUserScript = WKUserScript(source: selectionString, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
    webView.configuration.userContentController.addUserScript(selectionScript)
Apfelsaft
  • 5,766
  • 4
  • 28
  • 37
1

use userScript or isTextInteractionEnabled

if #available(iOS 14.5, *) {
    webView.configuration.preferences.isTextInteractionEnabled = false
} else {
    let selectionScript = WKUserScript(source: """
                document.body.style.webkitTouchCallout='none';
                document.body.style.webkitUserSelect='none';
            """, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
    webView.configuration.userContentController.addUserScript(selectionScript)
}
yycking
  • 1,017
  • 1
  • 9
  • 14
0

on your page add this. one deactivates the entire page the selection and only enabled in the INPUT

<style type="text/css">
    input[type=text], input[type=password], input[type=email], input[type=number], input[type=time], input[type=date], textarea {
        /* on selection */
        -webkit-touch-callout: auto;
        -webkit-user-select: auto;
    }
    * {
        /* off selection */
        -webkit-touch-callout: none;
        -webkit-user-select: none;
    }

</style>
Enrique Velasquez
  • 636
  • 1
  • 6
  • 4
-1
override func viewDidLoad() 
{
    super.viewDidLoad()
    let longPress:UILongPressGestureRecognizer = UILongPressGestureRecognizer(target: nil, action: nil)
    longPress.minimumPressDuration = 0.3
    webView.addGestureRecognizer(longPress)
}

**//also inherit the UIGestureRecognizerDelegate**

class ViewController: UIViewController, UIGestureRecognizerDelegate {
}
Albin KJ
  • 1
  • 3
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community May 16 '23 at 04:53
  • Please don't post code-only answers. Edit your answer and explain how your answer solves the question. And why do you need to inherit `UIGestureRecognizerDelegate` if you never set the gesture's `delegate` property? – HangarRash May 16 '23 at 04:53