如何在 WKWebView 中注入多个用户脚本以获得暗模式效果?

Posted

技术标签:

【中文标题】如何在 WKWebView 中注入多个用户脚本以获得暗模式效果?【英文标题】:How to inject multiple user scripts in WKWebView to obtain darkmode effect? 【发布时间】:2019-07-09 09:42:42 【问题描述】:

我已经使用来自这个伟大的tutorial 的源代码成功地在网站 html 页面上获得了随机 HTML 的暗模式效果。

我上传了这些照片以更好地解释我获得的东西。

我试图在 WKWebView 上获得相同的结果。 HTML 是从 API 加载的,因此我使用 WKWebView.loadHTMLString 方法。 对于此示例,演示 HTML 保存在 Xcode 项目的文件中。 我还在 Xcode 中添加了 2 个 javascript 文件:darkmode.min.js(这是库)和 darkmode-options.js(页面底部切换的位置和文本标签)。 我认为我没有正确注入使用 WKUserScript 的 2 个脚本。显然,darkmode.min.js 必须在 darkmode-options.js 之前加载。这就是我使用 WKUserScriptInjectionTime.atDocumentStart 和 WKUserScriptInjectionTime.atDocumentEnd 的原因。

此外,当我在控制台中打印 HTML 的视图源时,它不会显示已插入的脚本。

 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 ?? "")
        
    )

项目上传到github:https://github.com/CristiGhn/darkmode-webview。 Xcode 项目还包含一个 darkmode.html,它的工作原理与上面的照片完全相同。

谢谢!

【问题讨论】:

我刚刚在 darkmode-options.js 中添加了一些步骤日志。它一直正确执行,直到 darkmode = new Darkmode(options);但在此调用中崩溃。所以我猜你的 swift 是正确的,但是 darkmode.min.js 脚本有一些不适合 ios 模拟器的功能。 【参考方案1】:

使用这个tutorial,我使用 mix-blend-mode: difference 实现了效果。

在文档开始和文档结束的webiew中注入多个WKUserScript:

    在文档开始时具有切换功能的 JavaScript 文件 注入带有背景和搅拌器的 div 容器,这将产生不同的混合效果(在文档末尾)

    文档末尾CSS文件的内部样式标签内容

    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 和注入 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)
     
 

将 div 容器添加到 webview 的 DOM 的 JavaScript (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 (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;
 

带有工作项目的存储库:https://github.com/CristiGhn/darkmode-webview

【讨论】:

以上是关于如何在 WKWebView 中注入多个用户脚本以获得暗模式效果?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Swift 3 的 WKWebView 中注入 javascript

如何在 iOS webview 的多个页面中注入/评估 JS?

Swift:向WKWebView注入JS和CSS不起作用

如何使用 iOS WKWebView 注入 JavaScript 回调来检测 onclick 事件?

如何在没有 JavaScript 的情况下将 cookie 注入 WKWebView 或 WKWebSiteDataStore?

WKWebView禁止缩放拾遗