ios11 怎么知道safari wkwebview safari

IOS未安装APP获取Safari浏览器数据 - 胡东东博客
IOS未安装APP获取Safari浏览器数据
&1341&views
Categories:
Share to:
本篇文章的目的就是要达成未安装的app在安装app之后,去获取安装app之前Safari所浏览的数据,比如说用户在未安装手机百度时,已经在Safari浏览器中登录了百度帐号,当安装手机百度之后,打开该APP可以自动登录这个Safari浏览器中所登录的百度帐号。当然也可以达成那种效果,比如打开某个带有邀请码的网页推荐用户去下载app,当通过appstore下载完app之后,打开该app,可以知道该邀请码是多少,网页和下载app之间隔了一层appstore,不能从网页直接传值到app,所以如果未安装该app的话,就需要网页和app去读取一个相同的值去标记,但是对于ios系统来说,idfa等唯一标识符只能app获取,网页获取不到,所以一般无法通信比如上面这个图,A用户从web网页跳转到appstore,再从appstore下载app,但是这个过程中,也许用户A、B、C都在下载该软件,web网页是无法直接像app传送任何数据的,所以就需要确认到底哪个是从web网页推荐过来下载的,哪些是自己去appstore下载的。一、判断唯一用户1、通过idfa等标识判断idfa等唯一标识只有oc能获取,但是网页一般获取不到ios的idfa,uuid等硬件的唯一标识符(除非使用苹果配置文件,这个用户需要安装,无法做到无痕,而且使用起来比较麻烦,有兴趣的可以去看看)2、通过多重可获取的信息综合判断由于无法准确的获得idfa等信息,所以可以多记录几个网页和app都能获取的数据,比如网络模式、IP、时间、机型、位置等,通过多重判断来看是不是同一个人,但是这种方式是存在误差的,比如一个公司用的同一个网络同一个机型的两个人就会判断有错误。3、通过cookies判断之前是不可以的,因为ios应用是沙盒运行,app之间创建的webview之间的cookies都是沙盒状态的,但是ios9之后,终于增加了一个全新的类SFSafariViewController,这个相当于在app内部创建了一个safari浏览器,用的和safari浏览器共同的cookies,所以可以用SFSafariViewController来获取cookies二、使用SFSafariViewController这个SFSafariViewController很简单,导入头文件#import &SafariServices/SafariServices.h&就可以像其他普通的viewcontroller一样创建self.safariView&=&[[SFSafariViewController&alloc]&initWithURL:[NSURL&URLWithString:@&/&]];
self.safariView.delegate=
[self&presentViewController:self.safariView&animated:false&completion:nil]SFSafariViewController一般使用这两个代理函数//点击done按钮时调用
-&(void)safariViewControllerDidFinish:(SFSafariViewController&*)controller
&&&&NSLog(@&%s&,__func__);
//加载完成之后调用
-&(void)safariViewController:(SFSafariViewController&*)controller&didCompleteInitialLoad:(BOOL)didLoadSuccessfully
&&&&NSLog(@&%d&,didLoadSuccessfully);
}使用之后就可以打开指定的url,并且使用的是safari的cookies,打开的页面样子像下面这样下面的工具栏在代理中也可以设置,但是一般不自己再设置了三、网页和app共用cookies使用SFSafariViewController访问域名之后,用的就是用safari打开的页面的cookies,比如我在手机的safari页面打开的网址是:/uid/20,产生了一个cookies:20,然后我在app中打开网址的时候,就可以用到同一个cookies:20,,而别人如果没有用safari页面事先打开这个网址的话,cookies:20是不会有的,这样就知道是我打开的,然后我在app中给服务器单独传值即可。现在cookies虽然知道了,但是还有一点就是在SFSafariViewController中是获取不到cookies的,因为这个cookies存在safari系统中,那么怎么得到对应的值呢,那就需要服务端做一个对于你软件的scheme跳转了。因为当你访问网页的时候,网页可以获取到你的cookies,你无需手动获得cookies,需要做的就是使用这个cookies去登录app中需要打开的那个网站,而在网页返回数据中调用你软件的scheme,同时在调用的时候把定义的cookies或者其他值传进来,比如我软件的scheme是comjdnetkuaifa,那么可以通过js调用:location.href = &comjdnetkuaifa://uid/& +,这样就可以把用户的uid标识直接传过来了,然后在app中的代理方法-&(BOOL)application:(UIApplication&*)app&openURL:(NSURL&*)url&options:(NSDictionary&NSString*,&id&&*)options&NS_AVAILABLE_IOS(9_0)获取scheme传过来的值,比如像我们做的一样把uid传过来。cookies的作用仅仅是登录同一个网站让网页端去判断之前是哪个用户登录的,然后网页返回对应的需要的值即可。四、细节优化因为要做到无痕,就是在用户不知不觉间登录,所以需要调整SFSafariViewController的样式,因为如果使用presentViewController的方案,在viewcontroller之间跳转的话,肯定会影响用户的体验,而网上流传的方案&safari.view.alpha&=&0.0;
&safari.view.hidden&=&设置透明度为透明和隐藏的话,苹果现在官方是不允许的SafariViewContoller must be used to visibly present
the controller may not be hidden or obscured by other views or layers. Additionally, an app may not use SafariViewController to track users without their knowledge and consent.并且现在透明度最低设置为0.05,所以这个方案是会被拒的。网上提供了一种思路,可以考虑吧safariView加到现在的Viewcontroller中,&[self&addChildViewController:self.safariView];
&[self.view&addSubview:self.safariView.view];当使用完毕之后,再移除即可[self.safariView.view&removeFromSuperview];
[self.safariView&removeFromParentViewController];
self.safariView&=&但在实际运行中,发现如果这样处理的话的确隐藏了,但是却并没有调用访问。所以就用了一种解决方案是使用presentViewController切换界面[self&presentViewController:self.safariView&animated:false&completion:nil];在初始化完成的时候,切换过来即可-&(void)safariViewController:(SFSafariViewController&*)controller&didCompleteInitialLoad:(BOOL)didLoadSuccessfully
&&&&NSLog(@&didLoadSuccessfully:%d&,didLoadSuccessfully);
&&&&if&(didLoadSuccessfully)&{
&&&&&&&&[controller&dismissViewControllerAnimated:true&completion:nil];
}五、其他获取cookies的方法如果使用webview的话,可以在webview的代理函数中,去获取cookies。-&(void)webViewDidFinishLoad:(UIWebView&*)webView
&&&&NSHTTPCookieStorage&*sharedHTTPCookieStorage&=&[NSHTTPCookieStorage&sharedHTTPCookieStorage];
&&&&NSArray&*cookies&=&[sharedHTTPCookieStorage&cookiesForURL:[NSURL&URLWithString:@&/&]];
&&&&NSEnumerator&*enumerator&=&[cookies&objectEnumerator];
&&&&NSHTTPCookie&*
&&&&while&(cookie&=&[enumerator&nextObject])&{
&&&&&&&&NSLog(@&COOKIE{name:&%@,&value:&%@}&,&[cookie&name],&[cookie&value]);
&&&&&&&&[sharedHTTPCookieStorage&deleteCookie:cookie];
}但是这个cookies是沙盒中的cookies,就是软件自己的cookies,不是safari的cookies六、demo下载Github下载地址:GitOSC下载地址:当然还有另外一个别人写好可以测试网页的demogithub下载地址:七、参考文章
Sweeping payments
&Pay by WeChat
Leave a Comment
submitting...
Popular articles
评论数: 28
评论数: 18
评论数: 11
评论数: 10
评论数: 9
叫你还用百毒,活该被坑
请问渲染像素和物理像素有什么区别?提交时,视频应该按照哪种分辨...
是的,现在有个问题,就是我加载成功了,然后上下出现黑边,这个问...
楼主,我按照你的方法设置的,为什么启动图变成黑色的了呢?
I have been browsing online mor...
Random articles
评论数: 0
评论数: 0
评论数: 0
评论数: 0
评论数: 0
Categories教你使用 WKWebView 的正确姿势
作者:谢波
本文为原创文章,转载请注明作者及出处
WKWebView 是 iOS 8 之后提供的一款浏览器组件,其载入速度和内存占用对比老的 UIWebView 来说简直是一次飞跃。下面对比 UIWebView 介绍该组件如何去使用,以及使用过程中会存在的问题。
介绍:为什么需要 WKWebView
使用:对比 UIWebView 介绍
深入:JS 和 Native交互
重点:已知问题和解决方案
总结 & 结束
正文 一、介绍:为什么需要 WKWebView
用 Web 方式承载业务引入 app 的混合开发已成为一个硬性需求,并且随着业务的扩展和审核的限制,该比例会愈加增大,这样对承载的平台就有严格要求,而老旧的 UIWebView 存在严重的性能和内存消耗问题,限制了业务方的自由度。而自 iOS 8 之后,苹果提供的 WebKit 库包含了 WKWebView,WKWebView 采用跨进程方案,Nitro JS 解析器,高达 60fps 的刷新率,理论上性能和 Safari 比肩,而且对 H5 的高度支持,还提供了一个准确的加载进度值属性,我们没有理由拒绝这样的一个新事物。
二、使用:对比 UIWebView 介绍 使用
WKWebView 和 UIWebView 二者在使用上差不多(如下代码所示),如果仅做页面呈现和简单交互,不需要考虑太多的投入成本。 对比代码,二者在创建和使用上基本一致,通过一个 URL 字符串构建 Request 对象,然后使用WebView 内置接口载入 Request 对象即可。
UIWebView*webView = [[ UIWebViewalloc] init];
NSURL*url = [ NSURLURLWithString: @""];
[webView loadRequest:[ NSURLRequestrequestWithURL:url]];
WKWebView*webView = [[ WKWebViewalloc] init];
NSURL*url = [ NSURLURLWithString: @""];
[webView loadRequest:[ NSURLRequestrequestWithURL:url]];
流程上二者有一定的区别,如下图,左边是 UIWebView,右边是WKWebView,在节点上,WKWebView 比 UIWebView 多了一个询问过程,在服务器响应请求之后会询问是否载入内容到当前 Frame,在控制上会比UIWebView 粒度更细一些。
WKWebView 和 UIWebView 差异
以上流程的控制主要是用过 Protocol 去实现,WKWebView 的代理协议为 WKNavigationDelegate,对比 UIWebDelegate 首先跳转询问,就是载入 URL之前的一次调用,询问开发者是否下载并载入当前 URL,UIWebView 只有一次询问,就是请求之前的询问,而 WKWebView 在 URL 下载完毕之后还会发一次询问,让开发者根据服务器返回的 Web 内容再次做一次确定。
#pragma mark - UIWebViewDelegate
- ( BOOL)webView:( UIWebView*)webView shouldStartLoadWithRequest:( NSURLRequest*)request navigationType:( UIWebViewNavigationType)navigationType { returnYES;}
#pragma mark - WKNavigationDelegate
- ( void)webView:( WKWebView*)webView decidePolicyForNavigationAction:( WKNavigationAction*)navigationAction decisionHandler:( void(^)( WKNavigationActionPolicy))decisionHandler { }
- ( void)webView:( WKWebView*)webView decidePolicyForNavigationResponse:( WKNavigationResponse*)navigationResponse decisionHandler:( void(^)( WKNavigationResponsePolicy))decisionHandler { } #pragma mark - UIWebViewDelegate
- ( void)webViewDidStartLoad:( UIWebView*)webView {}
#pragma mark - WKNavigationDelegate
- ( void)webView:( WKWebView*)webView didStartProvisionalNavigation:( null_unspecifiedWKNavigation*)navigation { }
- ( void)webView:( WKWebView*)webView didCommitNavigation:( null_unspecifiedWKNavigation*)navigation { }
页面下载完毕之后,UIWebView 会直接载入视图并调用载入成功回调,而WKWebView 会发询问,确定下载的内容被允许之后再载入视图。
#pragma mark - UIWebViewDelegate
- ( void)webViewDidFinishLoad:( UIWebView*)webView {}
#pragma mark - WKNavigationDelegate
- ( void)webView:( WKWebView*)webView didFinishNavigation:( null_unspecifiedWKNavigation*)navigation { }
成功则调用成功回调,整个流程有错误发生都会发出错误回调。
#pragma mark - UIWebViewDelegate
- ( void)webView:( UIWebView*)webView didFailLoadWithError:( NSError*)error {}
#pragma mark - WKNavigationDelegate
- ( void)webView:( WKWebView*)webView didFailProvisionalNavigation:( null_unspecifiedWKNavigation*)navigation withError:( NSError*)error { }
- ( void)webView:( WKWebView*)webView didFailNavigation:( null_unspecifiedWKNavigation*)navigation withError:( NSError*)error {}
而除此之外,WKWebView 对比 UIWebView 有较大差异的地方有几点。
1、 WKWebView 多了一个重定向通知,在收到服务器重定向消息并且跳转询问允许之后,会回调重定向方法,这点是 UIWebView 没有的,在 UIWebView之上需要验证是否重定向,得在询问方法验证 head 信息。
#pragma mark - WKNavigationDelegate
- ( void)webView:( WKWebView*)webView
didReceiveServerRedirectForProvisionalNavigation:
( null_unspecifiedWKNavigation*)navigation { }
2、 因为 WKWebView 是跨进程的方案,当 WKWebView 进程退出时,会对主进程做一次方法回调。注:该方法是在 iOS 9 之后才出现,而我们最低支持版本是 iOS 8,所以还得考虑 iOS 8下WKWebView进程崩溃问题,另外该方法也不是很靠谱,不一定所有崩溃情况都会触发回调,具体的在后面的部分细说。
- ( void)webViewWebContentProcessDidTerminate:( WKWebView*)webView API_AVAILABLE(macosx( 10.11), ios( 9.0)) {}
3、 HTTPS 证书自定义处理
- ( void)webView:( WKWebView*)webView didReceiveAuthenticationChallenge:( NSURLAuthenticationChallenge*)challenge completionHandler:( void(^)( NSURLSessionAuthChallengeDispositiondisposition, NSURLCredential* _Nullable credential))completionHandler { }
注意:证书认证代理不一定百分百会回调,可能是 iOS 系统的 Bug,目前无解,只能不要太过依赖该回调逻辑。
4、 新增 WKUIDelegate 协议,该协议包含一些UI相关的内容。
在 UIWebView中,Alert、Confirm、Prompt 等视图是直接可执行的,但在WKWebView上,需要通过WKUIDelegate协议接收通知,然后通过 iOS 原生执行。
其次,WKWebView关闭时的回调通知也在WKUIDelegate协议中。注:该方法也是 iOS 9 才有。
另外,对于类似 ‘A’ 标签 ‘target=_blank’ 这种情况,会要求创建一个新的WKWebView 视图,这个消息的通知回调也在该协议中,不过针对 iOS 设备在当前一个视图中显示,该标签点击会没反应,所以在视图载入之后会清除掉所有的 _blank 标记
还有在 iOS 10 之后,新增了链接预览的支持,相关方法也在该协议中
协议相关的就是这些,相对来说还是比较简单的,用来做呈现控制是足够了,更进一步,就需要涉及到和 JS 端的交互问题了,交互就是 Native 通知 JS,JS 通知 Native,基于这个能力拟订具体的交互协议。
三、深入:JS 和 Native交互 Native 通知 JS
先来看 Native 通知 JS,这个完全依靠 WebView 提供的接口实现,WKWebView 提供的接口和 UIWebView 命名上较为类似,区别是 WKWebView 的这个接口是异步的,而 UIWebView 是同步接口
#pragma mark - UIWebView
NSString*title = [webView stringByEvaluatingJavaFromString: @"document.title"];
#pragma mark - WKWebView
[wkWebView evaluateJava: @"document.title"
completionHandler:^( id_Nullable ret, NSError* _Nullable error) {
NSString*title =
}]; JS通知Native
对比 Native 通知 JS,JS 通知 Native 就要复杂许多
JS 调用 Native
在 iOS 6 之前,UIWebView 是不支持共享对象的,Web 端需要通知 Native,需要通过修改 location.url,利用跳转询问协议来间接实现,通过定义 URL 元素组成来规范协议
在 iOS 7 之后新增了 JavaCore 库,内部有一个 JSContext 对象,可实现共享
而 WKWebView 上,Web 的 window 对象提供 WebKit 对象实现共享
而 WKWebView 绑定共享对象,是通过特定的构造方法实现,参考代码,通过指定 UserContentController 对象的 MessageHandler 经过 Configuration 参数构造时传入
WKUserContentController*userContent = [[ WKUserContentControlleralloc] init];
[userContent addMessageHandler: id& WKMessageHandler& name: @"MyNative"];
WKWebViewConfiguration*config = [[ WKWebViewConfigurationalloc] init];
config.userContentController = userC
WKWebView*webView = [[ WKWebViewalloc] initWithFrame: CGRectZeroconfiguration:config];
而 handler 对象需要实现指定协议,实现指定的协议方法,当 JS 端通过 window.webkit.messageHandlers 发送 Native 消息时,handler 对象的协议方法被调用,通过协议方法的相关参数传值
#pragma mark - WKMessageHandler
- ( void)userContentController:( WKUserContentController*)userContentController didReceiveMessage:( WKMessage*)message {} // Java
functioncallNative() {
window.webkit.messageHandlers.MyNative.postMessage( 'body');
至此,WKWebView 的呈现和交互就已经说完了,如果没有太高的要求,这些完全可以做简单的呈现交互操作,实现一个轻度页面。
但,我们的目标肯定不仅于此,于是,重点话题来了。
四、重点:已知问题和解决方案
WKWebView 是一个新组件,并且是采用跨进程方案,实现了比较好的性能和体验,那同样的,肯定会带来一些问题
在说问题之前,我们先看一下接入 WKWebView 之后的内存结构
接入内存结构
为什么 app 接入 WKWebView 之后,相对比 UIWebView 内存占用小那么多,是因为网页的载入和渲染这些耗内存和性能的过程都是由 WKWebView 进程去实现的,相对来说 app 仅占很小一部分内存,甚至因为 Web 进程内存的膨胀,触发 app 的内存警告,导致 app 内存占用还会下跌。
但 Web 进程也是会崩溃的,能致 UIWebView 内存爆掉的页面在 WKWebView 上也可能导致 Web 进程崩溃,只是这个上限值相对比起来会高很多,而且崩溃体现到 app 也没那么严重,具体结果可能就是白屏、载入失败之类等。
根据问题的特性,我们将之大体分为三类。首先是最关键的 Cookie 问题;其次是使用上的一些功能性问题,需要针对适配的问题;还有就是前端适配的页面问题。针对这三类问题我们一一说。
Cookie 问题
对于 Cookie 问题,如下图,这张图是正常的登录 Cookie 认证流程,用户发起登录请求,后台登录之后,对浏览器写入 Cookie,该 Cookie 会写入磁盘,在后续请求发起时会带上该 Cookie,后台通过验证该 Cookie 来认证身份,确定用户已登录
在 WKWebView 上,最大的问题就在于 Cookie 写入这里。 UIWebView 的Cookie是通过 NSHTTPCookieStorage 统一管理,服务器返回时写入,发起请求时读取,Web 和 Native 通过该对象能共享 Cookie
而在 WKWebView 上,NSHTTPCookieStorage 不再是一个必经的流程节点,虽然 WKWebView 同样会对该对象写入Cookie,但并不是实时的,而且针对不同的系统版本延迟还不一样,另外发起请求时也不会实时去读取 Cookie。 这就导致每次 app 每次重启 Cookie 都会丢失,无法做到会话和Native同步
针对这个问题,我们做了一些尝试。
既然 WKWebView 无法实时写入磁盘,那我们手动干涉这个过程,主动读取Cookie 写入磁盘,然后载入时再绑定 Cookie 是否可行?
整个操作的流程如图所示,在登录之后,获取服务器返回的 Cookie 值,持久化到本地,在下次 WebView 初始化时,读取本地的缓存值手动设置 Cookie
try方案一、标准流程
读取 Cookie 值写入 NSHttpCookieStorageWeb 的请求分三类:Location 跳转、AJAX 请求、资源载入对于 Locaiton 跳转,会走 Web 组件的 Navigation 代理流程,我们可以通过拦截相应回调方法- (void)webView:(WKWebView*)webView decidePolicyForNavigationResponse:(WKNavigationResponse*)navigationResponse decisionHandler:(void(^)(WKNavigationResponsePolicy))decisionHandler{NSHTTPURLResponse*httpResponse = (NSHTTPURLResponse*)navigationResponse.idcookies = [httpResponse.allHeaderFields objectForKey:@“Set-Cookie”];if(cookies) {// Cookie 写入 NSHttpCookieStorage}decisionHandler(WKNavigationResponsePolicyAllow);}而 AJAX 和资源载入请求不会走协议代理方法。前者因为 W3C 标准影响,无法通过 JS 去读取 Set-Cookie 的值,直接读取 SESSIONID 也因为HTTPOnly 问题无法读取;而后者更是直接的无法拦截。总的来说,只能获取 Location 跳转请求的 Cookie 信息,如果登录操作由 AJAX 实现,那无法实现。
读取 NSHttpCookieStorage 写入 Request而对 Request 的 Cookie 写入也分两部分,一个是当前 Request,二个是子元素的 Request当前 Request 可以通过设置 Request 对象的 Header 去绑定 Cookie,但这个值只在当前请求中有效NSURL*url = [NSURLURLWithString:@""];NSMutableURLRequest*request = [NSMutableURLRequestrequestWithURL:url];[request addValue:@"key0=value0"forHTTPHeaderField:@"Cookie"];[wkWebView loadRequest:request];注意:Request 信息是通过 IPC 进程通信传递给 WKWebView,因为HTTPBody 和 HTTPBodyStream 信息可能比较大,在传递过程中被舍弃了,也就说发起请求的 Request 不能设置 body 值request 如果页面包含多 Frame ,出现 302 重定向时,Cookie 无法跨域设置,针对 MainFrame 还可以通过 Delegate 的请求询问方法中手动载入, 但非MainFrame 就没办法了而子资源请求的 Cookie 问题,同样的因为 W3C 限制,JS 无法对 Cookie和标记为 HTTPOnly 的值进行写入,子资源无法设置 Cookie
方案一总结:通过 WKWebView 提供的标准接口来实现 Cookie 同步,无论是 Request 还是 Response 都有很大的限制,无法实际去运用。
方案二、私有方法
我们知道可以通过注册 NSURLProtocol 来代理全局的 HTTP 和 HTTPS 请求,在 UIWebView 中,通过该方案能拦截到所有的请求,包含 Location、AJAX、资源载入等,而 WKWebView 的载入是在单独进程中实现,默认的请求是不走该协议的,那么有没有办法让它遵循该协议呢? 答案是可以,通过私有 API
WKWebView 包含一个 browsingContextController 属性对象,该对象提供了 registerSchemeForCustomProtocol 和 unregisterSchemeForCustomProtocol 两个方法,能通过注册 scheme 来代理同类请求,符合注册 scheme 类型的请求会走 NSURLProtocol 协议
但毕竟是私有 API,存在被拒的风险,就算通过一定手段避开了苹果的审查,私有 API 在后续 iOS 的升级中也随时可能被废弃,存在一定的风险
总结来说,在 WKWebView Cookie 无法完美共享的前提下,登录会话无法通过依赖 Cookie 来实现
新方案:OAuth2
抛弃对 Cookie 的依赖,可选的方案就比较有限了,比如 OAuth2,OAuth2 授权认证系统能很好的解决身份认证问题,并且支持多点,而且成熟
如图,Web 第一次发起请求肯定是未授权状态,服务端验证失败,返回重定向登录,WKWebView 通过监听指定 URL (如这里的重定向地址),调用 app 内置的 OAuth2 认证服务,提示用户手动授权,app 得到授权后向第三方 HJ 认证服务器获取认证,得到认证 token,序列化到本地,同时写入 WKWebView Cookie,信息部署完毕之后,WKWebView 带上认证 token 重新发起请求,服务器通过认证服务器验证通过,返回正常服务
针对现有的问题和背景,在不改变现有结构的情况下接入 WKWebView 是不可能的,而以 OAuth2 方案来执行的话,需要各客户端实现认证授权系统,服务端新增认证服务中心,web 端服务得支持授权验证
针对 Cookie 的问题就到这里,Cookie 问题确实是 WKWebView 最头疼的问题,对全局架构的影响也是大家选择它时重点考评的点
功能性问题
除去 Cookie 问题之外,其它零零碎碎也比较多,但都还算好,遵循相关的规范都能处理掉
这里我列出了收集的一些其它比较容易遇到的问题:
1、WKWebView 进程崩溃引发的问题
WKWebView 进程崩溃,在 app 内的效果就是白屏,我们要做的就是在得知白屏时重新载入 Request,iOS 9 下有 Delegate 方法能收到崩溃的回调,但在打开相册或拍照比较耗内存的情况下,WKWebView 崩溃 Delegate 方法却不会被调用,同时我们支持的最低版本是 iOS 8,而在 iOS 8 下,可以通过校验webView.title 属性是否为空来确定,title 属性是 WKWebView 内置属性,自动读取 document.title 值,而在进程崩溃的情况下,该值为空
2、WKWebView 视图尺寸变化对页面的影响
WKWebView 也是通过 ScrollView 实现,设置 contentInset 等相关偏移值会映射到 Web 页面,导致页面的长度增加
其次 WKWebView 的页面渲染与 JS 执行同步进行的,可能你 JS 执行时布局渲染并未完成,所以不管是 JS 还是 Native,在页面载入完成之后就获取innerHeight 或者 contentSize 都是不准确的,要么通过延迟获取,要么监听属性值变化,实时修正获取的值
3、默认的跳转行为,打开 iTuns、tel、mail、open 等
在 UIWebView 上,如果超链接设置未 tel://00-0000 之类的值,点击会直接拨打电话,但在 WKWebView 上,该点击没有反应,类似的都被屏蔽了,通过打开浏览器跳转 AppStore 已然无法实现
这类情况只能在跳转询问中处理,校验 scheme 值通过 UIApplication 外部打开
4、 下载链接无法处理
下载链接在 UIWebView 上其实也是需要特殊处理,在服务器响应询问中校验流类型即可
5、跨域问题
HTTPS 对 HTTPS、HTTP 对 HTTP 跨域默认是能载入的,但如果是 HTTP 想载入 HTTPS 跨域链接,因为安全考虑,WKWebView 会被拦截,这问题在引入跨域 HTTPS 的页面也做 HTTPS。我们 HJ 已经切换了 HTTPS,所以不存在该问题
6、NSURLProtocol 问题
UIWebView 是通过 NSURLConneciton 处理的 HTTP 请求,而通过Conneciton 发出的请求都会遵循 NSURLProtocol 协议,通过这个特性,我们可以代理 Web 资源的下载,做统一的缓存管理或资源管理
但在 WKWebView 上这个不可行了,因为 WKWebView 的载入在单独进程中进行,数据载入 app 无法干涉
7、缓存问题
WKWebView 内部默认使用一套缓存机制,开发能控制的权限很有限,特别是在 iOS 8 下,根本没方式去操作,对于静态资源的更新,客户端经常出现读取缓存不更新的情况。
针对这个问题,如果仅仅是单个资源如此,并且其它缓存比较有用,那对该资源地址加时间戳避开缓存
如果全局都是如此,这需要手动的去清理缓存,iOS 9 之后,系统提供了缓存管理接口 WKWebsiteDataStore
// RemoveCache
NSSet*websiteTypes = [ NSSetsetWithArray:@[
WKWebsiteDataTypeDiskCache,
WKWebsiteDataTypeMemoryCache]];
NSDate*date = [ NSDatedateWithTimeIntervalSince1970: 0];
[[ WKWebsiteDataStoredefaultDataStore] removeDataOfTypes:websiteTypes
modifiedSince:date
completionHandler:^{
而 iOS 9 之前,就只能通过删除文件来解决了,WKWebView 的缓存数据会存储在 ~/Library/Caches/BundleID/WebKit/ 目录下,可通过删除该目录来实现清理缓存
8、其它问题
还有一些零碎的小问题,比如通过写入 NSUserDefaults 来统一修改UserAgent;第三方库可能修改 Delegate 引起问题等等就不一一例举了,通过上述的问题,主要想表明出现问题的解决思路,只要不断去尝试,这些都不是阻碍。
功能性的问题比较典型的大多在 iOS 更新中都会完善,相信随着最低支持版本的提高,问题会越来越少
最后,还有一些可能会对前端同学造成影响的因素,我这里列举了几条
1、页面退回上一页不会重新执行 脚本,也不会触发 reload 事件
这个是因为 WKWebView 的页面管理和缓存机制导致的
2、页面键盘弹出会触发 resize 事件
3、window.unload 只有刷新页面才会触发,退出或跳转到其它页都无法触发
根据这几条问题来看,新组件的适配主要集中在流程周期上,前端同学适配新组件过程中,可以针对周期的依赖做特殊测试
总结 & 结束
WKWebView 虽然很新,有许多问题需要去解决,但它有着新技术带来的种种诱惑,随着 iOS 系统版本的不断迭代升级,问题会越来越少,功能也会越来越多,而且有较多的一线团队已经做了切换,证明业务承载完全没问题。
我相信,它就像 HTTPS 一样,以后完全有可能成为 iOS 平台下主流浏览器。 谢谢。
责任编辑:
声明:本文由入驻搜狐号的作者撰写,除搜狐官方账号外,观点仅代表作者本人,不代表搜狐立场。
今日搜狐热点

我要回帖

更多关于 ios wkwebview 缓存 的文章

 

随机推荐