1. 程式人生 > >WKWebView中MessageHandler的記憶體洩漏問題解決過程

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];

思路效仿block , 結果失敗

嘗試2:

viewWillDisappear / viewDidDisappear 生命週期方法中呼叫

[_webView.configuration.userContentController removeAllUserScripts];

這算一個腦抽的嘗試,看文件說明就懂了。自行略過

這裡寫圖片描述

嘗試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)animated {
    [super viewWillDisappear:animated];

    [_webView.configuration.userContentController removeScriptMessageHandlerForName:GetKeyiOSAndroid_Action];
    [_webView.configuration.userContentController removeScriptMessageHandlerForName:Upload_Action];

}

結果成功

小結:

之前在使用WKWebView的時候很多blog的內容都只是說了怎麼新增Message Handler 但是並沒有告訴大家有這個記憶體洩漏的風險,如果你只是頁面內的資料呼叫你壓根都不會發現這個問題。

此坑已填!