wkwebview 开发中遇到的问题-加载时机和js的交互

在开发中有这个需求,选择若干个播放资源,然后将基本资源信息发送给js做html的展示,其中包含播放列表和播放区域。

最初的讨论是为了加快开发速度,不走java支持,将需要的数据打包成参数字典的形式来累加到url上,比如:

//dic为已经打包好的字典类型的数据结构,首先把dic转换成data

 

NSData jsonData = [NSJSONSerializationdataWithJSONObject:dic options:0 error:nil];

                //url string is the base play page url

                NSMutableString *urlString = 获取baseurl;

//然后将data转换成string

                [urlString appendString:[[NSStringalloc]initWithData:jsonDataencoding:NSUTF8StringEncoding]];

//然后进行特殊字符,空格,中文等的转译工作

              NSString *finalUrlString = [[urlStringstringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSetURLQueryAllowedCharacterSet]] mutableCopy];

            }

//然后把dic作为url?后面的参数部分进行传递

        NSMutableURLRequest *request = [[NSMutableURLRequestalloc]initWithURL:[NSURLURLWithString:finalUrlString]];

        [self.webViewloadRequest: request];

//js就会收到请求,让后进行解析数据和重新组装

这样实现不需要走java,不需要开新接口,但是问题就来了,当测试的时候请求的数据参数长度达到了一定的长度后,js出错,无法渲染出html页面,此时手动截短url长度,打开浏览器,可以粘贴成功并且可以访问了,说明的确是url长度超限了。就不同的浏览器url超限的长度是不同的,而且即便统一浏览器不同的版本url长度限制页存在差异,比如:(如果参数包含中文,那么所占用的字节更多)

Firefox
对于Firefox1.5.x,地址栏能显示的URL最大长度是65,536个字符,但实际上有效的URL最大长度不少于100,000个字符。
对于Firefox 3.0.5,mozilla官方论坛上有人测试其URL长度限制为65,000个字符。
也有人说Firefox可以支持URL高达2Gbyte的长度(参考),在data URL中可以运用到这样大数据量的URL。dataURL是一种URL本身包含了实际数据的URL,比如一个图片、一个HTML网页或者全部的数据、代码等等。仅有Firefox支持dataURL。
data URL示例:

 
 
   

This is a data URL

">This is a test
 


Safari
Safari最少支持80,000个字符长度的URL。

Opera
Opera官方网站上说,Opera并没有强制限制URL的长度。
网友测试Opera 9支持最少190,000个字都长度的URL,并且Opera9的地址栏可以显示、编辑、复制和粘贴完整的URL串。

 

那么这种方式就是存在隐患的。因此考虑使用java接口或者其他方式。由于pc端使用的localstorage,那么看看wkwebview是否也可以使用localstorage传递参数。答案是肯定的。

 

于是在didFinishNavigation中添加对应的删除和设置localstorage的操作。发现一个很奇怪的问题,js和app端数据读取的同步时机上总是有问题,导致页面要不就显示旧的内容,要不就什么也显示不出来。折腾半天。最后讨论中突然想起了android和ios中的webview finish并不是真正的监听到了网页最终加载完成,可能此时页面还没有最终完全的加载和渲染出来。于是会有时机上的不对。怎么办呢?因为虽然app不知道确切的finish loading的时间,但是有人知道呀,就是js呀。于是最终的方案确定了,在js finish后通知native我加载完成了,可以给我数据了,于是native此时再删除旧有的localstorage,然后set新的localstorage,并通知js set 完成了,因为js只负责取,他也不知道什么时候真正set成功了。于是需要native 告诉他可以取了,虽然有点儿麻烦,但是最终解决了问题。代码如下:

 

 

 WKWebViewConfiguration *config = [WKWebViewConfigurationnew];

//添加js调用native的方法

[config.userContentControlleraddScriptMessageHandler:selfname:@"finish"];

self.webView = [[WKWebViewalloc] initWithFrame:self.frameconfiguration:config];

 

- (void)userContentController:(WKUserContentController *)userContentController

      didReceiveScriptMessage:(WKScriptMessage *)message{

    NSDictionary *sentData = (NSDictionary*)message.body;

    NSString *methodName = [sentDataobjectForKey:@"method"];

     if([methodName isEqualToString:@"finish"]) {

              NSString *removeUserContent = @"localStorage.removeItem('params')";

//移除旧有的localstorage            [self.webView evaluateJavaScript:removeUserContent completionHandler:^(id _Nullable obj, NSError * _Nullableerror) {

                if (error == nil) {

//设置localstorage

                    NSString *jsString = [NSString stringWithFormat:@"localStorage.setItem('params', '%@')", self.finalJsonString];

                    [self.webView evaluateJavaScript:jsString completionHandler:^(id _Nullable obj, NSError * _Nullableerror) {

                        if (error == nil) {

//调用js端的方法告知已经设置成功了,可以get了                            [self.webView evaluateJavaScript:@"succed()" completionHandler:^(id _Nullable script, NSError* _Nullable error) {

                                if (error == nil) {

                                } else {

                                }

                                

                            }];

                        }

                    }];

                } else {

                }

                

            }];

        }

 

}

经过查找也同时有其他的kvo解决方式,代码如下:

 

    [self.webView addObserver:self forKeyPath: @"loading" options:NSKeyValueObservingOptionNew context:nil];

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {

    id observeObj = object;

    if (![observeObj isEqual:self.webView]) {

        return;

    }

    if ([keyPath isEqualToString:@"loading"]) {

        //loading keypath

        NSLog(@"start loading");

       BOOL didChange =  [[change valueForKeyPath:NSKeyValueChangeNewKey] boolValue];

        if (didChange) {

            NSLog(@"webview did change");

        } else {

            NSLog(@"webview loading finished"); // self.webView.loading 为0

//在这里可以做对应的加载完毕后的处理了

           

}

 

注意:需要在addobserver后适时地去remove掉这个observer,特别注意当html有刷新机制时会反复调用这一系列状态,所以需要在执行完第一次的处理后就立即将observer移除掉。否则的话可以在退出这个界面的时候remove掉这个observer。

综上所述:还是使用第一种解决方式,让js端告知加载完成了。

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值