WKWebView使用过程中遇到的坑

前言

在以前,一直以为Hybrid App开发是一种略显简单的事,不会使用太多能发挥移动端原生本身优势的复杂API,后来在新公司的工作(半混合式开发)过程中,发现混合式开发也是很多坑... 或者说WKWebView好多坑...

以下所说的内容,参考链接上基本上都有,本文的叙述方式主要是结合自己的经历(自己踩过的总结总是那么的深刻...[捂脸])
应该在开始混合开发之前就看下这篇文章的,结果真的是等自己踩坑踩了一遍,总结之后,发现这篇文章上都有....[大哭]
参考链接2: //www.greatytc.com/p/86d99192df68

目录

  1. 加载URL的 encode问题
  2. loadRequest造成的body数据丢失
  3. 使用WKUserContentController造成的内存泄漏问题
  4. WKWebView的白屏问题(拍照引起)
  5. NSURLProtocol(做网页缓存)
  6. WKWebView的截屏问题(做意见反馈)
  7. window.alert()引起的crash问题(暂时没遇到)
  8. WKWebView拦截协议
  9. User-Agent修改
  10. UI细节问题
    . wkwebview中 h5绝对布局不生效
    . iOS 12中WKWebView中表单 键盘弹起自动上移,导致的兼容问题
    . WKWebview会下移20
    . 页面滚动速率
    . 视频自动播放
    . goBack API问题
    · didFinishNavigation迟迟不调用
  11. iOS 11系统上,WKWebView内H5标签不可点击,Native不受影响

1. 加载URL的 encode问题

在数据网络请求或其他情况下,需要把URL中的一些特殊字符转换成UTF-8编码,比如:中文。解决无法加载的问题

编码:

iOS 9以前
stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding
ios9后对其方法进行了修改
stringByAddingPercentEncodingWithAllowedCharacters: [NSCharacterSet URLQueryAllowedCharacterSet]

解码

iOS 9以前
stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding
iOS 9以后
stringByRemovingPercentEncoding

总结:混合开发中,最好将所有的URL的编解码问题都交给前端或者后端来做,毕竟移动端发版太笨重了,最起码保证iOS与Android两端的处理一致,否则前端同学做处理就太麻烦了

2. loadRequest造成的body数据丢失

在 WKWebView 上通过 loadRequest 发起的 post 请求 body 数据会丢失:

//同样是由于进程间通信性能问题,HTTPBody字段被丢弃[request setHTTPMethod:@"POST"];
[request setHTTPBody:[@"bodyData" dataUsingEncoding:NSUTF8StringEncoding]];
[wkwebview loadRequest: request];

解决方案:见参考链接,目前暂无使用场景

3. 使用WKUserContentController造成的内存泄漏问题

  self -> webView -> WKWebViewConfiguration -> WKUserContentController -> self (addScriptMessageHandler)

__weak typeof(self) copy_self = self;
addScriptMessageHandler: copy_self  //不能解决问题

解决方案:
  单独创建一个类实现`WKScriptMessageHandler`协议,然后在该类中再创建一个协议,由self来实现协议
  即: `self -> webView -> WKWebViewConfiguration -> WKUserContentController -> weak delegate obj --delegate--> self `

示例代码:
 1.创建一个新类WeakScriptMessageDelegate

  #import <Foundation/Foundation.h>
  #import <WebKit/WebKit.h>
  @interface WeakScriptMessageDelegate : NSObject
    @property (nonatomic, weak) id<WKScriptMessageHandler> scriptDelegate;
    - (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate;
  @end

  @implementation WeakScriptMessageDelegate

  - (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate {
      self = [super init];
      if (self) {
        _scriptDelegate = scriptDelegate;
      }
      return self;
  }

  - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
      [self.scriptDelegate userContentController:userContentController didReceiveScriptMessage:message];
  }

  @end

  2.在我们使用WKWebView的控制器中引入我们创建的那个类,将注入js对象的代码改为:
  [config.userContentController addScriptMessageHandler:[[WeakScriptMessageDelegate alloc] initWithDelegate:self] name:scriptMessage];

  3.在delloc方法中通过下面的方式移除注入的js对象
  [self.config.userContentController removeScriptMessageHandlerForName:scriptMessage];
  上面三步就可以解决控制器不能被释放的问题了

4. WKWebView的白屏问题(拍照引起)

WKWebView 自诩拥有更快的加载速度,更低的内存占用,但实际上 WKWebView 是一个多进程组件,Network Loading 以及 UI Rendering 在其它进程中执行。
换WKWebView加载网页后,App 进程内存消耗反而大幅下降,但是仔细观察会发现,Other Process 的内存占用会增加。在一些用 webGL 渲染的复杂页面,使用 WKWebView 总体的内存占用(App Process Memory + Other Process Memory)不见得比 UIWebView 少很多。

在 UIWebView 上当内存占用太大的时候,App Process 会 crash;
而在 WKWebView 上当总体的内存占用比较大的时候,WebContent Process 会 crash,从而出现白屏现象

# 解决方案:
  1. 借助 iOS 9以后 WKNavigtionDelegate 新增了一个回调函数:
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView API_AVAILABLE(macosx(10.11), ios(9.0));

当 WKWebView 总体内存占用过大,页面即将白屏的时候,系统会调用上面的回调函数,我们在该函数里执行[webView reload](这个时候 webView.URL 取值尚不为 nil)解决白屏问题。在一些高内存消耗的页面可能会频繁刷新当前页面,H5侧也要做相应的适配操作。

  1. 检测 webView.title 是否为空
    并不是所有H5页面白屏的时候都会调用上面的回调函数,比如,最近遇到在一个高内存消耗的意见反馈H5页面上 present 系统相机,拍照完毕后返回原来页面的时候出现白屏现象(拍照过程消耗了大量内存,导致内存紧张,WebContent Process 被系统挂起),但上面的回调函数并没有被调用。在WKWebView白屏的时候,另一种现象是 webView.titile 会被置空, 因此,可以在 viewWillAppear 的时候检测 webView.title 是否为空来 reload 页面。

注意:可能有的前端页面确实没写title标签,在前端移动端开发中是可能会有这种场景的,会造成页面反复刷新

综合以上两种方法可以解决绝大多数的白屏问题。

5. NSURLProtocol(做网页缓存)

WKWebView中NSURLProtocol的使用以及对H5的缓存,这是利用NSURLProtocol做网页缓存以及带来的隐患。

6. WKWebView的截屏问题(做意见反馈)

WKWebView 下通过 -[CALayer renderInContext:]实现截屏的方式失效,需要通过以下方式实现截屏功能:

@implementation UIView (ImageSnapshot) 
- (UIImage*)imageSnapshot { 
    UIGraphicsBeginImageContextWithOptions(self.bounds.size,YES,self.contentScaleFactor); 
    [self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES]; 
    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 
    return newImage; 
} 
@end

然而这种方式依然解决不了 webGL 页面的截屏问题,Safari 以及 Chrome 这两个全量切换到 WKWebView 的浏览器也存在同样的问题:对webGL 页面的截屏结果不是空白就是纯黑图片

7. window.alert()引起的crash问题(暂时没遇到)

8. WKWebView拦截协议

WKWebView内默认不允许iTunes、weixin等协议跳转
UIWebView打开ituns.apple.com、跳转到appStore,、拨打电话,、唤起邮箱等一系列操作UIWebView 自己处理不了会自动交给UIApplication 来处理。

WKWebView上述事件WKWebView 不会自动交给UIApplication 来处理,除此之外,js端通过window.open() 打开新的网页的动作也被禁掉了

9. User-Agent修改

不要擅自修改webView的User-Agent,务必要跟前端反复确认,是否有用UA来做一些设备区分,进而做一些系统、机型适配问题。

10. UI细节问题

# 1. wkwebview中 h5绝对布局不生效
_baseWebView.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; (ios 11之后)`

然后:前端需要在meta标签中增加 **iPhoneX**的适配**---**适配方案**viewport-fit**:**cover**
# 2. iOS 12中WKWebView中表单 键盘弹起自动上移,导致的兼容问题

WKWebView会自动监听键盘弹出,并做上下移动处理(效果如同IQKeyboardManage这些库),但是在iOS12中会有一些问题,键盘收起后,控件不恢复原状,或者部分控件消失等不兼容问题
解决方案:

if(kSystemVersion < 12.0) {
    if (@available(iOS 11.0, *)) {
        _webview.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
    } 
}
if (@available(iOS 12.0, *)) {
     _webview.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentAutomatic;
}
# 3. WKWebview会下移20

解决方案:

VC.automaticallyAdjustsScrollViewInsets = NO;  //iOS11以及以后失效
需要使用_webview.scrollView.contentInsetAdjustmentBehavior
# 顺带解释一下以下两个属性

关于extendedLayoutIncludesOpaqueBarsautomaticallyAdjustsScrollViewInsets

  • 这两个属性属于UIViewController
  • 默认情况下extendedLayoutIncludesOpaqueBars = false 扩展布局不包含导航栏
  • 默认情况下automaticallyAdjustsScrollViewInsets = true 自动计算滚动视图的内容边距
  • 但是,当 导航栏 是 不透明时,而tabBar为透明的时候,为了正确显示tableView的全部内容,需要重新设置这两个属性的值,然后设置contentInset(参考代码).

在iOS11 中, UIViewController的automaticallyAdjustsScrollViewInsets属性已经不再使用,我们需要使用UIScrollView的 contentInsetAdjustmentBehavior属性来替代它.

UIScrollViewContentInsetAdjustmentBehavior 是一个枚举类型,值有以下几种:

  • automatic 和scrollableAxes一样,scrollView会自动计算和适应顶部和底部的内边距并且在scrollView 不可滚动时,也会设置内边距.
  • scrollableAxes 自动计算内边距.
  • never不计算内边距
  • always 根据safeAreaInsets 计算内边距一般我们肯定需要设置为 never,我们自己来控制间距,但是在iOS 12的webView中,就会出现开始所说的问题,需要设置为automatic才能解决

调整WKWebView布局方式,避免调整webView.scrollView.contentInset。实际上,即便在 UIWebView 上也不建议直接调整webView.scrollView.contentInset的值.

# 4. 页面滚动速率

WKWebView 需要通过 scrollView delegate 调整滚动速率:

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
 scrollView.decelerationRate = UIScrollViewDecelerationRateNormal;
}
# 5. 视频自动播放

WKWebView 需要通过WKWebViewConfiguration.mediaPlaybackRequiresUserAction设置是否允许自动播放,但一定要在 WKWebView 初始化之前设置,在 WKWebView 初始化之后设置无效。

# 6. goBack API问题

WKWebView 上调用 -[WKWebView goBack], 回退到上一个页面后不会触发window.onload()函数、不会执行JS。

# 7. didFinishNavigation迟迟不调用

明明看起来页面加载完全,却不调用(一般只发生在第一次进入该页面)。
解决方法:经过自定义NSURLProtocol,拦截所有的H5加载资源,并在didCompleteWithError中打印资源的加载情况,发现有图片资源,域名有问题
Error Domain=NSURLErrorDomain Code=-1003 "未能找到使用指定主机名的服务器。
DNS解析失败导致系统认定H5一直没加载完成,第二次再进入,系统缓存了DNS解析的映射记录,所以很快就认定资源错误,调用了didFinish方法。

11. iOS 11系统上,WKWebView内H5标签不可点击,Native不受影响

在频繁的切换页面、刷新WKWebView的情况下,会出现WKWebView卡死,所有的H5标签不可点击,Native的UI不受影响,TabBarVC的几个子控制器最为严重,有时候切换、刷新四五次左右,就会出现这种情况。

更新:结论:在viewWillAppear方法中调用了evaluateJavaScript: completionHandler:方法,将该方法的调用移到viewDidAppear方法中即可。

下面是探索的一些步骤,也走了一些弯路,可绕过

分别从内存、视图、网络请求几个方面入手,按照以下步骤定位问题:
1.对APP进行内存泄漏检测,优化了几处代码。毫无用处
2.WKWebView单独进程内存问题?因为有一些二级页面按照问题出现流程复现了N多次,都没有出现,所以暂时先排除
3.网速问题。发现网速差时,确实很容易复现,网速好的时候,试了好几次没复现!做了一些网络优化,比如及时cancel掉一些不需要的请求,没有效果。
4.视图加载、更新问题。**猜测依据:一级页面更容易复现,且比二级页面多了一个Tabbar的视图。
结论:结合第3、4,猜测是网络过慢时,tabbar出现、隐藏,及WKWebView刷新、加载、渲染HTML,几种情况结合导致的WKWebView布局混乱。
最后解决方法:包含WKWebView的一级页面,`viewDidAppear`时重新设置了一下WKWebView的约束。(设置UIScrollViewContentInsetAdjustmentAutomatic = YES,没有效果)
效果:大大改善了,但却没有根治问题。加了个保底方案,下拉刷新时,销毁旧WKWebView,创建新的,并loadRequest。(因为这些情况下iOS 11上出现的,且没有更低版本的测试机复现,所以暂时把修改限制在了iOS 11及以下的系统)

最后:有个最省事的方案,针对这些页面,将WKWebView替换成UIWebView。 可行,但逃避问题,不太可取,而且UIWebView、WKWebView各有一些特性,另一个不支持,比如WKWebView支持html,滚动时实时回调,而UIWebView只支持滚动停止时回调。且苹果已经不太支持UIWebView。还是早点拥抱WKWebView吧。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,123评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,031评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,723评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,357评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,412评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,760评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,904评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,672评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,118评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,456评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,599评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,264评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,857评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,731评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,956评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,286评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,465评论 2 348

推荐阅读更多精彩内容

  • 导语 WKWebView 是苹果在 WWDC 2014 上推出的新一代 webView 组件,用以替代 UIKit...
    Jecky丶阅读 8,380评论 2 22
  • 1、WKWebView 白屏问题WKWebView 自诩拥有更快的加载速度,更低的内存占用,但实际上 WKWebV...
    iosRn阅读 2,096评论 1 10
  • 1、WKWebView 白屏问题WKWebView 自诩拥有更快的加载速度,更低的内存占用,但实际上 WKWebV...
    无名感恩阅读 2,135评论 0 3
  • 转载:http://www.cnblogs.com/NSong/p/6489802.html 导语 WKWebVi...
    李小威阅读 4,852评论 8 9
  • WKWebView 是苹果在 WWDC 2014 上推出的新一代 webView 组件,用以替代 UIKit 中笨...
    Aiana阅读 4,569评论 1 8