WKWebView与JS交互,UIWebView+JavascriptCore和JS交互
最近一直在做有关Swift和JavaScript交互的程序,所以有关UIWebView和WKWebView在使用上的差别在此总结下:
UIWebView:
(1)创建
var webView: UIWebView! self.webView = UIWebView.init(frame: CGRect.init(x: 0, y: 0, width: kScreenWidth, height: kScreenHeight)) self.view.addSubview(self.webView!) self.webView.delegate = self
(2)请求
let url = "" let request = NSURLRequest(URL: NSURL(string: url)!) self.webView.loadRequest(request)
(3)常用代理
UIWebViewDelegate func webViewDidStartLoad(webView: UIWebView) { } func webView(webView: UIWebView, didFailLoadWithError error: NSError?) { } func webViewDidFinishLoad(webView: UIWebView) { }
UIWebView最屌的当然还是结合传说中的JavaScriptCore的Hybrid方式了
(4)在UIWebView中注入(执行)JS (注意要在webViewDidFinishLoad回调,也就是加载完后才能执行)
//第一种方法,直接webview执行(应该是封装了下面的方法二) let resultStr="1234" self.webView.stringByEvaluatingJavaScriptFromString("theFunc('"+resultStr+"');")! as String //第二种,使用kvc来取得mainframe的context,然后执行 let context = webView.valueForKeyPath("documentView.webView.mainFrame.javaScriptContext") as! JSContext context.evaluateScript(theScript)
(5)在UIWebView中监听JS的函数,这种方式可以通过原生return来call back,不过return是一种同步的call back。不是非常好。
let context = webView.valueForKeyPath("documentView.webView.mainFrame.javaScriptContext") as! JSContext //假如JS传给原生一个JSON的字符串 let accountSerial: @convention(block) String -> () = { _ in let value = JSContext.currentArguments().first let data = value?.toString().dataUsingEncoding(NSUTF8StringEncoding) let accountInfoDic = try? NSJSONSerialization.JSONObjectWithData(data!, options:[]) as! NSDictionary } context.setObject(unsafeBitCast(accountSerial, AnyObject.self), forKeyedSubscript: "saveAccountInfo") //假如需要原生return一个JSON的字符串 let cookiesSerial : @convention(block) () -> String = { let cookies = NSHTTPCookieStorage.sharedHTTPCookieStorage().cookiesForURL((webView.request?.URL)!) let header=NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!) as NSDictionary if(header.objectForKey("Cookie") != nil) { return cookies.toJsonString() } }
(6)另外一种奇葩的通过URL拦截的方式,让JS调用原生
http://www.cnblogs.com/rayshen/p/4560728.html
WKWebView:
(1)创建,需要import的框架和继承的协议
//需要导入 import WebKit class MXWebDemoController:UIViewController,WKNavigationDelegate,WKUIDelegate,WKScriptMessageHandler{} private var webView:WKWebView! private var progressView:UIProgressView! //进度条 progressView = UIProgressView(progressViewStyle: UIProgressViewStyle.Default) progressView.frame = CGRectMake(0, 0, UIScreen.mainScreen().bounds.width, 22) progressView.tintColor = UIColor.blueColor() self.view.addSubview(progressView) //初始化 let conf = WKWebViewConfiguration() webView = WKWebView(frame: CGRectMake(0,0,kScreenWidth,kScreenHeight), configuration: conf) self.view.insertSubview(webView, belowSubview: progressView)
(2)请求
let request = NSURLRequest(URL: NSURL(string:baseUrl)!, cachePolicy: .ReloadIgnoringLocalCacheData, timeoutInterval: 10)
self.webView.loadRequest(request)
(3)常用代理
//webview加载完,重置进度条 func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) { progressView.setProgress(0.0, animated: false) } //kvo监听 override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) { if keyPath == "estimatedProgress" { progressView.hidden = webView.estimatedProgress == 1 progressView.setProgress(Float(webView.estimatedProgress), animated: true) } } //和JS消息交互 // MARK: - WKScriptMessageHandler func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) { if(message.name == "mxBack"){ self.navigationController?.popViewControllerAnimated(true) } }
(4)JS注入,最基本的就是evaluateJavaScript函数,在页面加载完后去执行。再而,WKWebView新增了JS注入的接口。
//方法1 let jsStr = "" webView.evaluateJavaScript(jsStr),completionHandler: { (object, error) in if(error != nil){ print(error) } }) //方法2 let script = WKUserScript(source:self.scriptStr,injectionTime: .AtDocumentStart,forMainFrameOnly: true)
(5)接受来自JS的消息
//1 conf.userContentController.addScriptMessageHandler(self, name:"mxBack") //2 func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) { weak var weakself = self if(message.name == "mxBack"){ self.hasGetResult = true self.gotoBack() } }
有关WKWebView,有个缺点,就是和JS之间没有同步的函数(依靠return来回传的方式)。
之前大部分iOS项目都是使用UIWebView,现在iOS8后Webkit良好的性能取代了UIWebView,但它的异步对很多旧的Web工程都有点影响。
别人的Demo:
https://github.com/CoderJackyHuang/WKWebViewTestDemo
下周有空我会写个更好的,更详细的介绍JS和原生之间的交互。
___________________________________________________
专注iOS/前端开发,广泛涉猎多种平台和技术,欢迎交流
可以在微博关注并@沈z伟