WKWebView或UIWebView无法拦截的页面地址变更问题

简介: WKWebView或UIWebView无法拦截的页面地址变更问题

大家有没有发现微信端的js代码移植到ios app上,当点击js上的按钮跳转到页面,咱们的WKWebView或UIWebView无法拦截到这个地址的变更。

当h5页面的第一页面为下面的地址:http://test/market/homepage.htm,当点击他们上的按钮跳转到一个新的网页地址(https://test/market/homepage.htm#!/https://test/market/auction/detail.htm?aId=12)并刷新页面,而UIWebView的页面加载完回调函数(-(void)webViewDidFinishLoad:(UIWebView )webView)和加载前函数(-(BOOL)webView:(UIWebView )webView shouldStartLoadWithRequest:(nonnull NSURLRequest )request navigationType:(UIWebViewNavigationType)navigationType)没有任何回调;同样WKWebView的页面加载完回调函数(-(void)webView:(WKWebView )webView didFinishNavigation:(WKNavigation )navigation)和服务器开始请求的时候调用回调函数(- (void)webView:(WKWebView )webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler)没有任何回调。我把这两个控件的所有协议函数都实现也没有看到它回调他们,并且连WKWebView的进度条 KVO监听函数也没有回调,导致页面跳转时没有显示进度条。

我研究了两天发现,无语了,WKWebView根本根本无法监控到这种页面的变化。经过分析可能是页面被替换时,可能是os系统可能比较两者的地址是否互相以其中一个为前缀,若是就不回调。而UIWebView由于设置了HybridNSURLProtocol协议拦截,部分子页面通过canInitWithRequest回调,不经过didFinishNavigation回调。

但是我们的需求是要监控到这种页面变更,若是几个指定的首页页面不能显示返回按钮,若不是首页的页面请求需要显示返回按钮。

最好真的办法了,最终通过监控页面的变化来查看当前页面url来决定是否显示返回按钮。

下面是一个不完美的判断当前页面的方法,在我们的app测试时有小bug。

WKWebView的self.wkWebView.backForwardList.currentItem一般是当前页面(但是当一个tabbar页面有个子页面,可能这个地址并非时真实的当前网页地址,所以最好别用它),这个地址:NSString *url = [self.wkWebView.URL.absoluteString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];一般是当前页面具体地址。

backForwardList是可以返回的页面请求地址。不过最好别直接读这个数组,或计算它的个数。因为页面变化时,这个数组会变化的。大家知道,当一个可变数组正变化时,另一个线程计算它的个数可能引起crash.

获取当前页面的地址最直接的方法是通过:self.wkWebView.URL.absoluteString直接获取。


问题是何时去读区当前页面的地址呢?由于WKWebView有一个成员对象scrollView,而UIScrollView的contentSize属性是可以通过KVO监控的。我们采用的响应式编程ReactiveCocoa这个库,通过这段代码监控页面尺寸的变化:

    [RACObserve(self.wkWebView.scrollView, contentSize) subscribeNext:^(id x) {
        @strongify(self);
        NSLog(@"xxxxxx:%@, nowTime:%lld毫秒", x, (long long)([[NSDate date] timeIntervalSince1970]*1000));
        [self updateNavigationItems:self.wkWebView.URL.absoluteString];
    }];

大家可以看到只要页面地址变化,这个KVO都能监控到,当然有的js页面是不断刷新的,这个KVO也能监控到,这个频率不是一般的快,大约20毫秒左右就会出现一次页面尺寸的变化,当然有的页面加载完成后变化几次就不会引起页面尺寸的变化了。页面变化那么快,也就是手机打开网页,电量下降飞快的原因吧?

2018-05-31 17:19:26.114506+0800 ArtEnjoymentWeChatAuction[61101:5370688] xxxxxx:NSSize: {320, 504}, nowTime:1527758366114毫秒
2018-05-31 17:19:26.114783+0800 ArtEnjoymentWeChatAuction[61101:5370688] current url:https://test/market/homepage.htm
2018-05-31 17:19:26.122076+0800 ArtEnjoymentWeChatAuction[61101:5370688] xxxxxx:NSSize: {320, 504}, nowTime:1527758366121毫秒
2018-05-31 17:19:26.122325+0800 ArtEnjoymentWeChatAuction[61101:5370688] current url:https://test/market/homepage.htm
2018-05-31 17:19:26.148894+0800 ArtEnjoymentWeChatAuction[61101:5370688] xxxxxx:NSSize: {320, 504}, nowTime:1527758366148毫秒
2018-05-31 17:19:26.149110+0800 ArtEnjoymentWeChatAuction[61101:5370688] current url:https://test/market/homepage.htm

根据这个KVO更新返回按钮的隐藏属性就可以。

-(void)updateNavigationItems:(NSString *)url
{
//    WKBackForwardListItem *currentItem = self.wkWebView.backForwardList.currentItem;
//    NSString *url = [currentItem.URL.absoluteString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    FLDDLogVerbose(@"current url:%@", url);
    self.navigationItem.leftBarButtonItem.customView.hidden = [AWGeneralFunction isHiddenWebBackButton:url];
}

-(BOOL)isHiddenWebBackButton:(NSString *)reqUrl
{
    if(isEmptyString(reqUrl))
    {
        return YES;
    }
    if(([reqUrl rangeOfString:homepageHtml].location != NSNotFound) && ([reqUrl rangeOfString:homepageExtendHtml].location == NSNotFound))
    {
        return YES;
    }
    else
    {
        return NO;
    }
}

具体代码见:https://blog.csdn.net/jia12216/article/details/80526133

用loadWebURLSring跳转到这个h5页面,加载远程js代码(h5地址上个页面提供)或在viewDidLoad加载指定的js地址(页面控制器指定h5地址)都可以,也可以加载本地代码(本地h5页面)。


上面的解决方案思路是对的,用KVO监控self.wkWebView.scrollView的contentSize,由于页面可能不断刷新,飞速的调用监控的处理函数(就是一个页面加载多次重复回调页面变化处理函数),这样功能是实现了,但是这样重复的操作实在没有必要。当时我找了几天我都没有找到更完美的解决方案。今天我偶然发现他的最佳解决方案。通过KVO监控URL的变化,并且就是像上面介绍的一个请求地址里包含两个Url也会回调,并且只回调一次。具体代码如下,在viewDidLoad函数中增加下面的代码:

[self.wkWebView addObserver:self forKeyPath:@"URL"options:NSKeyValueObservingOptionNew context:nil];

在observeValueForKeyPath函数中增加下面的代码,注意这个函数包含WKWebView的进度条的处理,要识别keyPath是@”URL”的情况判断,不判断乱使用app会crash的,测试用的是WKWebView控件:

//KVO监听进度条
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {

    if ([keyPath isEqualToString:NSStringFromSelector(@selector(estimatedProgress))] && object == self.wkWebView) {
        [self.progressView setAlpha:1.0f];
        BOOL animated = self.wkWebView.estimatedProgress > self.progressView.progress;
        [self.progressView setProgress:self.wkWebView.estimatedProgress animated:animated];

        // Once complete, fade out UIProgressView
        if(self.wkWebView.estimatedProgress >= 1.0f) {
            [UIView animateWithDuration:0.3f delay:0.3f options:UIViewAnimationOptionCurveEaseOut animations:^{
                [self.progressView setAlpha:0.0f];
            } completion:^(BOOL finished) {
                [self.progressView setProgress:0.0f animated:NO];
            }];
        }
    }
    else if([keyPath isEqualToString:@"URL"] && object == self.wkWebView)
    {
        [self updateNavigationItems:self.wkWebView.URL.absoluteString];
        NSLog(@"url == %@",self.wkWebView.URL.absoluteString);
    }
    else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

真搞不懂WKWebView为何不所有页面都走didStartProvisionalNavigation代理函数,这明显是它的bug,这不是害我们吗?


目录
相关文章
|
移动开发 小程序
微信小程序web-view嵌入uni-app H5页面,通过H5页面跳转企业微信客户聊天窗口如何操作?
微信小程序web-view嵌入uni-app H5页面,通过H5页面跳转企业微信客户聊天窗口如何操作?
|
9月前
|
JSON API 开发者
淘宝淘口令转换API接口(淘宝API系列)
淘宝淘口令转换API是用于将淘宝商品或店铺链接与淘口令进行双向转换的接口,支持HTTP POST请求。开发者可通过此API生成或解析淘口令,方便在不同平台传播淘宝内容,吸引更多潜在客户。API返回JSON格式数据,包含转换结果和状态信息。使用前需注册并申请权限,确保调用稳定可靠。示例代码展示了如何通过Python实现淘口令的生成和解析功能。
|
前端开发 数据处理 开发者
Flutter应用开发中滚动性能优化与无限列表实现的重要性
本文深入探讨了Flutter应用开发中滚动性能优化与无限列表实现的重要性。首先分析了影响滚动性能的因素,如布局复杂度、重绘频率和数据处理等。接着介绍了优化方法,包括懒加载、简化布局、控制重绘和高效数据处理。最后详细讲解了无限列表的实现原理及步骤,并通过案例分析展示了具体应用,旨在为开发者提供实用的技术指导。
268 5
|
存储 移动开发 缓存
多个WKWebView页面的cookie不共享问题及解决方案
多个WKWebView页面的cookie不共享问题及解决方案
357 0
|
Java Linux iOS开发
如何设置 Java 的环境变量
设置Java环境变量是使用Java开发工具和运行Java程序的前提。主要步骤包括:安装JDK,配置系统环境变量中的JAVA_HOME、PATH和CLASSPATH,确保命令行可直接调用javac和java命令。
552 6
|
安全
鸿蒙实现底部安全距离
鸿蒙实现底部安全距离
216 0
|
JavaScript
WKWebView采用HybridNSURLProtocol协议拦截图片等资源预加载
WKWebView采用HybridNSURLProtocol协议拦截图片等资源预加载
286 1
|
移动开发 Android开发 iOS开发
ios标准页面调用HTML5页面和HTML5调用ios的函数
ios标准页面调用HTML5页面和HTML5调用ios的函数
224 0
|
JavaScript
dyld: Library not loaded:解决办法
dyld: Library not loaded:解决办法
929 1