您的位置:首页 > 移动开发

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

2018-01-30 13:16 1626 查看
在开发中有这个需求,选择若干个播放资源,然后将基本资源信息发送给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<
4000
span class="s2">]
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端告知加载完成了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: