iOS 使用WKWebView替换UIWebView(二)——代码实战(包括OC与JS互调)
2016-06-30 02:06
603 查看
1、ViewController.h
2、ViewController.m
// // ViewController.h // WebViewDemo // // Created by 555chy on 6/28/16. // Copyright © 2016 555chy. All rights reserved. // #import <UIKit/UIKit.h> #import <WebKit/WebKit.h> @interface ViewController : UIViewController<WKNavigationDelegate, WKUIDelegate, WKScriptMessageHandler> @end
2、ViewController.m
// // ViewController.m // WebViewDemo // // Created by 555chy on 6/28/16. // Copyright © 2016 555chy. All rights reserved. // #import "ViewController.h" #define SCRIPT_MESSAGE_HANDLER_NAME @"scriptMessageHandlerName" @interface ViewController () @property UIButton *button; @property WKWebView *webView; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. CGRect rect = self.view.bounds; //把内容的范围减去标题栏 rect.origin.y += 22; rect.size.height -= 22; self.button = [[UIButton alloc] initWithFrame:CGRectMake(rect.origin.x, rect.origin.y+rect.size.height-50, rect.size.width, 50)]; self.button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter; self.button.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter; [self.button setTitle:@"button" forState:UIControlStateNormal]; [self.button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; [self.button setBackgroundColor:[UIColor blackColor]]; [self.view addSubview:self.button]; NSString *js = @"var count = document.images.length; for(var i=0;i<count;i++) {var image = document.images[i]; image.style.width=320;}; window.alert('找到'+count+'张图')"; /* @enum WKUserScriptInjectionTime @abstract when a user script should be injected into a webpage. @constant WKUserScriptInjectionTimeAtDocumentStart Inject the script after the document element has been created, but before any other content has been loaded. @constant WKUserScriptInjectionTimeAtDocumentEnd Inject the script after the document has finished loading, but before any subresources may have finished loading. NS_ASSUME__BEGIN typedef NS_ENUM(NSInteger, WKUserScriptInjectionTime) { WKUserScriptInjectionTimeAtDocumentStart, WKUserScriptInjectionTimeAtDocumentEnd } NS_ENUM_AVAILABLE(10_10, 8_0); */ WKUserScript *jsScript = [[WKUserScript alloc] initWithSource:js injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES]; NSString *cookie = @"TestCookieKey1=TestCookieValue1;TestCookieKey2=TestCookieValue2"; WKUserScript *cookieScript = [[WKUserScript alloc] initWithSource:cookie injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO]; WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init]; //设置加载完成后,就会被调用的javascript脚本 [configuration.userContentController addUserScript:jsScript]; [configuration.userContentController addUserScript:cookieScript]; //JavaScript只能调用向WKWebView注册过的方法 [configuration.userContentController addScriptMessageHandler:self name:SCRIPT_MESSAGE_HANDLER_NAME]; //To initialize an instance with the default configuration. The initializer copies the specified configuration, so mutating the configuration after invoking the initializer has no effect on the web view. //意思是configuration仅能在webview初始化的时候设置 self.webView = [[WKWebView alloc] initWithFrame:CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height-100) configuration:configuration]; [self.webView setNavigationDelegate:self]; [self.webView setUIDelegate:self]; //加载网页(前面加不加<html>或<body>的标签都一样) [self.webView loadHTMLString:@"<ol><li><image src='https://timgsa.baidu.com/timg?image&quality=80&size=b10000_10000&sec=1467217122235&di=dbb5ffb49d8f588813f73e695467affe&imgtype=jpg&src=http%3A%2F%2Fwww.yooyoo360.com%2Fphoto%2F2009-1-1%2F20090112124741382.jpg' /></li><li><image src='https://timgsa.baidu.com/timg?image&quality=80&size=b10000_10000&sec=1467207071&di=288773b78ea4efc22ce9145364cfad0a&src=http://www.yooyoo360.com/photo/2009-1-1/20090112114754542.jpg' /></li><ol>" baseURL:nil]; /* //加载网页 NSString *urlStr = @"https://www.baidu.comfadfa"; NSURL *url = [NSURL URLWithString:urlStr]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; //添加Cookie,让WKWebView知道登录状态 [request addValue:cookie forHTTPHeaderField:@"Cookie"]; [self.webView loadRequest:request]; */ //添加左滑回退的功能 self.webView.allowsBackForwardNavigationGestures = true; [self.view addSubview:self.webView]; [self.button addTarget:self action:@selector(buttonDidClick) forControlEvents:UIControlEventTouchUpInside]; } #pragma mark - WKScriptMessageHandler(@protocol) /* @abstract Invoked when a script message is received from a webpage. @param userContentController The user content controller invoking the delegate method. @param message The script message received. OC中注册供JS调用的方法 [self.webView.configuration.userContentController addScriptMessageHandler:self name:<name>]; JS在调用OC中注册的方法的时候要使用下面的方式: window.webkit.messageHandlers.<name>.postMessage(<messageBody>); 注意:name(方法名)是放在中间的,messageBody只能是一个对象,如果要传多个值,需要封装成数组或是字典。 另外:xxx...xxx.postMessage(),即如果‘messageBody’不填,也会报错 */ -(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message { NSLog(@"didReceiveScriptMessage, name = %@, body = %@", message.name, message.body); } #pragma mark - WKWebView执行javascript的方法 -(void)buttonDidClick { NSLog(@"buttonDidClick"); //js显示对话框 NSString *js1 = @"var count = document.images.length; for(var i=0;i<count;i++) {var image = document.images[i]; image.style.width=320;}; window.alert('找到'+count+'张图')"; [self.webView evaluateJavaScript:js1 completionHandler:^(id _Nullable obj, NSError * _Nullable error) { NSLog(@"evaluateJavaScript, obj = %@, error = %@", obj, error); }]; //js调用oc的方法 NSString *js2 = [NSString stringWithFormat:@"var msg = {'key1':'value1','key2':'value2'};window.webkit.messageHandlers.%@.postMessage(msg);", SCRIPT_MESSAGE_HANDLER_NAME]; [self.webView evaluateJavaScript:js2 completionHandler:^(id _Nullable obj, NSError * _Nullable error) { NSLog(@"evaluateJavaScript, obj = %@, error = %@", obj, error); }]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } #pragma mark - WKNavigationDelegate 用来追踪加载过程 //Provisional - 临时的 //页面开始加载时调用 -(void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation { NSLog(@"didStartProvisionalNavigation"); } //内容开始返回时调用 -(void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation { NSLog(@"didCommitNavigation"); } //页面加载完成之后被调用 -(void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation { NSLog(@"didFinishNavigation"); } //页面加载失败之后被调用 -(void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:( NSError *)error { NSLog(@"didFailProvisionalNavigation"); } #pragma mark - WKNavigationDelegate 页面跳转 //在接受到服务器的重定向请求之后调用 -(void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation { NSLog(@"didReceiveServerRedirectForProvisionalNavigation"); } //Policy - 策略性的 //在接收到响应后,决定是否跳转 -(void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler { NSLog(@"decidePolicyForNavigationResponse, navigationResponse = %@", navigationResponse); decisionHandler(WKNavigationResponsePolicyAllow); } //在发送请求之前,决定是否跳转 -(void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { //'stringByReplacingPercentEscapesUsingEncoding:' is deprecated: first deprecated in iOS 9.0 - Use -stringByRemovingPercentEncoding instead, which always uses the recommended UTF-8 encoding. //NSString *urlStr = [navigationAction.request.URL.absoluteString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; NSString *urlStr = [navigationAction.request.URL.absoluteString stringByRemovingPercentEncoding]; NSLog(@"decidePolicyForNavigationAction, navigationAction.request.URL = %@", urlStr); /* typedef NS_ENUM(NSInteger, WKNavigationActionPolicy) { WKNavigationActionPolicyCancel, WKNavigationActionPolicyAllow, } NS_ENUM_AVAILABLE(10_10, 8_0); */ decisionHandler(WKNavigationActionPolicyAllow); } //接收到用户身份认证之后触发 -(void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(nonnull NSURLAuthenticationChallenge *)challenge completionHandler:(nonnull void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler { NSLog(@"didReceiveAuthenticationChallenge"); /* typedef NS_ENUM(NSUInteger, NSURLCredentialPersistence) { NSURLCredentialPersistenceNone, NSURLCredentialPersistenceForSession, NSURLCredentialPersistencePermanent, NSURLCredentialPersistenceSynchronizable NS_ENUM_AVAILABLE(10_8, 6_0) }; */ NSURLCredential *credential = [[NSURLCredential alloc] initWithUser:@"username" password:@"password" persistence:NSURLCredentialPersistenceForSession]; /* typedef NS_ENUM(NSInteger, NSURLSessionAuthChallengeDisposition) { NSURLSessionAuthChallengeUseCredential = 0, Use the specified credential, which may be nil NSURLSessionAuthChallengePerformDefaultHandling = 1, Default handling for the challenge - as if this delegate were not implemented; the credential parameter is ignored. NSURLSessionAuthChallengeCancelAuthenticationChallenge = 2, The entire request will be canceled; the credential parameter is ignored. NSURLSessionAuthChallengeRejectProtectionSpace = 3, This challenge is rejected and the next authentication protection space should be tried; the credential parameter is ignored. } NS_ENUM_AVAILABLE(NSURLSESSION_AVAILABLE, 7_0); */ completionHandler(NSURLSessionAuthChallengeUseCredential, credential); } #pragma mark - WKUIDelegate 新窗口 //打开一个新的窗口 -(WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(nonnull WKWebViewConfiguration *)configuration forNavigationAction:(nonnull WKNavigationAction *)navigationAction windowFeatures:(nonnull WKWindowFeatures *)windowFeatures { NSLog(@"createWebViewWithConfiguration"); CGRect rect = self.view.bounds; self.webView = [[WKWebView alloc] initWithFrame:CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height-100) configuration:configuration]; [self.view addSubview:self.webView]; return webView; } #pragma mark - WKUIDelegate 对话框 //js的对话框是不能在iOS中显示的,要想显示这些对话框就需要调用iOS中的相应方法。 //警告框 -(void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler { NSLog(@"runJavaScriptAlertPanelWithMessage"); UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"AlertTitle" message:message preferredStyle:UIAlertControllerStyleAlert]; [alertController addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){ completionHandler(); }]]; [self presentViewController:alertController animated:YES completion:nil]; } //确认框 -(void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:( WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler { NSLog(@"runJavaScriptConfirmPanelWithMessage"); UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"AlertTitle" message:message preferredStyle:UIAlertControllerStyleAlert]; [alertController addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){ completionHandler(YES); }]]; [alertController addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action){ completionHandler(NO); }]]; [self presentViewController:alertController animated:YES completion:nil]; } //输入框 -(void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:( void (^)(NSString * _Nullable))completionHandler { NSLog(@"runJavaScriptTextInputPanelWithPrompt"); completionHandler(@"Client Not handler"); } @end
相关文章推荐
- Swift 范的 CGRect、CGSize 和 CGPoint
- web中filter需要注入bean(如service,dao等bean)--- DelegatingFilterProxy
- ioS之Socket心跳包机制与实现
- iOS之实现后台socket长连接
- android 动画(3)属性动画
- android高级工程师应该会的知识
- iOS发展史(里程碑)
- Swift3.0带来的变化汇总系列三——函数和闭包写法上的微调
- 基于Android系统Api封装常用工具类
- 移动端适配问题
- android 动画(2)帧动画
- App后台学习
- 一个小白从零基础自学Android编程笔记之如何切换另一个活动(窗口)
- Android Error : No resource found that matches the given name 'Theme.AppCompat.Light'.
- APP版本兼容,伤不起!
- 安卓app——脸萌
- iOS中常用的几种设计模式
- Android数据持久化存储
- Android开发小问题记录
- android Activity 四大启动模式探究