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)
}
其他缩放方法(没测试):这里