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示例:
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端告知加载完成了。
最初的讨论是为了加快开发速度,不走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最少支持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端告知加载完成了。
相关文章推荐
- IOS开发(7)WKWebView加载本地HTML、CSS、JS文件JS(解决html内访问其他资源路径问题)
- IOS 使用 WKWebView 加载本地的JS和CSS文件出现乱码问题
- iOS开发中的WKWebView与JS的交互
- IOS UIWebView转WKWebView中的js交互问题
- iOS WKWebView与JS交互及不能释放问题
- Android开发中webView的使用以及与js交互传值问题
- WKWebView和UIWebView加载本地html和JS交互各种坑解决办法
- iOS 8 WkWebView 网页的配置和前进,后退,js 交互和进度条的加载
- iOS开发中OC与H5网页交互之OC传值给JS(WKWebView)
- iOS 8 WkWebView 网页的配置和前进,后退,js 交互和进度条的加载
- WKWebView 基本使用及与JS交互,以及低版本系统崩溃问题解决
- iOS开发之WKWebView的使用以及遇到的问题
- [IOS开发]js与WKwebview交互Demo(调取二维码扫描)
- android h5 js 混合开发解决webview加载白屏,不加载网页的问题(硬件加速网页渲染,优化体验)
- webview 笔记二(android和js交互、包括链接跳转常见问题处理,加载监视,拦截Url等)
- iOS 加载HTML的相关问题(与JS的互相调用和WKWebView加载本地网页)
- WebView与js交互遇到的问题
- iOS wkwebview懒加载中遇到的问题
- android webview与js交互时遇到的问题解决
- iOS开发,webView加载图片, js交互, 点击图片放大