Search code examples
swiftwebkitwkwebview

Swift Inject Javascript to remove HTML element into WebView


I am trying to inject my self directly into the source code.

We want to execute this script to remove a banner on google.com by injecting the javascript into the webview, but it's not working.

This is block of code we are trying to remove:

<mobile-promo jsname="EfADOe" jscontroller="sqHuef" jsaction="rcuQ6b:npT2md"> </mobile-promo>

This is what is not working:

func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
    let removeGoogleBottomBar = """
        function removeDummy() {
            var elem = document.getElementById('mobile-promo');
            elem.parentNode.removeChild(elem);
            return false;
        }
        removeDummy()
    """
    webView.evaluateJavaScript(removeGoogleBottomBar)
}

Is there anything wrong with this approach to injecting javascript?


Solution

  • First, your javascript code will never work because you are trying to retrieve the element with id mobile-promo, but instead the tag name of your element is mobile-promo. (and it doesn't have id attribute)

    If there is only one HTML element with mobile-promo as tag, then the following javascript code will work:

    function removeDummy() {
        var elem = document.getElementsByTagName('mobile-promo')[0];
        elem.parentNode.removeChild(elem);
        return false;
    }
    removeDummy()
    

    If not then you should do something like this:

    function removeDummy() {
        var elem = document.getElementsByTagName('mobile-promo');
        for (var i = 0; i < elem.length; i++) {
            if (elem[i].getAttribute("jsname") == "EfADOe" && elem[i].getAttribute("jscontroller") == "sqHuef" && elem[i].getAttribute("jsaction") == "rcuQ6b:npT2md") {
                elem[i].parentNode.removeChild(elem[i]);
            }
        }
        return false;
    }
    removeDummy()
    

    To inject your javascript code, there is WKUserScript API available from iOS 8. You can do something like this at viewDidLoad:

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let source = """
        function removeDummy() {
            var elem = document.getElementsByTagName('mobile-promo')[0];
            elem.parentNode.removeChild(elem);
            return false;
        }
        removeDummy()
        """
        let script = WKUserScript(source: source, injectionTime: .atDocumentEnd, forMainFrameOnly: false)
        webView.configuration.userContentController.addUserScript(script)
    }
    

    Note that just to be safe, we passing .atDocumentEnd as injectionTime parameter. As documentation states:

    Inject the script after the document finishes loading, but before other subresources finish loading.