Swift 中使用WKWebview的开发记录

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

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

这里的注意点:

image.png

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

image.png

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

image.png

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

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<String, AnyObject> {
            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 的页面,本地有缓存,就请求缓存,没有再去请求。
例如新闻详情这样的不更改内容的静态网页就可以使用这个方式来加载。
这个网页加载的方式的优点是省流量:
网页的内容包括(图片)都可以缓存。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,071评论 4 62
  • 虽然WKWebView是在Apple的WWDC 2014随iOS 8和OS X 10.10出来的,是为了解决UIW...
    winann阅读 135,540评论 196 641
  • 虽然我写作还只是起步,但是我觉得这段时间的练习,有两条比较实用的经验。1刚开始可能下笔很困难,就告诉自己先随便写写...
    佐江阅读 732评论 0 0
  • “嘶,痛,不对,我不是死了吗?” 栗罂吃力地睁开双眼第一个看到的人是一个穿着古代衣服的小姑娘,小姑娘边哭边说:“小...
    破晓的黎阅读 328评论 0 0
  • 哇,今天的书是《习惯的力量》!这本书在我电子书上阅读了一半就搁置了,前阵子听指南针老师的分享,然后又是今天晨读。是...
    云棫阅读 206评论 2 2