2

I have successfully obtained darkmode effect for random HTML on a website html page using source from this great tutorial.

I have uploaded these photos to explain better what I obtained. Random html loaded

Darkmode applied

I am trying to obtain the same on a WKWebView. The HTML is loaded from an API so I use the WKWebView.loadHTMLString method. For this example the demo HTML is saved in a file in the Xcode project. Also I've added 2 javascript files in Xcode: darkmode.min.js (which is the library) and darkmode-options.js (the position and text label for the toggle in the bottom of the page). I think that I do not inject correctly the 2 scripts using WKUserScript. Obviously the darkmode.min.js must be loaded before darkmode-options.js. That is why I used WKUserScriptInjectionTime.atDocumentStart and WKUserScriptInjectionTime.atDocumentEnd.

Also when I print in the console the view source of the HTML, it does not show the scripts that have been inserted.

 private func initWebView() {

    let html = self.demoHTML
    let jsLibrary = self.darkModeLibraryJS
    let jsOptions = self.darkModeOptionsJS

    let webConfiguration = WKWebViewConfiguration()
    let contentController = WKUserContentController()

    // Libray script an document start
    let userScript = WKUserScript(source: jsLibrary, injectionTime: WKUserScriptInjectionTime.atDocumentStart, forMainFrameOnly: false)
    contentController.addUserScript(userScript)

    // Options script and document end
    let optionsScript = WKUserScript(source: jsOptions, injectionTime: WKUserScriptInjectionTime.atDocumentEnd, forMainFrameOnly: false)
    contentController.addUserScript(optionsScript)

    webConfiguration.userContentController = contentController


    self.webview = WKWebView(frame: CGRect.zero, configuration: webConfiguration)
    self.webview?.navigationDelegate = self
    self.view.addSubview(webview!)

    self.webview!.loadHTMLString(html, baseURL: nil)
    self.webview!.fillSuperview() // after view has been added as subview
}

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    self.chechHTML()
}

private func chechHTML() {

    let script = "document.documentElement.outerHTML.toString()"

    self.webview?.evaluateJavaScript(script, completionHandler: { (html, error) in

        if html != nil {
            print("❌: check html response", html ?? "")
        }
        if error != nil {
            print("❌: check html with error", error ?? "")
        }
    })
}

The project is uploaded on github: https://github.com/CristiGhn/darkmode-webview. The Xcode project also contains a darkmode.html that works and shows the exact as the photos above.

Thank you!

Cristi Ghinea
  • 474
  • 1
  • 7
  • 20
  • 1
    I just added some step logs in darkmode-options.js. It is executed correctly until darkmode = new Darkmode(options); but crashes inside this call. So I guess your swift is correct but the darkmode.min.js script has some features that is not good for the iOS simulator. – AirXygène Jul 09 '19 at 21:45

1 Answers1

1

Using this tutorial I implemented the effect with mix-blend-mode: difference.

Inject multiple WKUserScript in the webiew at document start and document end:

  1. JavaScript file with toggle function at document start
  2. Inject div container with background and blender that will make the blend difference (at document end)
  3. Inside style tags contents of CSS file at document end

    let webConfiguration = WKWebViewConfiguration()
    let contentController = WKUserContentController()
    
    // Libray script an document start
    let darkModeScript = WKUserScript(source: self.darkModeLibraryJS, injectionTime: WKUserScriptInjectionTime.atDocumentStart, forMainFrameOnly: false)
    contentController.addUserScript(darkModeScript)
    
    let injectDarkModeScript = WKUserScript(source: self.injectDarkModeJS, injectionTime: WKUserScriptInjectionTime.atDocumentEnd, forMainFrameOnly: false)
    contentController.addUserScript(injectDarkModeScript)
    
    let injectCSScript = WKUserScript(source: self.injectCSS, injectionTime: WKUserScriptInjectionTime.atDocumentEnd, forMainFrameOnly: false)
    contentController.addUserScript(injectCSScript)
    
    webConfiguration.userContentController = contentController
    
    self.webview = WKWebView(frame: CGRect.zero, configuration: webConfiguration)
    self.webview?.navigationDelegate = self
    self.view.addSubview(webview!)
    
    self.webview!.loadHTMLString(html, baseURL: nil)
    

JavaScript with toggle function and inject CSS (darkmode.js)

function injectCSS(css) {
    head = document.head || document.getElementsByTagName('head')[0],
    style = document.createElement('style');
    head.appendChild(style);

    style.type = 'text/css';
    if (style.styleSheet){
         // This is required for IE8 and below.
        style.styleSheet.cssText = css;
    } else {
        style.appendChild(document.createTextNode(css));
    }
 }

 function showDarkMode() {
     var blender = document.getElementById('blender')
     if (blender.hasAttribute("hidden")) {
         blender.removeAttribute("hidden")
     }
  }

 function showOriginalMode() {
     var blender = document.getElementById('blender')

     if (!blender.hasAttribute("hidden")) {
         blender.setAttribute("hidden", true)
     }
 }

JavaScript with adding div container to DOM of the webview (inject-darkmode.js)

var container = document.createElement('div')
container.id = 'darkmode-container'
document.body.appendChild(container)

var background = document.createElement('div')
background.classList.add('darkmode-background')
container.appendChild(background)

var blender = document.createElement('div')
blender.id = 'blender'
blender.setAttribute('hidden', true)
container.appendChild(blender)

CSS for defining blender and background (darkmode.css)

#blender {
    width: 100vw;
    height: 100vh;
    left: 0pt;
    top: 0pt;
    position: fixed;
    background: white;
    transition: all 1s ease;
    mix-blend-mode: difference;
 }

 img {
     isolation: isolate;
 }

 .darkmode-background {
     position: fixed;
     background: white;
     top: 0;
     left: 0;
     width: 100vw;
     height: 100vh;
     z-index: -1;
 }

Repository with working project: https://github.com/CristiGhn/darkmode-webview

Cristi Ghinea
  • 474
  • 1
  • 7
  • 20