WKWebView 小记

WKWebView 不支持点击处理电话,邮件等格式化的URL,暂时记录下简单的webView处理

URL 特殊字符编码:
iOS9.0 之前:
NSString *encodedString = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,(CFStringRef)urlStr,(CFStringRef)@"!$&'()*+,-./:;=?@_~%#[]",NULL,kCFStringEncodingUTF8));
iOS9.0 之后:
NSString *encodedUrl = [url stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]
webView加载本地Html
guard let file = Bundle.main.path(forResource: "index", ofType: "html", inDirectory: "Html") else {
    return
}
let fileURL = URL(fileURLWithPath: file)
webView.loadFileURL(fileURL, allowingReadAccessTo: fileURL)
//html附带文件的情况下设置allowingReadAccessTo为文件夹路径
webView.loadFileURL(fileURL, allowingReadAccessTo: fileURL.deletingLastPathComponent())
webView初始化 Session同步
//初始化时注入sessionID  暂时用着没问题
NSString *cookieStr = [NSString stringWithFormat:@"document.cookie='%@=%@;path=/';",ShareManager.urlCookie.name,ShareManager.urlCookie.value];
WKUserScript *wkScript = [[WKUserScript alloc] initWithSource:cookieStr injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
WKUserContentController *contentC = [[WKUserContentController alloc] init];
[contentC addUserScript:wkScript];
WKWebViewConfiguration *wkConfig = [[WKWebViewConfiguration alloc] init];
wkConfig.userContentController = contentC; 
webView = [[WKWebView alloc]initWithFrame:self.view.frame configuration:wkConfig];

//URL监听 记着释放
[self.wkWebView addObserver:self forKeyPath:@"URL" options:NSKeyValueObservingOptionNew context:nil];
webView contentInsets
if #available(iOS 11.0, *) {
    webView.scrollView.contentInsetAdjustmentBehavior = .never
} else {
    automaticallyAdjustsScrollViewInsets = false
}
webView frame不正确的时候写了下面方法
- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
        
    if (@available(iOS 11.0, *)) {
        CGRect safeFrame = self.view.safeAreaLayoutGuide.layoutFrame;
        [self.wkWebView setFrame:CGRectMake(0, self.backOriginView.frame.origin.y, self.view.frame.size.width, safeFrame.size.height)];
    }
    else
    {
        float height = [[UIApplication sharedApplication] statusBarFrame].size.height;
        if (!self.navigationController.navigationBarHidden) {
            height = 0;
        }
        [self.wkWebView setFrame:CGRectMake(0, height, ScreenWidth, self.view.frame.size.height - height)];
    }
    
}
webBridge 注入JS交互
第三方 `WebViewJavascriptBridge`类
registerHandler
callHandler
//JS方法退出Web类需要手动移除,否则类不释放
[self.bridge removeHandler:js];

自定义js注入
function fun(){
 window.webkit.messageHandlers.<#自定义name#>.postMessage('<#自定义msg#>');
 }
 (function(){
 //获取h5元素,getElementById/getElementsByClassName 都可
 var e = document.getElementById('');
 //添加事件
 e.addEventListener('click',fun,false);
 }());"
 WKUserScript *userScript = [[WKUserScript alloc] initWithSource:scriptStr injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
 [userContentController addUserScript:userScript];
 [userContentController addScriptMessageHandler:self name:<#自定义name#>];
 // 实现WKScriptMessageHandler方法
 // 收到通知
 - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
 }
可以判断页面退出吗???主要是手势返回
- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];
    if (!self.navigationController && //navigation
        !self.tabBarController &&   //tabbar
        !self.presentingViewController) //present
    {
        [self deleteHanderMethod];
    }
}
不这样会导致内存泄露???
在viewWillAppear设置
if (self.bridge) {
  //不设置 WKWebView 代理不执行
  [self.bridge setWebViewDelegate:self];
}
在viewWillDisappear 设置
[self.bridge setWebViewDelegate:nil];
webViewDelegate
//绕过证书认证
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler {
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        NSURLCredential *card = [[NSURLCredential alloc]initWithTrust:challenge.protectionSpace.serverTrust];
        completionHandler(NSURLSessionAuthChallengeUseCredential,card);
    }else {
        completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
    }
}

//页面开始加载
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
  //
}
//页面加载完成
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
  //
}
//页面加载失败
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error {
   //
}
//收到响应后是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {
    decisionHandler(WKNavigationResponsePolicyAllow);
}
-(void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
    
    NSURL *linkUrl = navigationAction.request.URL;
    if (navigationAction.navigationType == WKNavigationTypeLinkActivated && [self.urlStr containsString:@"jumpWebUrl=1"]) {
        //url包含jumpWebUrl=1字段 允许跳转外部链接
        if (![linkUrl.host containsString:webView.URL.host]) {
            //当前链接域名不一致 跳转新H5类
            [self goWebViewController:@"" urlStr:navigationAction.request.URL.absoluteString];
            decisionHandler(WKNavigationActionPolicyCancel);
            return;//不return崩溃
        }
    }
    
    NSString *urlScheme = linkUrl.scheme;
    if (urlScheme.length && ([linkUrl.host containsString:@"itunes.apple.com"] || ![urlScheme containsString:@"http"])) {
        
        NSString *scheme = @"";
        if ([urlScheme isEqualToString:@"tel"]) {
            scheme = @"telprompt";//拨打电话☎️会弹窗提示
        } else {
            scheme = urlScheme;
        }
        
        if (IOS10_OR_LATER) {
            [[UIApplication sharedApplication]openURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@:%@",scheme,[linkUrl resourceSpecifier]]] options:@{} completionHandler:nil];
        } else {
            [[UIApplication sharedApplication]openURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@:%@",scheme,[linkUrl resourceSpecifier]]]];
        }
        decisionHandler(WKNavigationActionPolicyCancel);
        return;//不return崩溃
    }
    if (navigationAction.targetFrame == nil) {
        [webView loadRequest:navigationAction.request];
    }
    decisionHandler(WKNavigationActionPolicyAllow);
}

//弹窗
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
  //
}
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler {
  //
}
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler { 
  //
}

其他方法
goBack; //处理显示`返回``关闭`按钮
//禁止缩放 方法不是很完美 

//这个已废:
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {~~
    return nil;
}

//这是有效的:
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
  let js = "var script = document.createElement('meta');script.name = 'viewport';script.content=\"width=device-width, user-scalable=no\";document.getElementsByTagName('head')[0].appendChild(script);"
  webView.evaluateJavaScript(js, completionHandler: nil)
}

其他缩放方法(没测试):这里

WKWebView暂告一段落了

你可能感兴趣的:(WKWebView 小记)