万能的wkWebview,哈哈
2019-02-26 本文已影响0人
艾希_可可
#import "KINWebBrowserViewController.h"
#import <MJRefresh/MJRefresh.h>
#import <JavaScriptCore/JavaScriptCore.h>
#import "LNBrowserPluginManager.h"
#import "NSString+LNUrl.h"
#import "AiWKProcessPool.h"
static void *KINWebBrowserContext = &KINWebBrowserContext;
@interface KINWebBrowserViewController ()
@property (nonatomic, strong) UIBarButtonItem* closeButtonItem;//关闭按钮
@property (nonatomic, strong) NSTimer *fakeProgressTimer;
@property (nonatomic, strong) NSURL *URLToLaunchWithPermission;
@property (nonatomic, strong) UIAlertController *externalAppPermissionAlertView;
// js和native交互的管理器
@property (nonatomic, strong) LNBrowserPluginManager *pluginManager;
@end
@implementation KINWebBrowserViewController
#pragma mark - Static Initializers
+ (KINWebBrowserViewController *)webBrowser {
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
KINWebBrowserViewController *webBrowserViewController = [[self alloc] initWithConfiguration:configuration];
return webBrowserViewController;
}
#pragma mark - Initializers初始化生命周期
- (id)init {
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
return [self initWithConfiguration:configuration];
}
- (id)initWithConfiguration:(WKWebViewConfiguration *)configuration {
self = [super init];
if(self) {
MJRefreshNormalHeader *header = [MJRefreshNormalHeader headerWithRefreshingTarget:self.wkWebView refreshingAction:@selector(reload)];
header.lastUpdatedTimeLabel.hidden = YES;
self.showsURLInNavigationBar = NO;
self.showsPageTitleInNavigationBar = YES;
[self.view addSubview:self.wkWebView];
[self updateWebViewCookie];
}
return self;
}
#pragma mark - 导航设置---------生命周期
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self updateNavigationBarState];
if ([self.wkWebView.URL.absoluteString containsString:@"progresslist"] && [self.wkWebView.title isEqualToString:@"申请额度"]) {
[self refreshWKwebView];
}
if ([self.wkWebView.title isEqualToString:@"集市"]) {
[self.navigationController setNavigationBarHidden:YES animated:false];
[self.view addSubview:self.progressBar];
self.progressBar.frame = CGRectMake(0, kStatusBarHeight, __kScreenWidth, 2);
[self.wkWebView setFrame:CGRectMake(0, kStatusBarHeight, __kScreenWidth, __kScreenHeight-kTabBarHeight-kStatusBarHeight)];//-88
}else{
[self.navigationController setNavigationBarHidden:NO animated:false];
[self.navigationController.navigationBar addSubview:self.progressBar];
self.progressBar.frame = CGRectMake(0, 0, __kScreenWidth, 2);
if ([self.wkWebView.title isEqualToString:@"基本信息"] || [self.wkWebView.title isEqualToString:@"银行卡绑定"] || [self.wkWebView.title isEqualToString:@"贷款相关协议"]) {
[self.wkWebView setFrame:CGRectMake(0, 0, __kScreenWidth, __kScreenHeight-kTopHeight)];
}else{
[self.wkWebView setFrame:CGRectMake(0, 0, __kScreenWidth, __kScreenHeight-kTabBarHeight-kTopHeight)];
}
}
}
-(void)viewDidAppear:(BOOL)animated{
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self.progressBar removeFromSuperview];
}
-(void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
// [self deleteWebCache];
// [self cleanCacheAndCookie];
}
- (void)viewDidLoad {
[super viewDidLoad];
// 初始化交互管理器
_pluginManager = [[LNBrowserPluginManager alloc] initWithBrowser:self];
[_pluginManager addDefaultPlugins];
//更新webView的cookie
[self updateWebViewCookie];
self.progressBar = [[UNProgressBar alloc] init];
[self.progressBar setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin];
// [self addSpaceButton];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshWKwebView) name:@"refreshWKwebView" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(backMorenHomeResultPage) name:@"backMorenHomeResultPage" object:nil];
}
//回到首页页面
-(void)backMorenHomeResultPage{
[self.wkWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@sudaihomepage",kDomainLSDKUrl]]]];
}
-(void)refreshWKwebView{
YEAFNAppLog(@"刷新的时候链接%@",self.webURLString);
[self.wkWebView reload];
}
-(WKWebView *)wkWebView{
if (!_wkWebView){
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
WKUserContentController *userContentController = [[WKUserContentController alloc] init];
// 注入获取app版本号的js代码
WKUserScript *script = [[WKUserScript alloc] initWithSource:[self getVersionInjectionCode] injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
[userContentController addUserScript:script];
// 执行js,初始化时添加cookies
WKUserScript * cookieScript = [[WKUserScript alloc] initWithSource:[self cookieString] injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
//添加Cookie
[userContentController addUserScript:cookieScript];
//页面加载完成立刻回调,获取页面上的所有Cookie
WKUserScript *cookieScript2 = [[WKUserScript alloc] initWithSource:@" window.webkit.messageHandlers.currentCookies.postMessage(document.cookie);" injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:NO];
[userContentController addUserScript:cookieScript2];
configuration.userContentController = userContentController;
configuration.processPool = [AiWKProcessPool singleWkProcessPool];
WKPreferences *preferences = [[WKPreferences alloc]init];
preferences.javaScriptCanOpenWindowsAutomatically = YES;
configuration.preferences = preferences;
_wkWebView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration];
// self.webView.allowsBackForwardNavigationGestures = YES; //允许右滑返回上个链接,左滑前进
_wkWebView.allowsLinkPreview = YES; //允许链接3D Touch
[_wkWebView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
[_wkWebView setNavigationDelegate:self];
[_wkWebView setUIDelegate:self];
[_wkWebView setMultipleTouchEnabled:YES];
[_wkWebView setAutoresizesSubviews:YES];
[_wkWebView.scrollView setAlwaysBounceVertical:YES];
_wkWebView.scrollView.delegate = self;
// _wkWebView.scrollView.contentInset = UIEdgeInsetsMake(-200, 0, 0, 0);
_wkWebView.backgroundColor = [UIColor clearColor];
[_wkWebView addObserver:self forKeyPath:NSStringFromSelector(@selector(estimatedProgress)) options:0 context:KINWebBrowserContext];
}
return _wkWebView;
}
#pragma mark - scrollView代理
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
scrollView.decelerationRate = UIScrollViewDecelerationRateNormal;
}
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
[self.wkWebView setNeedsLayout];
}
-(void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context{
YEAFNAppLog(@"什么东东observer==%@,keyPath====%@,context=====%@",observer,keyPath,context);
}
#pragma mark - 导航设置
- (void)addleftBackItem{
if (self.navigationController) {
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
self.navigationItem.leftBarButtonItems = nil;
if ([self.navigationController.viewControllers indexOfObject:self] > 0) {
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]initWithImage:[UIImage imageNamed:kNavBtn_left_custom] style:UIBarButtonItemStylePlain target:self action:@selector(goBackLastPage:)];
}
}
}
- (void)checkWebViewCanGoBack{
if ([self.wkWebView canGoBack]) {
[self addSpaceButton];
}
}
#pragma mark - NavigationItem
- (void)goBackLastPage:(UIButton *)sender {
if ([self.wkWebView canGoBack]) {//判断是否可以返回,如果可以返回添加X按钮
[self.wkWebView goBack];
// if (LSTabBarViewController.instance.selectedIndex == 0 || LSTabBarViewController.instance.selectedIndex == 1) {
if ([self.wkWebView.URL.absoluteString containsString:@"hardwaremall"] || [self.wkWebView.URL.absoluteString containsString:@"integration"]) {
[self.wkWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@",self.wkWebView.URL.absoluteString]]]];
}
[self addSpaceButton];
}
// if ([self gotoBack]) {
// [self closeItemClicked];
// }else{
//
// }
}
- (BOOL)gotoBack{
if ([self.wkWebView canGoBack]) {//判断是否可以返回,如果可以返回添加X按钮
[self.wkWebView goBack];
[self addSpaceButton];
return NO;
}
return YES;
}
- (void)addSpaceButton{
if ([self.wkWebView.title isEqualToString:@"商城"] || [self.wkWebView.title isEqualToString:@"我的"] || [self.wkWebView.title isEqualToString:@"活动"] || [self.wkWebView.title isEqualToString:@"积分"] || [self.wkWebView.title isEqualToString:@"集市"] || [self.wkWebView.title isEqualToString:@"首页"] || [self.wkWebView.title isEqualToString:@"信用"] || [self.wkWebView.title isEqualToString:@"达客良品"] || ([self.wkWebView.URL.absoluteString containsString:@"hardwaremall"] && [self.wkWebView.title isEqualToString:@"达客良品"]) || ([self.wkWebView.URL.absoluteString containsString:@"integration"] && [self.wkWebView.title isEqualToString:@"信用"]) || ([self.wkWebView.URL.absoluteString containsString:@"homePage"] && [self.wkWebView.title isEqualToString:@"积分"]) || ([self.wkWebView.URL.absoluteString containsString:@"minePage"] && [self.wkWebView.title isEqualToString:@"我的"]) || [self.wkWebView.title isEqualToString:@"达客速贷-还款"] || [self.webURLString containsString:@"hardwaremall"] || [self.webURLString containsString:@"integration"] || [self.webURLString containsString:@"minePage"] || [self.webURLString containsString:@"homePage"]){// || [self.wkWebView.URL.absoluteString containsString:@"hardwaremall"]
self.navigationItem.leftBarButtonItem = nil;
self.navigationItem.leftBarButtonItems = @[];
}else{
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]initWithImage:[UIImage imageNamed:kNavBtn_left_custom] style:UIBarButtonItemStylePlain target:self action:@selector(goBackLastPage:)];
}
}
-(UIBarButtonItem*)closeButtonItem{
if (!_closeButtonItem) {
_closeButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"nav_icon_close"] style:UIBarButtonItemStylePlain target:self action:@selector(closeItemClicked)];
}
return _closeButtonItem;
}
-(void)closeItemClicked{
if (_isgoRoot) {
[self.navigationController popToRootViewControllerAnimated:true];
}else{
[self.navigationController popViewControllerAnimated:YES];
}
}
#pragma mark - NavigationBar State
- (void)updateNavigationBarState {
if(self.wkWebView.loading) {
if(self.showsURLInNavigationBar) {
NSString *URLString;
if(self.wkWebView) {
URLString = [self.wkWebView.URL absoluteString];
}
URLString = [URLString stringByReplacingOccurrencesOfString:@"http://" withString:@""];
URLString = [URLString stringByReplacingOccurrencesOfString:@"https://" withString:@""];
URLString = [URLString substringToIndex:[URLString length]-1];
if (self.navigationItem.title == nil) {
self.navigationItem.title = URLString;
}
}
} else {
if(self.showsPageTitleInNavigationBar) {
if(self.wkWebView) {
self.navigationItem.title = self.wkWebView.title;
}
}
}
if (self.isHomeView && [self gotoBack]) {
if (self.delegate && [self.delegate respondsToSelector:@selector(showLeftBackItem)]) {
[self.delegate showLeftBackItem];
}
}
self.tintColor = self.tintColor;
self.barTintColor = self.barTintColor;
}
#pragma mark - Public 加载方式
- (void)loadRequest:(NSURLRequest *)request {
if(self.wkWebView) {
[self.wkWebView loadRequest:request];
}
}
- (void)loadUrl:(NSString *)url
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
//给发出的request也添加上cookies
[self.wkWebView loadRequest:[self fixRequest:request]];
}
- (void)loadURLString:(NSString *)URLString {
YEAFNAppLog(@"*******************加载的链接%@",URLString);
self.webURLString = URLString;
NSURL *URL = [NSURL URLWithString:URLString];
NSString *urlString = URL.absoluteString;
//给发出的request也添加上cookies
// NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlString]];
// [self.wkWebView loadRequest:[self fixRequest:request]];
[self.wkWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlString]]];
}
- (void)loadHTMLString:(NSString *)HTMLString {
if(self.wkWebView) {
[self.wkWebView loadHTMLString:HTMLString baseURL:nil];
}
}
#pragma mark----***一、WKWebView加载时序:
#pragma mark - WKNavigationDelegate********************
//1、开始请求,是否允许跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
YEAFNAppLog(@"1");
YEAFNAppLog(@"开始请求,判断链接是否允许跳转------%@----%@",webView.title,self.wkWebView.URL.absoluteString);
[self updateWebViewCookie];
[self addSpaceButton];
if(webView == self.wkWebView) {
self.navigationItem.title = self.wkWebView.title;
//判断导航
if ([self.wkWebView.title isEqualToString:@"集市"]) {
[self.navigationController setNavigationBarHidden:YES animated:false];
[self.wkWebView setFrame:CGRectMake(0, kStatusBarHeight, __kScreenWidth, __kScreenHeight-kTabBarHeight-kStatusBarHeight)];//-88
}else{
[self.navigationController setNavigationBarHidden:NO animated:false];
if ([self.wkWebView.title isEqualToString:@"基本信息"] || [self.wkWebView.title isEqualToString:@"银行卡绑定"] || [self.wkWebView.title isEqualToString:@"贷款相关协议"]) {
[self.wkWebView setFrame:CGRectMake(0, 0, __kScreenWidth, __kScreenHeight-kTopHeight)];
}else{
[self.wkWebView setFrame:CGRectMake(0, 0, __kScreenWidth, __kScreenHeight-kTabBarHeight-kTopHeight)];
}
}
// NSURL *URL = navigationAction.request.URL;
// if(![self externalAppRequiredToOpenURL:URL]) {
// if(!navigationAction.targetFrame) {
// decisionHandler(WKNavigationActionPolicyCancel);
// return;
// }
// }else if([[UIApplication sharedApplication] canOpenURL:URL]) {
//// [self launchExternalAppWithURL:URL];
// decisionHandler(WKNavigationActionPolicyCancel);
// return;
// }
}
//解决Cookie丢失问题
// NSURLRequest *originalRequest = navigationAction.request;
// [self fixRequest:originalRequest];
NSString *url = navigationAction.request.URL.absoluteString;
if ([url hasPrefix:@"alipays://"] || [url hasPrefix:@"alipay://"]) {
[[UIApplication sharedApplication]openURL:navigationAction.request.URL];
// decisionHandler(WKNavigationActionPolicyAllow);
// return;
}
if ([url containsString:@"itunes.apple.com"]) {
[[UIApplication sharedApplication]openURL:navigationAction.request.URL];
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
UIApplication *app = [UIApplication sharedApplication];
if ([url containsString:@"itms-services://"]) {
[app openURL:[NSURL URLWithString:url] options:@{} completionHandler:^(BOOL success) {
YEAFNAppLog(@"打开链接");
}];
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
NSURL *URL = navigationAction.request.URL;
NSString *scheme = [URL scheme];
if ([scheme isEqualToString:@"tel"]) {
NSString *resourceSpecifier = [URL resourceSpecifier];
NSString *callPhone = [NSString stringWithFormat:@"telprompt://%@", resourceSpecifier];
/// 防止iOS 10及其之后,拨打电话系统弹出框延迟出现
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:callPhone]];
});
}
//允许跳转
decisionHandler(WKNavigationActionPolicyAllow);//是否继续打开allow是,cancel否
return;
}
//2、开始加载时调用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
[self addSpaceButton];
YEAFNAppLog(@"2开始加载时调用");
if(webView == self.wkWebView) {
//展期 点击确定按钮返回
if ([[[webView URL] scheme] isEqualToString:@"pcrequest"]) {
[self.navigationController popViewControllerAnimated:YES];
return ;
}
if ([[[webView URL]scheme] isEqualToString:@"goShareView"]) {
NSString * sharInfo;
if (self.delegate && [self.delegate respondsToSelector:@selector(webBrowserClickShowShareView:)]) {
[self.delegate webBrowserClickShowShareView:sharInfo];
}
[self.navigationController popViewControllerAnimated:NO];
return ;
}
[self updateNavigationBarState];
self.progressBar.isLoading = YES;
[self.progressBar progressUpdate:.05];
if([self.delegate respondsToSelector:@selector(webBrowser:didStartLoadingURL:)]) {
[self.delegate webBrowser:self didStartLoadingURL:self.wkWebView.URL];
}
if ([self.wkWebView.title isEqualToString:@"集市"] || ([self.webURLString containsString:@"homePage"] && [self.wkWebView.title isEqualToString:@"集市"])) {
[self.navigationController setNavigationBarHidden:YES animated:false];
[self.view addSubview:self.progressBar];
self.progressBar.frame = CGRectMake(0, kStatusBarHeight, __kScreenWidth, 2);
[self.wkWebView setFrame:CGRectMake(0, kStatusBarHeight, __kScreenWidth, __kScreenHeight-kTabBarHeight-kStatusBarHeight)];//-88
}else{
[self.navigationController setNavigationBarHidden:NO animated:false];
[self.navigationController.navigationBar addSubview:self.progressBar];
self.progressBar.frame = CGRectMake(0, 0, __kScreenWidth, 2);
if ([self.wkWebView.title isEqualToString:@"基本信息"] || [self.wkWebView.title isEqualToString:@"银行卡绑定"] || [self.wkWebView.title isEqualToString:@"贷款相关协议"]) {
[self.wkWebView setFrame:CGRectMake(0, 0, __kScreenWidth, __kScreenHeight-kTopHeight)];
}else{
[self.wkWebView setFrame:CGRectMake(0, 0, __kScreenWidth, __kScreenHeight-kTabBarHeight-kTopHeight)];
}
}
}
}
//3、NSLog(@"收到返回内容之后,是否允许加载,允许加载");
//在WkWebView接收到Response后,将Response带的Cookies取出,然后直接放入[NSHTTPCookieStorage sharedHTTPCookieStorage] 容器中,实现cookie共享
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
YEAFNAppLog(@"3、收到返回内容之后%@------链接%@----%@",self.wkWebView.title,navigationResponse.response.URL.absoluteString,self.wkWebView.URL.absoluteString);
//此处用作去掉首页第一次加载显示箭头,在addspace里面判断self.webURLString
self.webURLString = self.wkWebView.URL.absoluteString;
[self addSpaceButton];
//判断返回
if ([self.wkWebView.title isEqualToString:@"集市"] && ![self.webURLString containsString:@"homePage"]) {
LSTabBarViewController.instance.selectedIndex = 2;
// [self sendRiskDataInfo];
}else if ([self.wkWebView.title isEqualToString:@"达客良品"] && [self.wkWebView.URL.absoluteString containsString:@"platformmall"]){
LSTabBarViewController.instance.selectedIndex = 0;
decisionHandler(WKNavigationResponsePolicyCancel);//是否继续加载
return;
}else{
}
NSHTTPURLResponse *response = (NSHTTPURLResponse *)navigationResponse.response;
NSArray *cookies =[NSHTTPCookie cookiesWithResponseHeaderFields:[response allHeaderFields] forURL:response.URL];
for (NSHTTPCookie *cookie in cookies) {
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
}
decisionHandler(WKNavigationResponsePolicyAllow);//是否继续加载
}
#pragma mark-----------------***二、显示开始加载html CSS js 和图片资源等(JS引擎单线程顺序执行)---------------
#pragma mark - UIWebViewDelegate------------------------------------
// 4、当main frame的导航开始请求时,内容开始返回时会调用此方法。当内容开始到达主帧时被调用(即将完成)
- (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation{
YEAFNAppLog(@"4");
YEAFNAppLog(@"当main frame的导航开始请求时,会调用此方法");
}
//5、结束加载内容,页面加载完成之后调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
YEAFNAppLog(@"5");
//取出cookie
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
//js函数
NSString *JSFuncString =
@"function setCookie(name,value,expires)\
{\
var oDate=new Date();\
oDate.setDate(oDate.getDate()+expires);\
document.cookie=name+'='+value+';expires='+oDate+';path=/'\
}\
function getCookie(name)\
{\
var arr = document.cookie.match(new RegExp('(^| )'+name+'=({FNXX==XXFN}*)(;|$)'));\
if(arr != null) return unescape(arr[2]); return null;\
}\
function delCookie(name)\
{\
var exp = new Date();\
exp.setTime(exp.getTime() - 1);\
var cval=getCookie(name);\
if(cval!=null) document.cookie= name + '='+cval+';expires='+exp.toGMTString();\
}";
//拼凑js字符串
NSMutableString *JSCookieString = JSFuncString.mutableCopy;
for (NSHTTPCookie *cookie in cookieStorage.cookies) {
NSString *excuteJSString = [NSString stringWithFormat:@"setCookie('%@', '%@', 1);", cookie.name, cookie.value];
[JSCookieString appendString:excuteJSString];
}
//执行js
[webView evaluateJavaScript:JSCookieString completionHandler:^(id obj, NSError * _Nullable error) {
YEAFNAppLog(@"执行js函数%@",error);
}];
[webView evaluateJavaScript:@"getUser()" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
YEAFNAppLog(@"getUser() 交互函数结果%@----%@",result, error);
}];
[self checkWebViewCanGoBack];
[self updateNavigationBarState];
self.progressBar.isLoading = NO;
if([self.delegate respondsToSelector:@selector(webBrowser:didFinishLoadingURL:)]) {
[self.delegate webBrowser:self didFinishLoadingURL:self.wkWebView.URL];
}
}
//当跳转失败时调用
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation
withError:(NSError *)error {
YEAFNAppLog(@"当跳转失败时调用didFailNavigation:%@", error);
if(webView == self.wkWebView) {
[self updateNavigationBarState];
self.progressBar.isLoading = NO;
[self.progressBar updateProgress:0.0];
if([self.delegate respondsToSelector:@selector(webBrowser:didFailToLoadURL:error:)]) {
[self.delegate webBrowser:self didFailToLoadURL:self.wkWebView.URL error:error];
}
// if (!self.reloadView) {
// self.reloadView = [[UIView alloc] initWithFrame:CGRectMake(0, kTopHeight, __kScreenWidth, __kScreenHeight-kTopHeight)];
//
// UIImageView *imgView = [MyUtil createImageViewFrame:CGRectMake(0, 0, __kScreenWidth, __kScreenHeight-kTopHeight) imageName:@"no-wl"];
// imgView.contentMode = UIViewContentModeCenter;
// [self.reloadView addSubview:imgView];
// }
// [self.view addSubview:self.reloadView];
//
// UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(reloadTap:)];
// [self.view addGestureRecognizer:tap];
}
if ([error code] == NSURLErrorCancelled) {
return ; //忽略这个错误。
}
}
// 加载webview内容数据失败时调用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation
withError:(NSError *)error {
YEAFNAppLog(@"加载webview内容数据失败时调用--------%@",error);
if(webView == self.wkWebView) {
[self updateNavigationBarState];
self.progressBar.isLoading = NO;
[self.progressBar updateProgress:0.0];
if([self.delegate respondsToSelector:@selector(webBrowser:didFailToLoadURL:error:)]) {
[self.delegate webBrowser:self didFailToLoadURL:self.wkWebView.URL error:error];
}
}
if ([error code] == NSURLErrorCancelled) {
return ; //忽略这个错误。
}
}
#pragma mark -证书验证
//iOS8系统下,自建证书的HTTPS链接,不调用此代理方法
//在WKWebView中,WKNavigationDelegate中提供了一个权限认证的代理方法,这是权限认证更为便捷访问HTTPS网页 当webView需要响应身份验证时调用(如需验证服务器证书)
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler
{
YEAFNAppLog(@"didReceive证书验证");
completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
// if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
// if ([challenge previousFailureCount] == 0) {// 如果没有错误的情况下 创建一个凭证,并使用证书
// NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
// completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
// } else {// 验证失败,取消本次验证
// completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
// }
// } else {
// completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
// }
}
// 当因为某些问题,导致webView进程终止时触发,比如白屏
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView {
YEAFNAppLog(@"webView进程终止时触发");
[webView reload]; //刷新就好了
}
#pragma mark - WKUIDelegate 创建一个新的WebView
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures{
YEAFNAppLog(@"创建一个新的WebView");
// [self.wkWebView loadRequest:[self fixRequest:navigationAction.request]];
if (!navigationAction.targetFrame.isMainFrame) {
[webView loadRequest:navigationAction.request];
}
return nil;
}
//JavaScript调用Obj-C,则是通过web view的代理方法,来接收JavaScript的网络请求从而实现调用
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSLog(@"ua=======%@",[request valueForHTTPHeaderField:@"userAgent" ]);
//判断是否是单击
if (navigationType == UIWebViewNavigationTypeLinkClicked) {
NSURL *url = [request URL];
[[UIApplication sharedApplication]openURL:url];
return NO;
}
return YES;
}
//js -> oc oc接收h5传来的值
#pragma mark - WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController
didReceiveScriptMessage:(WKScriptMessage *)message {
YEAFNAppLog(@" 从web界面中接收到一个脚本时调用");
//处理这个事件
if ([message.name isEqualToString:@"share"]) {
id body = message.body;
YEAFNAppLog(@"share分享的内容为:%@", body);
}
}
// 当main frame接收到服务重定向时,就是跳转到其他的服务器,会回调此方法
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation{
YEAFNAppLog(@"当main frame接收到服务重定向时,就是跳转到其他的服务器,会回调此方法");
}
#pragma mark - Estimated Progress KVO (WKWebView)监听事件
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
// YEAFNAppLog(@"监听事件 %@",keyPath);
if ([keyPath isEqualToString:NSStringFromSelector(@selector(estimatedProgress))] && object == self.wkWebView) {
// double estimatedProgress = 1.0;
double estimatedProgress = [change[@"new"] doubleValue];
[self.progressBar progressUpdate:estimatedProgress];
}else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
#pragma mark - wkwebView添加的自定义函数
- (void)reloadTap:(UITapGestureRecognizer *)sender {
YEAFNAppLog(@"重新加载");
[self.view removeGestureRecognizer:sender];
if (self.reloadView) {
[self.reloadView removeFromSuperview];
}
// if (self.webURLString.length>0) {
// NSURL *URL = [NSURL URLWithString:self.webURLString];
// NSURLRequest *request = [NSURLRequest requestWithURL:URL];
// [self.wkWebView loadRequest:request];
// }
}
- (UIView *)reloadView {
return objc_getAssociatedObject(self, _cmd);
}
- (void)setReloadView:(UIView *)reloadView {
objc_setAssociatedObject(self, @selector(reloadView), reloadView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
// 注入获取app版本号的js代码
- (NSString *)getVersionInjectionCode {
NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"] ?:@"";
NSString *injectionCode = [NSString stringWithFormat:@"function getVersion() { return '%@'; }",version];
return injectionCode;
}
- (NSURLRequest *)fixRequest:(NSURLRequest *)request
{
NSMutableURLRequest *fixedRequest;
if ([request isKindOfClass:[NSMutableURLRequest class]]) {
fixedRequest = (NSMutableURLRequest *)request;
} else {
fixedRequest = request.mutableCopy;
}
//防止Cookie丢失
NSDictionary *dict = [NSHTTPCookie requestHeaderFieldsWithCookies:[NSHTTPCookieStorage sharedHTTPCookieStorage].cookies];
if (dict.count) {
NSMutableDictionary *mDict = request.allHTTPHeaderFields.mutableCopy;
[mDict setValuesForKeysWithDictionary:dict];
fixedRequest.allHTTPHeaderFields = mDict;
}
return fixedRequest;
}
#pragma mark - Fake Progress Bar Control (UIWebView)
- (void)fakeProgressBarStopLoading {
if(self.fakeProgressTimer) {
[self.fakeProgressTimer invalidate];
}
if(self.progressView) {
[self.progressView setProgress:1.0f animated:YES];
[UIView animateWithDuration:0.3f delay:0.3f options:UIViewAnimationOptionCurveEaseOut animations:^{
[self.progressView setAlpha:0.0f];
} completion:^(BOOL finished) {
[self.progressView setProgress:0.0f animated:NO];
}];
}
}
-(UIAlertController *)externalAppPermissionAlertView{
if (!_externalAppPermissionAlertView) {
_externalAppPermissionAlertView = [UIAlertController alertControllerWithTitle:@"Leave this app?" message:@"This web page is trying to open an outside app. Are you sure you want to open it?" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
[_externalAppPermissionAlertView addAction:cancelAction];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
YEAFNAppLog(@"确定");
[[UIApplication sharedApplication] openURL:self.URLToLaunchWithPermission];
self.URLToLaunchWithPermission = nil;
}];
[_externalAppPermissionAlertView addAction:okAction];
}
return _externalAppPermissionAlertView;
}
#pragma mark - External App Support
- (BOOL)externalAppRequiredToOpenURL:(NSURL *)URL {
NSSet *validSchemes = [NSSet setWithArray:@[@"http", @"https"]];
return ![validSchemes containsObject:URL.scheme];
}
- (void)launchExternalAppWithURL:(NSURL *)URL {
self.URLToLaunchWithPermission = URL;
if (!self.externalAppPermissionAlertView) {
[self.externalAppPermissionAlertView presentViewController:self animated:YES completion:^{
}];
}
}
/*!
* 更新webView的cookie
*/
- (void)updateWebViewCookie
{
WKUserScript * cookieScript = [[WKUserScript alloc] initWithSource:[self cookieString] injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
//添加Cookie
[self.wkWebView.configuration.userContentController addUserScript:cookieScript];
}
- (NSString *)cookieString
{
NSMutableString *script = [NSMutableString string];
for (NSHTTPCookie *cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]) {
// Skip cookies that will break our script
if ([cookie.value rangeOfString:@"'"].location != NSNotFound) {
continue;
}
// Create a line that appends this cookie to the web view's document's cookies
[script appendFormat:@"document.cookie='%@'; \n", cookie.da_javascriptString];
}
return script;
}
#pragma mark -处理js里的alert
/**
* 处理js里的alert
*
*/
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"" message:message preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler();
}]];
[self presentViewController:alert animated:YES completion:nil];
}
/**
* 处理js里的confirm
*/
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:message preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler(NO);
}]];
[alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler(YES);
}]];
[self presentViewController:alert animated:YES completion:nil];
}
#pragma mark - Dismiss
- (void)dismissAnimated:(BOOL)animated {
if([self.delegate respondsToSelector:@selector(webBrowserViewControllerWillDismiss:)]) {
[self.delegate webBrowserViewControllerWillDismiss:self];
}
[self.navigationController dismissViewControllerAnimated:animated completion:nil];
}
#pragma mark - Interface Orientation
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAllButUpsideDown;
}
- (BOOL)shouldAutorotate {
return YES;
}
#pragma mark - Dealloc
- (void)dealloc {
[self.wkWebView setNavigationDelegate:nil];
[self.wkWebView setUIDelegate:nil];
if ([self isViewLoaded]) {
[self.wkWebView removeObserver:self forKeyPath:NSStringFromSelector(@selector(estimatedProgress))];
}
[self.wkWebView stopLoading];
// [self deleteWebCache];
// [self cleanCacheAndCookie];
}
#pragma mark -删除缓存
- (void)deleteWebCache {
if ([[UIDevice currentDevice].systemVersion floatValue] >= 9.0) {
// NSSet *websiteDataTypes
// = [NSSet setWithArray:@[
// WKWebsiteDataTypeDiskCache,
// WKWebsiteDataTypeMemoryCache,
// WKWebsiteDataTypeCookies,
// ]];
NSSet *websiteDataTypes = [WKWebsiteDataStore allWebsiteDataTypes];
NSDate *dateFrom = [NSDate dateWithTimeIntervalSince1970:0];
//// Execute
[[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:websiteDataTypes modifiedSince:dateFrom completionHandler:^{
// Done
YEAFNAppLog(@"清除所有缓存");
}];
} else {
NSString *libraryDir = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES)[0];
NSString *bundleId = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleIdentifier"];
NSString *webkitFolderInLib = [NSString stringWithFormat:@"%@/WebKit",libraryDir];
NSString *webKitFolderInCaches = [NSString stringWithFormat:@"%@/Caches/%@/WebKit",libraryDir,bundleId];
NSError *error;
/* iOS8.0 WebView Cache的存放路径 */
[[NSFileManager defaultManager] removeItemAtPath:webKitFolderInCaches error:&error];
[[NSFileManager defaultManager] removeItemAtPath:webkitFolderInLib error:nil];
}
}
- (void)cleanCacheAndCookie
{
//清除cookies
NSHTTPCookie *cookie;
NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (cookie in [storage cookies])
{
[storage deleteCookie:cookie];
}
[[NSURLCache sharedURLCache] removeAllCachedResponses];
NSURLCache * cache = [NSURLCache sharedURLCache];
[cache removeAllCachedResponses];
[cache setDiskCapacity:0];
[cache setMemoryCapacity:0];
WKWebsiteDataStore *dateStore = [WKWebsiteDataStore defaultDataStore];
[dateStore fetchDataRecordsOfTypes:[WKWebsiteDataStore allWebsiteDataTypes]
completionHandler:^(NSArray<WKWebsiteDataRecord *> * __nonnull records)
{
for (WKWebsiteDataRecord *record in records)
{
[[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:record.dataTypes
forDataRecords:@[record]
completionHandler:^
{
// NSLog(@"清除Cookies for %@ deleted successfully",record.displayName);
}];
}
}];
}
#pragma mark - 分享
- (void)showShareItem {
if (self.navigationController) {
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
self.navigationItem.rightBarButtonItem = nil;
if ([self.navigationController.viewControllers indexOfObject:self] > 0) {
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:@"分享" style:UIBarButtonItemStylePlain target:self action:@selector(showShareView)];
}
}
}
- (void) showShareView{
}
//当网页中需要调用客户端中的方法时,可以通过下面的方式进行调用
//window.webkit.messageHandlers.test1.postMessage({msg: "test1"});
//window.webkit.messageHandlers.对象名.postMessage(传递参数);
//对象名:就是我们在初始化WKWebView时,通过addScriptMessageHandler注入的js对象名称;
//传递参数:建议用json进行参数的传递,两边约定好的规范,可以提高开发的效率
@end
@implementation UINavigationController(KINWebBrowser)
- (KINWebBrowserViewController *)rootWebBrowser {
UIViewController *rootViewController = [self.viewControllers objectAtIndex:0];
return (KINWebBrowserViewController *)rootViewController;
}
@end