美文网首页
从UIWebView到WKWebView替换历程(一)

从UIWebView到WKWebView替换历程(一)

作者: LiuffSunny | 来源:发表于2020-06-08 20:38 被阅读0次

前言由于每次打包上传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{
}

相关文章

网友评论

      本文标题:从UIWebView到WKWebView替换历程(一)

      本文链接:https://www.haomeiwen.com/subject/bbldtktx.html