iOS – WKWebView笔记(2) — 实现夜间模式 (WKWebViewConfiguration)

WKWebView笔记 — WKWebViewConfiguration

WKWebViewConfiguration 属性分析

/**
 * 核心
 */

// 进程池
open var processPool: WKProcessPool

// webView的偏好设置  (下文详细介绍)
open var preferences: WKPreferences

// 自定义webView的控制器
open var userContentController: WKUserContentController

/**
 * 更多
 */
 
// 可进行缓存操作
open var websiteDataStore: WKWebsiteDataStore

// 是否等完全加载完成再显示网页内容 (默认值false)
open var suppressesIncrementalRendering: Bool

// userAgent
open var applicationNameForUserAgent: String?

// 是否允许AirPlay (默认true)
open var allowsAirPlayForMediaPlayback: Bool

// 确定哪些媒体类型需要用户手势才能开始播放。
open var mediaTypesRequiringUserActionForPlayback: WKAudiovisualMediaTypes

// HTML5视频是否内嵌播放(true)或使用native全屏控制器(false)。(默认值false)
open var allowsInlineMediaPlayback: Bool

// 网页交互中选择内容的粒度。(自动变化/任何字符串边界)
open var selectionGranularity: WKSelectionGranularity

// HTML5视频是否可以播放画中画。
open var allowsPictureInPictureMediaPlayback: Bool

// 数据监测类型 (类似监测网页中的电话号码,邮箱地址等)
open var dataDetectorTypes: WKDataDetectorTypes

// 是否允许页面缩放 (默认值false)
open var ignoresViewportScaleLimits: Bool

WKPreferences 属性

// 字体大小 (默认值0)
open var minimumFontSize: CGFloat

// 是否允许运行JS (默认值true)
open var javaScriptEnabled: Bool

// 是否可以不通过用户的交互打开窗口,默认在iPhone是NO,在Mac上是YES (大概意思是js通过window.open()的方式打开新的页面)
open var javaScriptCanOpenWindowsAutomatically: Bool

WKUserContentController 属性

WKUserContentController为JS提供了一种方法,允许它将消息发送至webView

// 所有的自定义js脚本对象
open var userScripts: [WKUserScript] { get }

// 添加js脚本对象
open func addUserScript(_ userScript: WKUserScript)

// 移除所有js脚本对象
open func removeAllUserScripts()

// js调用iOS原生方法
open func add(_ scriptMessageHandler: WKScriptMessageHandler, name: String)
open func removeScriptMessageHandler(forName name: String)

// 过滤规则有关
open func add(_ contentRuleList: WKContentRuleList)
open func remove(_ contentRuleList: WKContentRuleList)
open func removeAllContentRuleLists()

WKUserScript

// js代码
open var source: String { get }

// 注入时机 (.atDocumentStart 文档开始, .atDocumentEnd 文档结束)
open var injectionTime: WKUserScriptInjectionTime { get }

// 是否只注入main Frame
open var isForMainFrameOnly: Bool { get }

WKScriptMessageHandler

当JS需要调用iOS原生方法时,需要实现该delegate

public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage)

基本可以推断,WKUserContentController 使用 add(_ scriptMessageHandler: WKScriptMessageHandler, name: String) 方法将js和iOS原生代码添加关联后,需要在上述方法中去做响应。 这类似于KVO操作。


实战

接下来通过几个功能分析上述用法。

  1. 夜间模式

首先,需要自定义WKWebViewConfiguration

修改WKWebView实例化代码

// 原来的代码
private lazy var webView: WKWebView = {
    let webView = WKWebView(frame: view.frame)
    webView.addObserver(self, forKeyPath: "estimatedProgress", options: [.old, .new], context: nil)
    webView.allowsBackForwardNavigationGestures = true
    
    return webView
}()

// 修改为
private lazy var webView: WKWebView = {
    let config = WKWebViewConfiguration()
    
    let userContentController = WKUserContentController()
    config.userContentController = userContentController
    
    let webView = WKWebView(frame: view.frame, configuration: config)
    webView.addObserver(self, forKeyPath: "estimatedProgress", options: [.old, .new], context: nil)
    webView.allowsBackForwardNavigationGestures = true
    
    return webView
}()

1. 夜间模式阅读

可以考虑在加载html时注入js,设置所有的div背景色为浅灰色,所有字体颜色为深灰色。

修改上述代码,在userContentController中注入自定义js代码

private lazy var webView: WKWebView = {
// ...    
    let config = WKWebViewConfiguration()
        
    let userContentController = WKUserContentController()
        
    let jsStr = """
        window.onload = function(){
            document.getElementsByTagName('body')[0].style.webkitTextFillColor = '#8F9999'

            let style = document.createElement('style');
            style.type = 'text/css';
            style.innerHTML="*{ background-color:#616465 }";
            document.getElementsByTagName('HEAD').item(0).appendChild(style);

        }
    """
    let userScript = WKUserScript(source: jsStr, injectionTime: .atDocumentStart, forMainFrameOnly: false)
    
    userContentController.addUserScript(userScript)
    
    config.userContentController = userContentController
    
    let webView = WKWebView(frame: view.frame, configuration: config)
    webView.addObserver(self, forKeyPath: "estimatedProgress", options: [.old, .new], context: nil)
    webView.allowsBackForwardNavigationGestures = true
    
    return webView
}()

这里通过注入js的方式去改变css样式,达到一个夜间阅读的功能。