WKWebView 使用
import "JspWebViewController.h"
import "LoginViewController.h"
import "AppDelegate.h"
import "IdleWindow.h"
import "UIDevice+TFDevice.h"
import <WebKit/WebKit.h>
@interface JspWebViewController ()<WKScriptMessageHandler,WKUIDelegate,WKNavigationDelegate> //(遵守的协议)
@property (nonatomic, strong) WKWebView *webView;
@property (strong, nonatomic) UIBarButtonItem *backItem0;
@property (strong, nonatomic) UIButton *btn;
@property(nonatomic,strong)UIAlertView *loadingAlert;
//@property (strong,nonatomic) UIAlertController *loadingAlert;
@end
@implementation JspWebViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self configWKWebView];
}
-
(void)configWKWebView{
WKUserContentController *userContentController = [[WKUserContentController alloc] init];
//获取cookie
NSArray *cookies = [NSHTTPCookieStorage sharedHTTPCookieStorage].cookies;
NSMutableDictionary *cookieDic = [NSMutableDictionary dictionary];
NSMutableString *cookieValue = [NSMutableString string];
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for(NSHTTPCookie *cookie in [cookieStorage cookies]) {
[cookieDic setObject:cookie.value forKey:cookie.name];
}
//cookie去重复,先放到字典中再去重
for(NSString *key in cookieDic.allKeys){
NSString *appendingStr = [NSString stringWithFormat:@"%@=%@",key,[cookieDic valueForKey:key]];
[cookieValue appendString:appendingStr];
}//js注入cookie,防止从请求页面返回后再次请求页面失败,ios 11以前系统
NSString *cookieSource = [[@"document.cookie = '" stringByAppendingString:cookieValue] stringByAppendingString:@"'"];
WKUserScript *cookieScript = [[WKUserScript alloc] initWithSource:cookieSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
[userContentController addUserScript:cookieScript];//测试将参数保存到缓存localStorage里,方便后台调用。
NSString *sendTocen = [NSString stringWithFormat:@"localStorage.setItem("accessToken",'%@');localStorage.setItem("testItem",'%@');",[self getUserName],[self getUserSP]];
//设置js和oc交互。可以设置多个
WKUserScript *script = [[WKUserScript alloc] initWithSource:sendTocen injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
[userContentController addScriptMessageHandler:[WeakScriptMessageDelegate alloc] name:@"iOS"];
[userContentController addUserScript:script];//WkwebView 配置协议
WKWebViewConfiguration *config = [WKWebViewConfiguration new];
config.userContentController = userContentController;config.preferences.javaScriptEnabled = YES;
config.preferences.javaScriptCanOpenWindowsAutomatically = YES;
config.suppressesIncrementalRendering = YES; // 是否支持记忆读取
[config.preferences setValue:@YES forKey:@"allowFileAccessFromFileURLs"];
if (@available(iOS 10.0, *)) {
[config setValue:@YES forKey:@"allowUniversalAccessFromFileURLs"];
}
//定义WKWebView
_webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
//设置代理
_webView.UIDelegate = self;
_webView.navigationDelegate = self;
//拼接访问地址
NSString *urlString = "自己的url";
// NSString *urlString = [baseUrl stringByAppendingString:@"JIRA/test.jsp"];
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request= [NSMutableURLRequest requestWithURL:url];
//设置请求头
[request setValue:cookieValue forHTTPHeaderField:@"Cookie"];
//设置cookie
// NSDictionary *requestHeaderFields = [NSHTTPCookie requestHeaderFieldsWithCookies:cookies];
// request.allHTTPHeaderFields = requestHeaderFields;
//设置post请求
// [request setHTTPMethod:@"POST"];
//加载后台页面
[_webView loadRequest:request];
//将导航栏设置为透明
self.navigationController.navigationBar.translucent = YES;
[self.view addSubview:_webView];
//重写返回按钮
self.navigationItem.leftBarButtonItem = self.backItem;
}
/**
*重写返回按钮,可以是页面返回上一页
*/
-(UIBarButtonItem *)backItem{
if (!self.backItem0) {
UIButton *back = [UIButton buttonWithType:UIButtonTypeSystem];
[back setImage:[UIImage imageNamed:@"backIcon"] forState:UIControlStateNormal];
// [back setTitle:@"Back" forState:UIControlStateNormal];
back.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
back.titleLabel.font = [UIFont systemFontOfSize:17];
back.frame = CGRectMake(0, 0, 44, 32);
[back addTarget:self action:@selector(back) forControlEvents:UIControlEventAllEvents];
self.backItem0 = [[UIBarButtonItem alloc] initWithCustomView:back];
}
return self.backItem0;
}
-(void)back{
[[self class] cancelPreviousPerformRequestsWithTarget:self selector:@selector(toDoSomeThing: ) object:self.btn];
[self performSelector:@selector(toDoSomeThing:) withObject:self.btn afterDelay:0.8f];
}
-(void)toDoSomeThing:(UIViewController *)vc{
if ([self.webView canGoBack]) {
AppDelegate * appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
appDelegate.allowRotation = NO;//关闭横屏仅允许竖屏
//切换到竖屏
[UIDevice switchNewOrientation:UIInterfaceOrientationPortrait];
[self.webView goBack];
}else{
AppDelegate * appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
appDelegate.allowRotation = NO;//关闭横屏仅允许竖屏
//切换到竖屏
[UIDevice switchNewOrientation:UIInterfaceOrientationPortrait];
[self.view resignFirstResponder];
//返回主菜单原生页面的时候导航栏设置为不透明
self.navigationController.navigationBar.translucent = NO;
[self.navigationController popViewControllerAnimated:YES];
}
}
//解决页面第一访问后cookie丢失问题
-
(void)webView:(WKWebView)webView decidePolicyForNavigationResponse:(WKNavigationResponse)navigationResponse decisionHandler:(void(^)(WKNavigationResponsePolicy))decisionHandler{
NSArray *cookies = [NSHTTPCookieStorage sharedHTTPCookieStorage].cookies;
if (@available(iOS 11.0, *)) {
WKHTTPCookieStore *cookieStroe = webView.configuration.websiteDataStore.httpCookieStore;
for(NSHTTPCookie *cookie in cookies) {
[cookieStroe setCookie:cookie completionHandler:nil];
}
}decisionHandler(WKNavigationResponsePolicyAllow);
}
pragma mark - WKNavigationDelegate
// 页面开始加载时调用
-
(void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{
if (self.loadingAlert==nil){
self.loadingAlert = [[UIAlertView alloc] initWithTitle:nil
message: @"正在加载数据,请稍候....."
delegate: self
cancelButtonTitle: nil
otherButtonTitles: nil];
UIActivityIndicatorView *activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
activityView.frame = CGRectMake(120.f, 48.0f, 37.0f, 37.0f);
[self.loadingAlert addSubview:activityView];
[activityView startAnimating];
[self.loadingAlert show];
}
}
// 当内容开始返回时调用
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation{
}
// 页面加载完成之后调用
-
(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
[self.loadingAlert dismissWithClickedButtonIndex:0 animated:YES];
}
//页面加载失败时调用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
{
NSLog(@"加载失败%@", error.userInfo);
}
// 接收到服务器跳转请求之后调用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation{
}
/**
*自建证书没有得到认证,访问https时需要强制信任证书,不知道我理解的有没有错
*/
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *_Nullable))completionHandler
{
// NSLog(@"=====证书pppp=======");
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
if (challenge.previousFailureCount == 0) {
NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
} else {
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
}
}
}
/**
- 将用户名和密码放到浏览器缓存里,这个是不需要的,懒得该
*/
-
(NSString *)getUserName {
return uname;
} -
(NSString *)getUserSP {
return usersp01;
}
/**
- web界面中有弹出警告框时调用
- @param webView 实现该代理的webview
- @param message 警告框中的内容
- @param completionHandler 警告框消失调用
*/
-
(void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
//将本地加载等待弹框清除
[self.loadingAlert dismissWithClickedButtonIndex:0 animated:YES];UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"" message:message?:@"" preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {if([message isEqualToString:@"用户信息过期,请重新登录!"]){ LogInViewController *loginVC = [[LogInViewController alloc] init]; AppDelegate *delegate = (AppDelegate*)[[UIApplication sharedApplication] delegate]; IdleWindow *idleWindow = (IdleWindow *)delegate.window; //这个是我写的记录手机时间超时的
// [[[NSURLCache alloc] init] removeAllCachedResponses]; //清除NSURLCache的缓存
[[NSURLCache sharedURLCache] removeAllCachedResponses];
[loginVC clearCookiesForWkWebView];
[idleWindow setRootViewController:loginVC];
}
completionHandler();
}])];
[self presentViewController:alertController animated:YES completion:nil];
}
/**
-
清除WKWebView 的cookie
*/
-(void)clearCookiesForWkWebView{if([[[UIDevice currentDevice] systemVersion] floatValue] >= 9.0 ){
NSArray *types = @[WKWebsiteDataTypeCookies,WKWebsiteDataTypeSessionStorage];
NSSet *websiteDataTypes = [NSSet setWithArray:types];
NSDate *dateformter = [NSDate dateWithTimeIntervalSince1970:0];
[[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:websiteDataTypes modifiedSince:dateformter completionHandler:^{}];
}else{
NSString *libaryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *cookieFolderPath = [libaryPath stringByAppendingString:@"/Cookies"];
NSError *errors;
[[NSFileManager defaultManager] removeItemAtPath:cookieFolderPath error:&errors];
}
}
// 确认框
//JavaScript调用confirm方法后回调的方法 confirm是js中的确定框,需要在block中把用户选择的情况传递进去
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"" message:message?:@"" preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:([UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
completionHandler(NO);
}])];
[alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler(YES);
}])];
[self presentViewController:alertController animated:YES completion:nil];
}
// 输入框
//JavaScript调用prompt方法后回调的方法 prompt是js中的输入框 需要在block中把用户输入的信息传入
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:prompt message:@"" preferredStyle:UIAlertControllerStyleAlert];
[alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.text = defaultText;
}];
[alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler(alertController.textFields[0].text?:@"");
}])];
[self presentViewController:alertController animated:YES completion:nil];
}
// 页面是弹出窗口 _blank 处理
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures {
if (!navigationAction.targetFrame.isMainFrame) {
[webView loadRequest:navigationAction.request];
}
return nil;
}
@end
@implementation WeakScriptMessageDelegate
-
(instancetype)initWithDelegate:(id<WKScriptMessageHandler>)delegate {
self = [super init];
if (self) {
_delegate = delegate;
}
return self;
} -
(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
if (self.delegate && [self.delegate respondsToSelector:@selector(userContentController:didReceiveScriptMessage:)]) {
[self.delegate userContentController:userContentController didReceiveScriptMessage:message];
}
}
@end