1. 程式人生 > >iOS11.3 WKWebView清除cookie所踩的坑!

iOS11.3 WKWebView清除cookie所踩的坑!

我們在iOS11.3上踩了一個大坑!這個坑表現在線上的版本只要使用者升級到iOS11.3且退出登入,或者登入態過期,都會閃退。因為iOS11.3支援了兩個超級一線城市的公交卡,引發了使用者短時間集中更新。為了解決這個問題,整個團隊發一個小版本來降級這個問題的影響。

問題的表現:

前面說過,只要退出登入,App就會閃退。這是因為我們在退出登入時清除WKWebView的cookie時引發了崩潰。

問題的原因:

蘋果應該在iOS11.3上修改了nonPersistentDataStore建立的DataStore的實現。

問題覆盤:

我們先回歸一下WKWebView下cookie的前世今生。cookie本質上是h5用來儲存登入、使用者名稱、以及一些特定時間內有效的資訊的機制。這個東西有幾個顯而易見的好處:

1、本地化的儲存一些資訊,可以減少h5請求的次數。提升h5的效能,降低服務端壓力;

2、cookie作為h5請求request的一部分,會把一些客戶端的固定資訊直接傳給服務端,避免h5因為某些資訊又需要傳送網路請求;

3、cookie是域名隔離的,有一定的安全性;

正因為有這麼多的好處,所以,很多時候h5大量的依賴了cookie機制。甚至用它儲存了一些敏感資訊。這些資訊的洩露會對使用者的安全造成重大威脅。所以蘋果在iOS8引入WKWebView時,沒有給原生暴露任何操控cookie的API(事實上,不僅cookie,其他任何和快取、持久化相關的介面都沒有)。我的理解是:蘋果有意識將cookie對開發者進行了遮蔽,就是不希望原生開發者對cookie進行干預。而cookie的安全性完全由h5來保證。講道理這麼做無可厚非。但是有個東西很可怕----那就是使用者習慣。在原來老的UIWebView下,以及其他的瀏覽器中熟悉了各種cookie操作的開發者肯定不會就此罷休。各種攜帶cookie的“黑”操作層出不窮。所以,從iOS9開始,蘋果暴露了WKWebView資料儲存的類----

WKWebsiteDataStore。顧名思義,這個類暴露了一些獲取(清除)特定快取的能力,這裡包括了cookie。下面稍微介紹一下這些能力

+ (NSSet<NSString *> *)allWebsiteDataTypes;

可以獲取dataStore中所有的資料型別。這裡有:

    WKWebsiteDataTypeDiskCache,//硬碟快取
    WKWebsiteDataTypeOfflineWebApplicationCache,//離線應用快取
    WKWebsiteDataTypeMemoryCache,//記憶體快取
    WKWebsiteDataTypeLocalStorage,//localStorage,cookie的一個兄弟
    WKWebsiteDataTypeCookies,//cookie
    WKWebsiteDataTypeSessionStorage,//session
    WKWebsiteDataTypeIndexedDBDatabases,//索引資料庫
    WKWebsiteDataTypeWebSQLDatabases//資料庫

這裡可以看出,與h5相關的快取都暴露給了原生。

-(void)fetchDataRecordsOfTypes:(NSSet<NSString*>*)dataTypes completionHandler:(void(^)(NSArray<WKWebsiteDataRecord *> *))completionHandler;
獲取某些指定的資料型別。最後資料例項用一個統一的抽象的WKWebsiteDataRecord來表示。
-(void)removeDataOfTypes:(NSSet<NSString*>*)dataTypes forDataRecords:(NSArray<WKWebsiteDataRecord *> *)dataRecords completionHandler:(void (^)(void))completionHandler;

移除某些特定的資料型別。

- (void)removeDataOfTypes:(NSSet<NSString*> *)websiteDataTypes modifiedSince:(NSDate *)date completionHandler:(void (^)(void))completionHandler;

移除指定時期的特定的資料型別。

從以上可以看出,蘋果暴露了各種快取的獲取方法和移除方法。但是沒有給設定方法。而且cookie並不突出。和其他兄弟一樣。所以蘋果的本意還是不希望原生直接干預cookie的設定。

但是從iOS11開始,一切都變了。蘋果徹底放開了cookie的操作許可權。它在WKWebsiteDataStore中暴露了一個

WKHTTPCookieStore型別的屬性。專門用來管理cookie。cookie搖身一變,從嬪妃變成了皇后。位置特殊了。通過這個屬性,原生可以自由的移除cookie和設定cookie了(是不是和以前的NSHttpCookieStorage一樣了?)。

這種設計帶來了一個問題?現在在iOS8、9、10、11都存在的情況下,我們如何清除cookie。iOS8沒有暴露介面,使用者量也不大了,我們不做考慮。iOS9,10只有一種方式。iOS11有兩種(注意蘋果暴露了WKHTTPCookieStore的屬性來操作cookie,但是老的API並沒有廢棄,哪怕是和cookie相關的那部分也沒有廢棄)。我想看到這個問題,腦子比較正常的人都會想:

iOS11採用新的API就行了啊。

但總有腦子不正常的人,比如我。我原本是想這麼幹的。但是後來一想,老的API沒有廢棄,那就肯定可以用,那我繼續用它唄。但是有個問題,iOS11既然暴露了新的介面,這是不是意味著老的API可能清除cookie會失敗呢?或者後續哪個版本萬一失敗呢?所以,我用了一種比較“保險”的方案。那就是先用老的API去清除,然後用新的API去校驗。虛擬碼可以這麼來看:

old api fetch cookie:
finish{
   old api remove cookie:
   finish{
        new api get cookie:
        finish{
           if cookie still exist
              new api clear cookie
        }
   }
}

邏輯上沒有毛病!!!我到目前為止仍然認為邏輯上沒有毛病。

下面開始清除。在清除的時候我們發現WKWebsiteDataStore有兩個類方法:

/* @abstract Returns the default data store. */
+ (WKWebsiteDataStore *)defaultDataStore;

/** @abstract Returns a new non-persistent data store.
 @discussion If a WKWebView is associated with a non-persistent data store, no data will
 be written to the file system. This is useful for implementing "private browsing" in a web view.
*/
+ (WKWebsiteDataStore *)nonPersistentDataStore;

字面意思很清楚,第二個是非持久的dataStore, 那第一個就是持久的。我的做法是分別去清除這兩類dataStore中的cookie。需求做完沒有毛病,一直很健康,退出登入時cookie被清除的寸草不生。我暗自欣慰。

但是iOS11.3推出後,登陸的同事反饋,閃退。瞎了我的鈦合金狗眼。為啥,再經歷了mac系統升級、xcode升級、手機作業系統升級等一系列變態操作後,真相來了:

我們上述方法在清除nonPersistentDataStore時當執行到用iOS11的API去校驗時就掛了。崩潰的棧顯示WKWebsiteDataStore正在析構。WTF!!!!

問題的原因大概就清晰了:

defaultDataStore不掛,原因是它類似於單例,程式碼執行過程中不會析構!

nonPersistentDataStore 以前不掛,現在開始掛,說明以前蘋果對它的實現也是單例,而現在它應該不是單例了。我們建立它的例項是在函式內部,當出了方法作用域後它就會析構了。執行iOS11 API檢驗時它正在析構,向一個正在析構的物件發訊息它是會掛的。

現在我們回頭來看nonPersistentDataStore的說明:

 @abstract Returns a new non-persistent data store.
 @discussion If a WKWebView is associated with a non-persistent data store, no data will
 be written to the file system. This is useful for implementing "private browsing" in a web view.

和前面持久化的dataStore不同的是,nonPersistentDataStore用於實現私密的瀏覽器,即該瀏覽器的資料與其他WebView不共享。蘋果本質的意願應該是一個WKWebView和一個nonPersistentDataStore的繫結。以前的策略應該是多個WKWebView可以和一個non-persistent的datastore繫結。只要它和普通的datastore隔離即可。(當然,以上都是通過現象的推測。如果有人有確定說明,歡迎指正)

至此,這個坑介紹完畢!我們來總結一下這裡我們的失誤:

第一、對nonPersistentDataStore缺少比較全面的理解,如果理解了它的用途,其實可以判定當前我們的App是沒有使用場景的;

第二、iOS11和iOS9、10的API最好不要巢狀使用。其實我們當時做的時候就發現老的API的效果是ok的。只不過不放心,用一種莫須有的心態增加了一個邏輯。其實這個邏輯即使有必要,也要經過驗證,證明老的API確實無法完成再去完善,畢竟cookie即使清除不了,也不是天塌下來的事。後續完善即可。這種前期畫蛇添足的思維方式還是要多改變!!!

完!

相關推薦

iOS11.3 WKWebView清除cookie

我們在iOS11.3上踩了一個大坑!這個坑表現在線上的版本只要使用者升級到iOS11.3且退出登入,或者登入態過期,都會閃退。因為iOS11.3支援了兩個超級一線城市的公交卡,引發了使用者短時間集中更新。為了解決這個問題,整個團隊發一個小版本來降級這個問題的影響。問題的表現:

python 3.6.1 安裝scrapy之旅

ext href sta 版本 deb targe IE src pyw 系統環境:win10 64位系統安裝 python基礎環境配置不做過多的介紹 window環境安裝scrapy需要依賴pywin32,下載對應python版本的exe文件執行安裝,下載的pywin

WKWebView 使用的一些記錄

// WKwebVeiew  不能呼叫系統的長按複製  處理方法 // 選擇CSS NSString *css = @"body{-webkit-user-select:auto;-webk

聚合sdk 打包

閒來許久 總結一下在聚合sdk打包過程中所遇到的問題: 報錯1:Caused by: brut.androlib.AndrolibException: brut.common.BrutException: could not exec (exit code =

Egret 生成 自帶EUI 的微信小遊戲

end custom 點擊 ati gre faq commonjs require IE 1. 首先,再次被網上一大堆屎一樣的資料搞得浪費了我一天時間。各種坑。 2. 本文先講一種正確的方式,然後再列舉坑。 去www.egret.com下載最新的引擎,我的最新版

github webhook 實現代碼自動部署

添加 sudoers lin http 必須 ebs spa 踩坑 bsp 踩坑:   1、php程序執行linux命令是以webserver的user用戶(如apache 、www……)操作的,需要在/etc/sudoers添加用戶免密碼操作權限;   2、以we

IOS應用內支付IAP從零開始詳解,讓你少

前言 什麼是IAP,即in-app-purchase 這幾天一直在搞ios的應用內購,查了很多部落格,發現幾乎沒有一篇部落格可以完整的概括出所有的點,為了防止大夥多次查閱資料,所以寫了這一篇部落格,希望大家能夠跟著我,從零開始,寫一個包含內購的應用出來 流程 一般有以下幾種

升級PHP7~~~

之前就聽說php7這個版本有很大的提升,終於公司的專案也要升級到PHP7了。 升級之前看了一下大家整理好的一些介紹,發現這個版本是從底層開始就有很大的更改,當然,效率也提升了很多。 除了一些新增的功能(這個大家都已經寫的很全了,寫一些我沒看到的,隨著專案的踩坑慢

【springMVC靜態資源無法訪問】靜態資源訪問

<!DOCTYPE html> <html> <head> <meta charset=utf-8> <meta name=viewport content="width=device-width,maximum-scale=1,

android端整合微信第三方登入

本篇記錄 app 端獲取到微信 code 的過程。用 code 獲取 access_token 的過程是後臺伺服器完成的。(當然也可以由 app 端自己去拿 code 換取 access_token,這

微信被動回覆訊息失敗有的Java篇【避指南】

背景: 隨便一個微信訂閱號都可以,使用者在訂閱號傳送訊息,然後我們自己的伺服器做出訊息回覆,之間的過程處理好多坑。 我這裡是從接入成功後開始踩到的坑,關於接入的沒什麼,微信公眾號文件很清楚。 開始了: 我的伺服器使用的ssm框架 1.坑列表: 獲取微信請求我方伺服

前端小白學習安裝node npm vue webpack

1.package.json 依賴包不全的時候 npm install 重新裝一下就可以了。 2.npm run dev 一定要在專案目錄下執行 否則會提示找不到package json。 3.mac使用者一定要記得命令前加sudo。

提交程式碼前沒有用svn st命令(只用了svn diff), 差點

       我還是建議大家在Windows上通過對比工具來提交程式, Windows上一切可見, 一目瞭然啊。 檔案狀態用顏色區分得一清二楚。        當然, 有的時候, 我們也可以在linux下提交程式。 最近我直接在linux上寫了個程式碼demo,  提交前,

爬蟲“學前班”,記住這些不

摘要:爬蟲就是模擬人的訪問操作來獲取網頁/App資料的一種程式。 爬蟲是什麼? 簡單的說爬蟲就是模擬人的訪問操作來獲取網頁/App資料的一種程式。我們可以把網際網路比作一張大網,而爬蟲(即網路爬蟲)便是在網上爬行的蜘蛛。把網的節點比作一個個網頁,爬蟲爬到這就相當於訪問了該頁面,獲取了其資訊。可以把節點間的連線

android studio 3.1 升級gradle4.4時到的

轉載自:https://blog.csdn.net/Public_x/article/details/80224838   公司原專案是使用Android studio 2.3編譯的,最近將Android studio升級到3.1後,build apk 時提示: The pro

在ubuntu 14.04上LIFT: Learned Invariant Feature Points 環境配置過的流過的淚(3

1.重灌nvidia 顯示卡驅動 2.重灌cuda8.0和cudnn 3。重新測試 看來執行不能用sudo 最後也沒管 2. theano nvcc compiler not found on $PATH 重新配置檔案 解決方案:重灌了一遍cuda 和c

symfony3 使用命令行工具生成Entity實體

rsh 分享 entity date symfony 命令 pan 連接郵箱 ner 1.把配置文件匯總連接郵箱的配置信息註釋掉了,在創建Entity時php bin/console doctrine:generate:entity報錯 2. 錯誤原因是實體文件映射到數

近半年數據分析工作的總結----或者說的總結

發生 森林 分層 交叉測試 要求 但是 應用 而且 維數 1. 算法(數學)原理重要不重要? 不重要。因為不懂數學,你也可以把數據扔進Sas,選擇一個名字看起來有逼格的算法,然後CPU煎個雞蛋,結果就出來了。還能配上不明覺厲的圖形化結果。更有逼格的,網上搜一下‘R/

給大家聊一聊雲收藏從 Spring Boot 1.0 升級到 2.0

springboot 雲收藏 先給大家曬一下雲收藏的幾個數據,作為一個 Spring Boot 的開源項目(https://github.com/cloudfavorites/favorites-web)目前在 Github 上面已經有1600多個 Star,如果按照 SpringBoot 標簽進行篩

配置taBar遇見的問題(之路)

分享圖片 type http 效果圖 navi src 之路 com nbsp 目前效果圖: 問題:我遇見一個問題,點擊每周關註的時候,他應該跳轉到哪一個頁面。在沒有設置taBar還是可以跳轉的。 解決方法是: 修改 open-type=‘navig