WKWebView中MessageHandler的内存泄漏问题解决过程

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WKWebView中MessageHandler的内存泄漏问题解决过程相关的知识,希望对你有一定的参考价值。

  背景
  
  项目中使用了WKWebView替换了之前的UIWebView,牵扯到Hybird开发,我们需要和H5交互,所以用到了WKWebViewConfiguration 中的 WKUserContentController
  
  所以初始化代码如下
  
  WKUserContentController *userContentController = [[WKUserContentController alloc] init];
  
  [userContentController addScriptMessageHandler:self name:GetKeyiosandroid_Action];
  
  [userContentController addScriptMessageHandler:self name:Upload_Action];
  
  // WKWebView的配置
  
  WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
  
  configuration.userContentController = userContentController;
  
  _webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration];
  
  _webView.navigationDelegate = self;
  
  _webView.UIDelegate = self;
  
  
  GetKeyiOSAndroid_Action Upload_Action 分别是H5通过message handler的方式来调用OC的两个方法。
  
  这时,就已经发生了隐患,因为
  
  [userContentController addScriptMessageHandler:self name:GetKeyiOSAndroid_Action];
  
  这里userContentController持有了self ,然后 userContentController 又被configuration持有,最终呗webview持有,然后webview是self的一个私有变量,所以self也持有self,所以,这个时候有循环引用的问题存在,导致界面被pop或者dismiss之后依然会存在内存中。不会被释放
  
  当然如果你只是静态界面,或者与H5的交互的内容仅限于本页面内的内容,其实只是单纯的内存泄漏,但是,如果此时和H5的交互方法中牵扯到全局变量,或者全局的一些内容,那么就不可控制了。
  
  我发现这个问题是因为我们web页面会监听token过期的和登录状态改变的通知,然后会刷新界面,并且重新发送请求,这一系列动作中会和用户的全局信息进行交互,所以在访问一个web页面后,切换账号登录时会发现有之前访问过的web页面请求发出,并且因为token不同报了token过期的错误,所以导致登录后误操作为token过期,紧接着被踢到登录界面。
  
  通过charles抓包发现,这些web页面都是在切换登录账号欠访问的所有界面,所以,锁定问题时web页面依旧存在,在切换登录后收到了登录状态改变的通知,重新刷新了界面导致请求发出并返回报错,进而出现登录后被踢出的bug。
  
  解决方案:
  
  既然是循环引用,那么必须破除一边的强引用,改为弱引用,或者直接去除引用。思路明朗了。。
  
  尝试1:
  
  id __weak weakSelf = self;
  
  WKUserContentController *userContentController = [[WKUserContentController alloc] init];
  
  [userContentController addScriptMessageHandler:weakSelf name:GetKeyiOSAndroid_Action];
  
  1
  
  2
  
  3
  
  思路效仿block , 结果失败
  
  尝试2:
  
  在viewWillDisappear / viewDidDisappear 生命周期方法中调用
  
  [_webView.configuration.userContentController www.yibaoyule1.com  removeAllUserScripts];
  
  1
  
  2
  
  这算一个脑抽的尝试,看文档说明就懂了。自行略过
  
  这里写图片描述
  
  尝试3:
  
  不在初始化时添加ScriptMessageHandler, 而是和Notificenter/KVC一个思路
  
  - (void)viewWillAppear:(BOOL)animated {
  
  [super viewWillAppear:animated];
  
  [_webView.configuration.userContentController addScriptMessageHandler:self name:GetKeyiOSAndroid_Action];
  
  [_webView.configuration.userContentController addScriptMessageHandler:self name:Upload_Action];
  
  }
  
  - (void)viewWillDisappear:(BOOL www.8555388.cn/ )animated {
  
  [super viewWillDisappear:animated];
  
  [_webView.configuration.userContentController removeScriptMessageHandlerForName:GetKeyiOSAndroid_Action];
  
  [_webView.configuration.userContentController www.471060.com  removeScriptMessageHandlerForName:Upload_Action];
  
  结果成功
  
  小结:
  
  之前在使用WKWebView的时候很多blog的内容都只是说了怎么添加Message Handler 但是并没有高速大家有这个内存泄漏的风险,如果你只是页面内的数据调用你压根都不会发现这个问题。
  
  此坑已填!






































































































以上是关于WKWebView中MessageHandler的内存泄漏问题解决过程的主要内容,如果未能解决你的问题,请参考以下文章

WKWebView与JS交互

webview部分手机无法加载iframe内容

H5与原生APP交互方式 (IOS及安卓)

一周技术文章汇总 - 20161021

NSQ vb.net MessageHandler

Symfony MessageHandler 计算消息被发送的次数