©️ OverlookArt
首页 / AppleDevelop / WKWebview

WKWebview

监听 WKWebview 属性

可监听 title, loading, estimatedProgress, URL, canGoBack, canGoForward

 1import RxSwift
 2import RxCocoa
 3import WebKit
 4extension Reactive where Base: WKWebView {
 5    // 标题
 6    public var title: Observable<String> {
 7        return self.observeWeakly(String.self, "title").map{$0 ?? ""}
 8    }
 9    // url
10    public var url: Observable<URL?> {
11        return self.observeWeakly(URL.self, "URL")
12    }
13    // 加载中
14    public var loading: Observable<Bool> {
15        return self.observeWeakly(Bool.self, "loading").map{$0 ?? false}
16    }
17    // 加载进度   
18    public var progress: Observable<Float> {
19        return self.observeWeakly(Double.self, "estimatedProgress").map { Float($0 ?? 0.0) }
20    }
21    // 可以后退       
22    public var canGoBack: Observable<Bool> {
23        return self.observeWeakly(Bool.self, "canGoBack").map{ $0 ?? false}
24    }
25    // 可以前进    
26    public var canGoForward: Observable<Bool> {
27        return self.observeWeakly(Bool.self, "canGoForward").map { $0 ?? false }
28    }
29}

那些被 WKWebview 抛弃的属性

在 UIWebview 中有这么一个属性 paginationMode 翻页模式,做一些阅读器的功能会使用到,它有五个枚举值:

  • unpaginated 无分页模式
  • leftToRight 从左到右
  • rightToLeft 从右到左
  • topToBottom 从上到下
  • bottomToTop 从下到上

paginationMode 属性虽然被 WKWebView 抛弃了,单还是可以通过 CSS 实现

1body {
2    /* 翻页模式 x:水平,y:垂直 */
3    overflow: -webkit-paged-y !important;
4    /* 翻页方向 t:上,l:左,b:下,r:右, ttb:从上到下 */
5    direction: ttb !important;
6}

注入 JS 脚本

WKWebView 的 configuration 属性下 userContentController 管理用户脚本

 1extension WKWebViewConfiguration {
 2    /// 添加用户脚本
 3    /// - Parameters:
 4    ///   - script: js脚本代码
 5    ///   - injectionTime: 注入时间
 6    ///   - forMainFrameOnly: 是否仅在主Frame注入
 7    ///   - world: 关键词
 8    public func addUserScript(script: String, injectionTime: WKUserScriptInjectionTime, forMainFrameOnly: Bool, world: String? = nil) {
 9        let userScript = WKUserScript(source: script, injectionTime: injectionTime, forMainFrameOnly: forMainFrameOnly)
10        addUserScript(script: userScript)
11    }
12
13    /// 添加用户脚本
14    /// - Parameters:
15    ///   - fileName: js脚本文件名
16    ///   - injectionTime: 注入时间
17    ///   - forMainFrameOnly: 是否仅在主Document注入
18    ///   - world: 关键词
19    public func addUserScript(fileName: String, injectionTime: WKUserScriptInjectionTime, forMainFrameOnly: Bool, world: String? = nil) throws {
20        do {
21            let source = try String(contentsOfFile: Bundle.main.path(forResource: fileName, ofType: "js") ?? "", encoding: .utf8)
22            let userScript = WKUserScript(source: source, injectionTime: injectionTime, forMainFrameOnly: forMainFrameOnly)
23            addUserScript(script: userScript)
24        } catch  {
25            throw error
26        }
27    }
28
29    /// 添加用户脚本
30    /// - Parameter script: 用户脚本
31    func addUserScript(script: WKUserScript) {
32        userContentController.addUserScript(script)
33    }
34    
35    /// 移除所有的用户脚本
36    public func removeAllUserScript() {
37        if userContentController.userScripts.count > 0 {
38            userContentController.removeAllUserScripts()
39        }
40    }
41}

禁用 JavaScript

禁用 JavaScript 后,Web视图不会执行Web内容引用的JavaScript代码。这包括在内联<script>元素、javascript:URL和所有其他引用的JavaScript内容中找到的JavaScript代码。但不会影响 WKUserScripts、evaluteJavaScript、callAsyncJavaScript,它们任可以执行。

 1extension WKWebViewConfiguration {
 2    /// 设置是否启用 JavaScript
 3    /// - Parameter enabled: 是否启用 
 4    public func setupJavaScriptEnabled(_ enabled: Bool) {
 5        if #available(iOS 14.0, *) {
 6            defaultWebpagePreferences.allowsContentJavaScript = enabled
 7        } else {
 8            preferences.javaScriptEnabled = enabled
 9        }
10    }
11}

执行 JS 脚本

WKWebView 提供了直接执行 JS 脚本的方法 evaluateJavaScript(_:completionHandler:)

1webView.evaluateJavaScript("java script") { result, error in
2    // result 执行脚本的结果
3    // error 执行脚本的错误       
4}

接收网页发送的消息

 1class ClassName {
 2    /// 添加脚本消息处理
 3    /// - Parameters:
 4    ///   - handler: 消息处理
 5    ///   - name: 脚本消息名称
 6    public func addScriptMessageHandler(_ handler: WKScriptMessageHandler, name: String) {
 7        webview.configuration.userContentController.add(handler, name: name)
 8    }
 9}
10
11//在网页中发送消息
12//function postMessage(message){
13//    window.webkit.messageHandlers.messageName.postMessage(message);
14//}
15
16//消息处理者需要遵守 WKScriptMessageHandler 协议并实现方法
17extension ClassName: WKScriptMessageHandler{
18    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
19        //接收到消息的名称
20        message.name
21        //接收到消息的内容
22        message.body
23    }
24}

滑动之后白屏问题

子类继承 WKWebView 后,对子类进行扩展并遵守 UIScrollViewDelegate 协议,实现了 UIScrollViewDelegate 中的方法

 1//BaseWebView.swift
 2BaseWebView: WKWebView {
 3    ...
 4}
 5extension BaseWebView: UIScrollViewDelegate {
 6    public func scrollViewDidScroll(_ scrollView: UIScrollView) {
 7        ...
 8    }
 9
10    public func scrollView ...
11}

用 BaseWebView 或者其子类加载网页后,滑动的时候就会出现网页有部分内容没有进行渲染