前言由于每次打包上传appStore,苹果都会给你一个警告邮件

(已弃用的API使用-自2020年12月起,将不再接受使用UIWebView的应用程序更新),所以替换成WKWebView就是早晚的问题,于是这两天就在做项目的整体替换.
WKWebView优势:
在性能、稳定性、功能方面有很大提升(最直观的体现就是加载网页是占用的内存);
允许JavaScript的Nitro库加载并使用(UIWebView中限制);
支持了更多的HTML5特性;
高达60fps的滚动刷新率以及内置手势;
1.UIWebview打电话的问题可见:打电话
https://www.jianshu.com/p/abfedeff96e3
// old修改前
NSURL *phoneUrl = [NSURL URLWithString:[NSString stringWithFormat:@"tel://%@",phoneNumber]];
UIWebView * callWebview = [[UIWebView alloc] init];
[callWebview loadRequest:[NSURLRequest requestWithURL:phoneUrl]];
[weakSelf.view addSubview:callWebview];
// new修改后
NSString *phoneStr = [NSString stringWithFormat:@"telprompt://%@",phoneNumber];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:phoneStr]];
2.加载HTML的控制器抽取BaseWKWebViewController(抽取公共的开始加载,加载完成,加载失败等的公共方法)
BaseWKWebViewController.h文件 这里的BaseNameVC是自定义的基础控制器方便于开始loading结束loading的
#import "BaseNameVC.h"
#import <WebKit/WebKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface BaseWKWebViewController : BaseNameVC
@property (nonatomic,strong) WKWebView *webView;
@end
NS_ASSUME_NONNULL_END
BaseWKWebViewController.m
#import "BaseWKWebViewController.h"
#import <WebKit/WebKit.h>
@interface BaseWKWebViewController ()<WKUIDelegate,WKNavigationDelegate>
@end
@implementation BaseWKWebViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
// 页面准备加载时调用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
[self startLoadingNOTouch:nil];
}
// 页面内容开始加载
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
[self startLoadingNOTouch:nil];
}
// 页面加载失败时调用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error {
[self stopLoading];
}
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error {
[self stopLoading];
}
// 页面加载完成之后调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
[self stopLoading];
// 禁用用户选择
[self.webView evaluateJavaScript:@"document.documentElement.style.webkitUserSelect='none';"completionHandler:nil];
// 禁止用户长按
[self.webView evaluateJavaScript:@"document.documentElement.style.webkitTouchCallout='none';" completionHandler:nil];
}
- (WKWebView *)webView {
if (_webView == nil) {
WKWebViewConfiguration *webConfiguration = [WKWebViewConfiguration new];
_webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:webConfiguration];
_webView.navigationDelegate = self;
_webView.UIDelegate = self;
}
return _webView;
}
一般的加载控制器,继承自BaseWKWebViewController完全够用了,如果是有特殊需求的,可以子控制器去实现相应的代理方法,子类会覆盖掉父类的实现.
//调用
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title= @"活动详情";
[self.view addSubview:self.webView];
[self createLeftNaviBarBtnItem];
[self createNaviRightbtn];
[self loadSmallImageFromService];
NSURLRequest *request;
NSString *loadUrlstring = [NSString returnAdTimeStampString:self.urlstring];
request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:loadUrlstring]];
[self.webView loadRequest:request];
}
Ps:UIWebView代理方法对应WKWebView关系以及详细注释
1.创建方式不同
// UIWebView <UIWebViewDelegate>
- (UIWebView *)showWebView{
if (!_showWebView) {
_showWebView =[[UIWebView alloc] initWithFrame:self.view.bounds];
_showWebView.backgroundColor = BACKlightGray;
_showWebView.scrollView.backgroundColor = BACKlightGray;
[_showWebView.scrollView setContentInset:UIEdgeInsetsMake(0, 0, 0, 0)];
_showWebView.delegate = self;
}
return _showWebView;
}
// wkwebview这些基本够用了,当然进度estimatedProgress这个属性也可以放在代理方法里面去拿到设置进度条UI,这里有不需要的可以适当增删 ##import <WebKit/WebKit.h><WKUIDelegate,WKNavigationDelegate>
- (WKWebView *)webView{
if (_webView == nil) {
// 配置网页的配置文件
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc]init]; //WKWebview配置对象
WKPreferences *preference = [[WKPreferences alloc]init];
config.preferences = preference;
//是否允许与js进行交互,默认是YES的,如果设置为NO,js的代码就不起作用了
preference.javaScriptEnabled = YES;
WKUserContentController *userContentController = [[WKUserContentController alloc]init];//交互的重要之点
config.userContentController = userContentController;
// 设置代理
_webView.UIDelegate = self;
_webView.navigationDelegate = self;
// 添加进度监控
/*
NSKeyValueObservingOptionNew 把更改之前的值提供给处理方法
NSKeyValueObservingOptionOld 把更改之后的值提供给处理方法
NSKeyValueObservingOptionInitial 把初始化的值提供给处理方法,一旦注册,立马就会调用一次。通常它会带有新值,而不会带有旧值。
NSKeyValueObservingOptionPrior 分2次调用。在值改变之前和值改变之后。
*/
[_webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
// 开启手势触摸
_webView.allowsBackForwardNavigationGestures = YES;
// 适应设定的尺寸
[_webView sizeToFit];
}
return _webView;
}
2.代理方法对比
// 页面开始加载时调用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
}
// 页面加载失败时调用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error {
[self.progressView setProgress:0.0f animated:NO];
}
// 当内容开始返回时调用
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
}
// 页面加载完成之后调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
[self getCookie];
}
//提交发生错误时调用
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error {
[self.progressView setProgress:0.0f animated:NO];
}
// 接收到服务器跳转请求即服务重定向时之后调用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation {
}
// 重要:用得最多也是最不好对应的方法根据WebView对于即将跳转的HTTP请求头信息和相关信息来决定是否跳转 ==等价于UIWebView - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSString * urlStr = navigationAction.request.URL.absoluteString;
NSLog(@"发送跳转请求:%@",urlStr);
//自己定义的协议头
NSString *htmlHeadString = @"github://";
if([urlStr hasPrefix:htmlHeadString]){
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"通过截取URL调用OC" message:@"你想前往我的Github主页?" preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:([UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
}])];
[alertController addAction:([UIAlertAction actionWithTitle:@"打开" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
NSURL * url = [NSURL URLWithString:[urlStr stringByReplacingOccurrencesOfString:@"github://callName_?" withString:@""]];
[[UIApplication sharedApplication] openURL:url];
}])];
[self presentViewController:alertController animated:YES completion:nil];
decisionHandler(WKNavigationActionPolicyCancel);
}else{
decisionHandler(WKNavigationActionPolicyAllow);
}
}
// 根据客户端受到的服务器响应头以及response相关信息来决定是否可以跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
NSString * urlStr = navigationResponse.response.URL.absoluteString;
NSLog(@"当前跳转地址:%@",urlStr);
//允许跳转
decisionHandler(WKNavigationResponsePolicyAllow);
//不允许跳转
//decisionHandler(WKNavigationResponsePolicyCancel);
}
//需要响应身份验证时调用 同样在block中需要传入用户身份凭证
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler{
//用户身份信息
NSURLCredential * newCred = [[NSURLCredential alloc] initWithUser:@"user123" password:@"123" persistence:NSURLCredentialPersistenceNone];
//为 challenge 的发送方提供 credential
[challenge.sender useCredential:newCred forAuthenticationChallenge:challenge];
completionHandler(NSURLSessionAuthChallengeUseCredential,newCred);
}
//进程被终止时调用
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView{
}
网友评论