iOS 自定义封装WKWebView,可以网页回退转跳,与网页交互事件监听,解决内存释放问题

自己封装的WKWebView,功能如下:
1、加载网页URL
2、网页转跳返回
3、与网页之间的交互事件
4、退出界面清除缓存
5、释放内存,防止内存溢出

使用方法:

HBWebViewVC *vc = [[HBWebViewVC alloc]init];
vc.url = @"https://www.baidu.com";
 [self.navigationController pushViewController:vc animated:YES];

部分关键代码:

#pragma mark 初始化webview
-(void)initWKWebView{
    WKWebViewConfiguration * configuration = [[WKWebViewConfiguration alloc]init];
    configuration.preferences.javaScriptEnabled = YES;//打开js交互
    //这两个方法有内存泄漏,需要解决一下
    [configuration.userContentController addScriptMessageHandler:self name:@"Native"];
    [configuration.userContentController addScriptMessageHandler:self name:@"callApp"];
    configuration.preferences.minimumFontSize = 0;

    _webConfiguration = configuration;
    _jsHandler = [[HBJSHandler alloc]initWithViewController:self configuration:configuration];
    
    _webView = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT-bAllNavTotalHeight-kBottomSafeHeight) configuration:configuration];

    _webView.scrollView.backgroundColor = [UIColor whiteColor];
     [self.webView setOpaque:NO];
    _webView.navigationDelegate = self;
    _webView.backgroundColor = [UIColor whiteColor];
    _webView.allowsBackForwardNavigationGestures =YES;//打开网页间的 滑动返回
    _webView.scrollView.decelerationRate = UIScrollViewDecelerationRateNormal;
    //监控进度
    [_webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
    [_webView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:NULL];
    [self.view addSubview:_webView];
    //进度条
    _progressView = [[UIProgressView alloc]initWithProgressViewStyle:UIProgressViewStyleDefault];
    _progressView.tintColor = [UIColor redColor];
    _progressView.trackTintColor = [UIColor clearColor];
    _progressView.frame = CGRectMake(0, 0, self.view.bounds.size.width, 5.0);
    [_webView addSubview:_progressView];
    
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:_url]];
    [_webView loadRequest:request];
    NSLog(@"打印一下网页链接:%@",_url);
    
    //更新导航栏按钮
    [self updateNavigationItems];
}
#pragma mark ==========KVO 监测进度==========
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"estimatedProgress"] && object == self.webView) {
        self.progressView.progress = self.webView.estimatedProgress;
        if (self.progressView.progress == 1) {
            __weak typeof (self)weakSelf = self;
            [UIView animateWithDuration:0.25f delay:0.3f options:UIViewAnimationOptionCurveEaseInOut animations:^{
                weakSelf.progressView.transform = CGAffineTransformMakeScale(1.0f, 1.4f);
            } completion:^(BOOL finished) {
                weakSelf.progressView.hidden = YES;
            }];
        }
    }else if ([keyPath isEqualToString:@"title"] && object == self.webView){//网页title
        NSInteger titleLength = 0;
        if (kUI_IPHONE5) {
            titleLength = 6;
        }else if (kUI_IPHONE6){
            titleLength = 9;
        }else if (kUI_IPHONE6PLUS){
            titleLength = 12;
        }else{
            titleLength = 9;
        }
        if (self.webView.title.length > titleLength) {
            NSString *titleStr = [self.webView.title substringToIndex:titleLength];
            self.title = [NSString stringWithFormat:@"%@...",titleStr];
        }else{
            self.title  =self.webView.title;
        }
    }else{
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}
#pragma mark - WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    NSLog(@"方法名:%@", message.name);
    NSLog(@"参数:%@", message.body);
    //自定义参数,这个可以跟前端后台统一参数,可以传字典类型
    //[HBClickEventManage GTPushViewController:nil andPushVC:self isPushType:2 ClickType:[message.body objectForKey:@"function"] clickParameter:[message.body objectForKey:@"parameters"] ClickUrl:@"" Title:@""];
}

#pragma mark ==========加载完成==========
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
    NSString *injectionJSString = @"var script = document.createElement('meta');"
    "script.name = 'viewport';"
    "script.content=\"width=device-width, initial-scale=1.0,maximum-scale=1.0, minimum-scale=1.0, user-scalable=no\";"
    "document.getElementsByTagName('head')[0].appendChild(script);";
    [webView evaluateJavaScript:injectionJSString completionHandler:nil];
    
    //更新进度调
    [self updateProgress:webView.estimatedProgress];
    
    //更新导航栏按钮
    [self updateNavigationItems];
}
#pragma mark ==========更新进度条==========
-(void)updateProgress:(double)progress{
    self.progressView.alpha = 1;
    if(progress > _lastProgress){
        [self.progressView setProgress:self.webView.estimatedProgress animated:YES];
    }else{
        [self.progressView setProgress:self.webView.estimatedProgress];
    }
    _lastProgress = progress;
    
    if (progress >= 1) {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            self.progressView.alpha = 0;
            [self.progressView setProgress:0];
            self.lastProgress = 0;
        });
    }
}
//加载失败 隐藏progressView
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error {
    self.progressView.hidden = YES;
    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
}
#pragma mark ==========判断链接是否允许跳转==========
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
    NSURL *URL = navigationAction.request.URL;
    NSString *scheme = [URL scheme];
    // 打电话
    if ([scheme isEqualToString:@"tel"]) {
        UIApplication *app = [UIApplication sharedApplication];
        if ([app canOpenURL:URL]) {
            [app openURL:URL];
            // 一定要加上这句,否则会打开新页面
            decisionHandler(WKNavigationActionPolicyCancel); return;
        }
    } // 打开淘宝
    if ([scheme isEqualToString:@"tbopen"]) {
        if (!self.isTBDidLoad) {//避免重复跳淘宝开关
            UIApplication *app = [UIApplication sharedApplication];
            if ([app canOpenURL:URL]) {
                [app openURL:URL];
                // 一定要加上这句,否则会打开新页面
                self.isTBDidLoad = YES;
                decisionHandler(WKNavigationActionPolicyCancel); return;
            }
        }else{
            decisionHandler(WKNavigationActionPolicyAllow); return;
        }
    } // 打开appstore
    if ([URL.absoluteString containsString:@"ituns.apple.com"]) {
        UIApplication *app = [UIApplication sharedApplication];
        if ([app canOpenURL:URL]) {
            [app openURL:URL];
            decisionHandler(WKNavigationActionPolicyCancel);
            return;
        }
    }
    //如果是跳转一个新页面
    if (navigationAction.targetFrame == nil) {
        [webView loadRequest:navigationAction.request];
        decisionHandler(WKNavigationActionPolicyAllow);
        return;
    }
    decisionHandler(WKNavigationActionPolicyAllow);
}
//  * 拿到响应后决定是否允许跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
    decisionHandler(WKNavigationResponsePolicyAllow);
}
#pragma mark ==========继承方法==========
-(void)closeItemInNaviClicked{
    NSLog(@"closeItemInNaviClicked");
}
#pragma mark - update nav items
-(void)updateNavigationItems{
    NSLog(@"canGoBack ==%d",self.webView.canGoBack);
    if (self.webView.canGoBack) {
        self.navigationController.interactivePopGestureRecognizer.enabled = NO;
        [self addWebNavigationItemWithTitles:@[@"mine_back_share_img", @"close_treasure_img"] isLeft:YES target:self action:@selector(leftBtnClick:) tags:@[@2000,@2001]];
    }else{
        self.navigationController.interactivePopGestureRecognizer.enabled = YES;
        [self addWebNavigationItemWithTitles:@[@"mine_back_share_img"] isLeft:YES target:self action:@selector(leftBtnClick:) tags:@[@2000]];
    }
}

- (void)addWebNavigationItemWithTitles:(NSArray *)titles isLeft:(BOOL)isLeft target:(id)target action:(SEL)action tags:(NSArray *)tags{
    NSMutableArray * items = [[NSMutableArray alloc] init];
    NSInteger i = 0;
    for (NSString *imgNameStr in titles) {
        UIButton * btn = [UIButton buttonWithType:UIButtonTypeCustom];
        btn.frame = CGRectMake(0, 0, 44 , 44);
        btn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
        [btn setImage:[UIImage imageNamed:imgNameStr] forState:UIControlStateNormal];
        if (i==0) {
            btn.backgroundColor = [UIColor redColor];
        }else{
            btn.backgroundColor = [UIColor blueColor];
        }
        [btn addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
        btn.tag = [tags[i++] integerValue];
        UIBarButtonItem * item = [[UIBarButtonItem alloc] initWithCustomView:btn];
        [items addObject:item];
    }
    if (isLeft) {
        self.navigationItem.leftBarButtonItems = items;
    } else {
        self.navigationItem.rightBarButtonItems = items;
    }
}

-(void)customBackItemClicked{
    self.webView.canGoBack? [self.webView goBack]: [self backBtnInNaviClicked];
}
#pragma mark ==========点击关闭按钮==========
-(void)closeWeb{
    NSLog(@"调用关闭按钮");
    [_jsHandler cancelHandler];
    [self.navigationController popViewControllerAnimated:YES];
}

最后附上DEMO地址

如果能帮助到你请点赞评论支持,谢谢!

END.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明似水

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值