美文网首页
iOS 解决WKWebView中WKScriptMessageH

iOS 解决WKWebView中WKScriptMessageH

作者: 笑笑菜鸟 | 来源:发表于2021-03-26 17:24 被阅读0次

    使用WKWebView时一般会遇到原生与JS交互的问题。在JS调用原生时需要使用WKUserContentController类的addScriptMessageHandler: name:方法监听JS事件,但在添加该监听后页面退出时会发现控制器不走dealloc方法,内存不释放。

    #import <WebKit/WebKit.h>
    
    @property (nonatomic ,strong) WKWebView *webView;
    
    - (WKWebView *)webView {
        if (!_webView) {
            WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
            [config.userContentController addScriptMessageHandler:self name:@"doShare"];
            
            _webView = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame)) configuration:config];
            _webView.navigationDelegate = self;
            _webView.UIDelegate = self;
            _webView.allowsBackForwardNavigationGestures = YES;
        }
        return _webView;
    }
    

    内存不释放原因分析:

    userContentController持有了self ,userContentController 又被configuration持有,configuration被webView持有,然后webView作为self的一个私有变量被self持有,最终导致了self的循环引用。

    解决思路:

    通过分析得知控制器不走dealloc方法的原因为循环引用,那么就必须将一方改为弱引用或者直接去除引用。

    解决方式1:

    在页面出现时再添加监听,页面消失时移除监听。

    - (void)viewWillAppear:(BOOL)animated {
        [super viewWillAppear:animated];
        
        [_webView.configuration.userContentController addScriptMessageHandler:self name:@"doShare"];
    }
    
    - (void)viewWillDisappear:(BOOL)animated {
        [super viewWillDisappear:animated];
        
        [_webView.configuration.userContentController removeScriptMessageHandlerForName:@"doShare"];
    }
    

    测试结果:成功,走dealloc方法,内存释放。
    但是个人觉得这并不是一个完美的解决方案。因为这种解决方式不仅在页面退出时会移除监听,在push进新的页面时监听也会被移除,而此时页面还在却无法及时监听到JS事件了。

    解决方式2:

    使用addScriptMessageHandler: name:方法是传入self弱引用对象。

    __weak typeof(self)weakSelf = self;
        [config.userContentController addScriptMessageHandler:weakSelf name:@"doShare"];
    

    测试结果:失败,不走dealloc方法,内存不释放。

    解决方式3:

    增加一个中间类去弱引用WKWebView,断开循环引用。

    WeakScriptMessageDelegate类代码如下:
    .h

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

    .m

    #import "WeakScriptMessageDelegate.h"
    
    @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];
    }
    
    
    - (void)dealloc {
        
    }
    @end
    

    WKWebView创建

    #import <WebKit/WebKit.h>
    
    @property (nonatomic ,strong) WKWebView *webView;
    
    - (WKWebView *)webView {
        if (!_webView) {
            //解决WKWebView与JS交互造成循环引用的问题
            WeakScriptMessageDelegate *weakScriptMessageDelegate = [[WeakScriptMessageDelegate alloc] initWithDelegate:self];
            
            WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
            [config.userContentController addScriptMessageHandler:weakScriptMessageDelegate name:@"doShare"];
    
            _webView = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame)) configuration:config];
            _webView.navigationDelegate = self;
            _webView.UIDelegate = self;
            _webView.allowsBackForwardNavigationGestures = YES;
        }
        return _webView;
    }
    - (void)dealloc {
        [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"doShare"];
    }
    

    测试结果:成功,走dealloc方法,内存释放。且控制器释放时自动解除监听。

    相关文章

      网友评论

          本文标题:iOS 解决WKWebView中WKScriptMessageH

          本文链接:https://www.haomeiwen.com/subject/joxshltx.html