Swift 中使用WKWebview的开发记录

把网页相关的文件打包到APP中

把网页相关文件打包到App中会加快一些js和css文件的加载速度(个人认为,不用耗流量去请求了)

这里的注意点:

Swift 中使用WKWebview的开发记录_第1张图片
image.png

Resourse 文件夹放到这里  Resourse 显示成黄色文件夹

Swift 中使用WKWebview的开发记录_第2张图片
image.png

自己定义的文件夹,需要填加成蓝色文件夹

Swift 中使用WKWebview的开发记录_第3张图片
image.png

folder references 这里就是蓝色的文件夹

Swift 中使用WKWebview的开发记录_第4张图片
image.png

Copy Bundle Resourses 这里你需要看看有没有加到这里来。如果这里没有把文件的引用加进来,Bundle 包里面是找不到这个文件的。 
苹果官方关于如何查找本地资源的文档在这里

For more details on how localized resources are found, read The Bundle Search Pattern in Bundle Programming Guide

.

相关加载代码

      let path = Bundle.main.path(forResource: "view1/html/recordMaterial", ofType: "html")
        let basePath  = (path! as NSString).deletingLastPathComponent
        do{
            // 这里可能会抛出错误,, try 这里会出现错误的。
            //  NSString(contentsOfFile: path!, encoding: String.Encoding.utf8.rawValue
            // 下面的这两个 file    的路径 调用方法 等价
//            let htmlString = ( try NSString(contentsOfFile: path!, encoding: String.Encoding.utf8.rawValue) ) as String
            let htmlString =  try String(contentsOfFile: path!, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue))
            webView.loadHTMLString(htmlString, baseURL:NSURL(fileURLWithPath: basePath) as URL)
        }catch{
            print(error)
        }

注意: forResource: "view1/html/recordMaterial"  这里的路径要替换成你自己的。

WKWebView 中alert(jsString) 不显示的问题

Swift 的代码中,当前加载WKWebview的 Controller遵守WKUIDelegate代理协议,
wkWebviewInstance..uiDelegate = self , 这里的 self 就是当前的 Controller .

copy 一下 代码::

// WKUIDelegate
    // 用于 WkWebView 上面  使用 alert 弹窗 结束
    func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo,
                 completionHandler: @escaping () -> Void) {
        
        let alertController = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)
        alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
            completionHandler()
        }))
        
        present(alertController, animated: true, completion: nil)
    }
    
    
    func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo,
                 completionHandler: @escaping (Bool) -> Void) {
        
        let alertController = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)
        
        alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
            completionHandler(true)
        }))
        
        alertController.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { (action) in
            completionHandler(false)
        }))
        
        present(alertController, animated: true, completion: nil)
    }
    
    
    func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo,
                 completionHandler: @escaping (String?) -> Void) {
        
        let alertController = UIAlertController(title: nil, message: prompt, preferredStyle: .actionSheet)
        
        alertController.addTextField { (textField) in
            textField.text = defaultText
        }
        
        alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
            if let text = alertController.textFields?.first?.text {
                completionHandler(text)
            } else {
                completionHandler(defaultText)
            }
        }))
        
        alertController.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { (action) in
            completionHandler(nil)
        }))
        
        present(alertController, animated: true, completion: nil)
    }
    // 用于 WkWebView 上面  使用 alert 弹窗 结束

我自己试验了一下,WKUIDelegate将JS的弹窗效果展示除了原生iOS的弹窗效果。

WKWebView 传值给 js.

给当前的controller 加一个扩展


extension RecordMaterialViewController: WKNavigationDelegate {
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        let dict = [
            "num1": 4,
            "num2": 8
        ]
        let jsonData = try! JSONSerialization.data(withJSONObject: dict, options: [])
        let jsonString = String(data: jsonData, encoding: String.Encoding.utf8)!
        webView.evaluateJavaScript("addTwoNumbers(\(jsonString));")  { (result, error) in
            guard error == nil else {
                print("there was an error")
                print("error === \(String(describing: error))")
                return
            }
            print("结果是\(result)")
        }
    }
}

Note: evaluateJavaScript这个函数的参数传入的值,必须是JS中在全局作用域下能拿到值的函数或在JS中全局作用域能执行的JS语句。

设置webView.navigationDelegate = self ,设置这个代理

javascript 中定义这个函数 addTwoNumbers


 var addTwoNumbers = function(swiftObj){
            // swiftObj   传过来的已经是一个对象了
            window.total = (swiftObj.num1 || 0) + (swiftObj.num2 || 0);
            alert("xxx===" + window.total )
            return window.total ;
          }

swiftObj 这个就是传过来的数据了

调试JS和页面传值的小技巧

开使用手机App加载 Webview的时候,有时候会遇到 window.xxx 绑定属性和alert 不显示弹窗的问题。有个技巧就是讲你要处理的数据绑定到某个html 页面的元素属性上,或者赋值给span 元素的文字上。

同时打开Xcodejavascript代码编辑器可以提高效率

代码提示,代码片段等等有助于我们编程的东东大多数和编辑器关联。
使用 Xcode 处理iOS . JS代码编辑器处理网页,不要只在 Xcode上处理JS.

调用JS的流程

注意点: 
   使用Swfit 执行javascript 这个方法的时候比较慢。需要使用 swift 传递过来的数据的时候,需要在webView.evaluateJavaScript(XXX) 中的XXX函数数调用其它的代码。否则,swift数据还没传递过来,其它函数执行了就没有正确的数据了。

JS传值给Swfit

如何使用javascriptswift 传值呢,WKUserContentController 可以做这个事情。

第一步

当前的控制器遵守 协议:WKScriptMessageHandler
使用WKUserContentController, WKUserContentController可以提供一个add 方法。
WKUserContentController的实例,可以填加 add的方法:
func add(_ scriptMessageHandler: WKScriptMessageHandler, name: String)
这里面: 
WKScriptMessageHandler 就是遵守这个 WKScriptMessageHandler这个协议的类。在当前控制器这里使用self就可以了。
func add(_ scriptMessageHandler: WKScriptMessageHandler, name: String)这个方法实现之后,
window.webkit.messageHandlers.name.postMessage(messageBody)

import UIKit
import WebKit

class UseHardWareViewController: UIViewController,WKScriptMessageHandler{

}

第二步

创建WKWebViewConfiguration的实例,这个实例可以给网页进行一些配置。注意这个实例只能在 web view第一次创建的时候才能使用。 
WKWebViewConfiguration的实例的一个属性是WKWebViewConfiguration的实例。
WKWebViewConfiguration的实例赋值WKWebViewConfiguration的实例。

第三步

使用 WKWebViewConfiguration的实例来创建webView, 并且将webView 添加到当前的控制器的视图上。

        let o = WKUserContentController()
        o.add(self, name: "foo")
        let config = WKWebViewConfiguration()
        config.userContentController = o
        webView = WKWebView.init(frame: view.bounds, configuration: config)
        self.view.addSubview(webView)

第四步

JS里面实现window.webkit.messageHandlers.name.postMessage(messageBody)

  var messageObj = {
    'tel':'010-12345678',
    'address':'安徽省合肥市滨河西路1200号',
    "dictionary": {"name": "foo"},
    'name':'fool'
  }
  
  window.webkit.messageHandlers.foo.postMessage(messageObj)

第五步

实现这个方法 swift 里面:
 func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage)

 /// Js 给 Swift 传值
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage){
        let body = message.body
        print("body===\(body)")
        if let dict = body as? Dictionary {
            print("dict====\(dict)");
            print("message====\(message)");
            print(message.name)
            if(message.name == "foo"){
                let value = String(describing: dict["name"]!)
                print("body.name: \(value)")
            }
        }
        
    }

打印结果是

body.name: fool

JS 给 Swift 传值就打通了。

WKWebView中web页面跳转处理

extension UseHardWareViewController: WKNavigationDelegate {
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        print("webView===\(webView.url!)")

    }
}

遵守这个协议WKNavigationDelegate后, 每次导航结束后都会有打印。

WKWebView加载了网页之后,对网页进行更改

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
       let  modifyImagesJS =
            "var images = document.getElementsByTagName('img');" +
            "for(var i = 0; i < images.length; i++) {" +
            "images[i].removeAttribute(\"height\");" +
            "images[i].style.height = \"auto\";" +
            "images[i].style.maxWidth = window.innerWidth - 20 * 2;" + 
            "}"
        
        webView.evaluateJavaScript(modifyImagesJS)  { (result, error) in
            guard error == nil else {
                print("there was an error")
                print("error === \(String(describing: error))")
                return
            }
            print("结果是\(result)")
        }
    }

在WKNavigationDelegate中的webView(_:didFinish:) 代码方法中实现,页面跳转完成之后实现更改网页中的图片尺寸。

不同帐号进入相同内容详情


 let url = NSURL(string:"**YourWebPath**");        
        
let request = NSURLRequest.init(url:url! as URL, cachePolicy:NSURLRequest.CachePolicy.returnCacheDataElseLoad, timeoutInterval: 10.0)
        
webView.load(request as URLRequest)

returnCacheDataElseLoad 使用的比较多:

Swift4
Specifies that the existing cached data should be used to satisfy the request, regardless of its age or expiration date. If there is no existing data in the cache corresponding the request, the data is loaded from the originating source.

大意就是如果这个请求的URL 的页面,本地有缓存,就请求缓存,没有再去请求。
例如新闻详情这样的不更改内容的静态网页就可以使用这个方式来加载。
这个网页加载的方式的优点是省流量:
网页的内容包括(图片)都可以缓存。

你可能感兴趣的:(Swift 中使用WKWebview的开发记录)