您的位置:首页 > 移动开发

iOS 使用WKWebView替换UIWebView(二)——代码实战(包括OC与JS互调)

2016-06-30 02:06 603 查看
1、ViewController.h

//
//  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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: