<!doctype html>
WKWebview学习
WKWebview学习
WKWebView 是苹果在 iOS 8 中引入的新组件,目的是给出一个新的高性能的 Web View 解决方案,摆脱过去 UIWebView 的老旧笨重特别是内存占用量巨大的问题。
- 稳定、功能强大;
- 支持更多的H5;
- KVO;
- 支持高达 60 fps 的滚动刷新率,内置了手势探测;
- 14个类和3个协议;
创建WKWebView
引入WebKit框架,首先配置WKWebView与网页交互的配置项WKWebViewConfiguration;
// 创建一个webiview的配置项
let configuretion = WKWebViewConfiguration()
//将TEST的ScriptMessageHandler注册到webiview的配置项中,这样在js中就可以向native传值 configuretion.userContentController.addScriptMessageHandler(self, name: "TEST")
初始化并配置WKWebView对象;
self.webview = WKWebView(frame: self.view.frame, configuration: configuretion)
self.webview.loadRequest(NSURLRequest(URL: NSURL(string: "http://www.baidu.com/")!))
self.view.addSubview(self.webview)
WKWebView的三个代理
WKNavigationDelegate:与页面导航加载相关
1、该代理提供的方法,可以用来追踪加载过程(页面开始加载、加载完成、加载失败)、决定是否执行跳转。
// 页面开始加载时调用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation;
// 当内容开始返回时调用
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation;
// 页面加载完成之后调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation;
// 页面加载失败时调用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation;
2、页面跳转的代理方法有三种,分为(收到跳转与决定是否跳转两种)
// 接收到服务器跳转请求之后调用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation;
// 在收到响应后,决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;
// 在发送请求之前,决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
WKUIDelegate:与JS交互时的ui展示相关:三种提示框;
/**
* web界面中有弹出警告框时调用
*
* @param webView 实现该代理的webview
* @param message 警告框中的内容
* @param frame 主窗口
* @param completionHandler 警告框消失调用
*/
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(void (^)())completionHandler;
WKScriptMessageHandler:必须实现的方法,这个方法是提高App与web端交互的关键,它可以直接将接收到的JS脚本转为OC或Swift对象
// 从web界面中接收到一个脚本时调用
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;
使用 Safari 自带的 Web View 调试工具
使用步骤,打开Safari偏好设置--》高级--》在菜单栏中先睡“开发”菜单(最下侧);
显示弹窗
在 UIWebView 里,js 的 alert() 弹窗会自动以系统弹窗的形式展示,但是 WKWebview 把这个接口也暴露给了我们,让我们自己 handle js 传来的 alert()。 在控制台中输入alert(1)
即可调用native中的提示框。
func webView(webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: () -> Void) {
let ac = UIAlertController(title: webView.title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
ac.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Cancel, handler: { (aa) -> Void in
completionHandler()
}))
self.presentViewController(ac, animated: true, completion: nil)
}
}
网页向APP传数据、调用APP类方法
在初始化webview时已配置WKWebViewConfiguration;使用window.webkit.messageHandlers.TEST.postMessage()
向APP传值;
苹果在 WKWebView 中的 js runtime 里事先注入了一个 window.webkit.messageHandlers.OOXX.postMessage() 方法,我们可以使用这个方法直接向 Native 层传值,异常方便
随便在控制台post一个数据便可在xcode控制台看到
// func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) {
//
// print(message.name)
// print(message.body.description)
//
// }
传js对象(js 对象的 键 不用加双引号)
在safari控制台中传输js对象,实现
:在APP中获取js对象,并根据对象内容,获取相应的类与该类中的方法。
window.webkit.messageHandlers.TEST.postMessage({className: "ClassName", functionName: "ClassFunc"})
实现WKScriptMessageHandler代理中的方法
func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) {
//根据定义的key来判断message
if message.name == "TEST" {
//转换为字典,并获取key/value
if let dic = message.body as? NSDictionary,
className = dic["className"]?.description,
functionName = dic["functionName"]?.description {
//运行时获取指定类
if let cls = NSClassFromString(NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleName")!.description + "." + className) as? NSObject.Type{
//初始化类对象并调用其方法
let obj = cls.init()
let functionSelector = Selector(functionName)
if obj.respondsToSelector(functionSelector) {
obj.performSelector(functionSelector)
} else {
print("方法未找到!")
}
} else {
print("类未找到!")
}
}
}
}
//创建类以供js调用
class ClassName: NSObject {
func ClassFuc() {
print("js调用APP类方法")
}
}