KZWFoudation系列之WKWebView的封裝

在iOS 8.0以后蘋果推出WKWebView诚撵,之前有性能問題的UIWebView基本就被棄用了捧韵,這里整理下我的WKWebView之旅和怎么封裝的丝蹭。

1互亮、WKWebView有個繞不過去的問題就是Cookie.

我們先來看下Cookie到底是個什么東西:

簡單地說犁享,cookie 就是瀏覽器儲存在用戶電腦上的一小段文本文件。cookie 是純文本格式豹休,不包含任何可執(zhí)行的代碼炊昆。一個 Web 頁面或服務(wù)器告知瀏覽器按照一定規(guī)范來儲存這些信息,并在隨后的請求中將這些信息發(fā)送至服務(wù)器,Web 服務(wù)器就可以使用這些信息來識別不同的用戶凤巨。大多數(shù)需要登錄的網(wǎng)站在用戶驗證成功之后都會設(shè)置一個 cookie视乐,只要這個 cookie 存在并可以,用戶就可以自由瀏覽這個網(wǎng)站的任意頁面敢茁。再次說明佑淀,cookie 只包含數(shù)據(jù),就其本身而言并不有害彰檬。緊跟 cookie 值后面的每個選項都以分號和空格分開伸刃,每個選擇都指定了 cookie 在什么情況下應(yīng)該被發(fā)送至服務(wù)器。

第一個選項是過期時間(expires)逢倍,指定了 cookie 何時不會再被發(fā)送至服務(wù)器捧颅,隨后瀏覽器將刪除該 cookie。該選項的值是一個 Wdy, DD-Mon-YYYY HH:MM:SS GMT 日期格式的值较雕。下一個選項是 domain碉哑,指定了 cookie 將要被發(fā)送至哪個或哪些域中。默認(rèn)情況下郎笆,domain會被設(shè)置為創(chuàng)建該 cookie 的頁面所在的域名谭梗,所以當(dāng)給相同域名發(fā)送請求時該 cookie 會被發(fā)送至服務(wù)器。另一個控制 Cookie 消息頭發(fā)送時機(jī)的選項是 path 選項宛蚓,和 domain 選項類似,path選項指定了請求的資源 URL 中必須存在指定的路徑時设塔,才會發(fā)送Cookie 消息頭凄吏。

這個比較通常是將 path 選項的值與請求的 URL 從頭開始逐字符比較完成的。如果字符匹配闰蛔,則發(fā)送 Cookie 消息頭痕钢。最后一個選項是 secure。不像其它選項序六,該選項只是一個標(biāo)記而沒有值任连。只有當(dāng)一個請求通過 SSL 或 HTTPS 創(chuàng)建時,包含 secure 選項的 cookie 才能被發(fā)送至服務(wù)器例诀。這種 cookie 的內(nèi)容具有很高的價值随抠,如果以純文本形式傳遞很有可能被篡改。

UIWebView Cookie

同一個應(yīng)用繁涂,不同UIWebView之間的Cookie是自動同步的拱她。并且可以被其他網(wǎng)絡(luò)類訪問比如NSURLConnection,AFNetworking。

它們都是保存在NSHTTPCookieStorage容器中扔罪。 當(dāng)UIWebView加載一個URL的時候秉沼,在加載完成時候,Http Response,對Cookie進(jìn)行寫入,更新或者刪除唬复,結(jié)果更新Cookie到NSHTTPCookieStorage存儲容器中矗积。

WKWebView Cookie

NSURLCache和NSHTTPCookieStroage無法操作(WKWebView)WebCore進(jìn)程的緩存和Cookie。

WKWebView實例將會忽略任何的默認(rèn)網(wǎng)絡(luò)存儲器(NSURLCache, NSHTTPCookieStorage, NSCredentialStorage) 和一些標(biāo)準(zhǔn)的自定義網(wǎng)絡(luò)請求類(NSURLProtocol,等等.)敞咧。

WKWebView實例不會把Cookie存入到App標(biāo)準(zhǔn)的的Cookie容器(NSHTTPCookieStorage)中,因為 NSURLSession/NSURLConnection等網(wǎng)絡(luò)請求使用NSHTTPCookieStorage進(jìn)行訪問Cookie,所以不能訪問WKWebView的Cookie棘捣,現(xiàn)象就是WKWebView存了Cookie,其他的網(wǎng)絡(luò)類如NSURLSession/NSURLConnection卻看不到妄均。柱锹,

與Cookie相同的情況就是WKWebView的緩存,憑據(jù)等丰包。WKWebView都擁有自己的私有存儲,因此和標(biāo)準(zhǔn)Cocoa網(wǎng)絡(luò)類兼容的不是那么好禁熏。

你也不能自定義requests(增加自己的http header,更改已經(jīng)存在的header)使用自定義的 URL schemes等等邑彪,因為NSURLProtocol也是不支持WKWebView的瞧毙。
WKWebView Cookie 寫入

1、JS注入:
WKUserContentController* userContentController = WKUserContentController.new;
    WKUserScript * cookieScript = [[WKUserScript alloc]
                                   initWithSource:[NSString stringWithFormat:@"document.cookie = '%@'", [self setCurrentCookie]]
                                   injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
    [userContentController addUserScript:cookieScript];
- (NSString *)setCurrentCookie {
    return @"";
}
2寄症、NSMutableURLRequest 注入
- (void)loadURLRequest {
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:self.url];
    [request addValue:[self readCurrentCookie] forHTTPHeaderField:@"Cookie"];
    [self.webView loadRequest:request];
}
- (NSString *)setCurrentCookie {
    return @"";
}

劃重點:坑一:JS注入的Cookie宙彪,比如PHP代碼在Cookie容器中取是取不到的, javascript document.cookie能讀取到有巧,瀏覽器中也能看到释漆。

NSMutableURLRequest 注入的PHP等動態(tài)語言直接能從$_COOKIE對象中獲取到,但是js讀取不到篮迎,瀏覽器也看不到

所以合理的辦法讓js男图,php,瀏覽器都能讀取到相同的Cookie方法就是創(chuàng)建WebView的時候javascript注入Cookie甜橱,一開始發(fā)送NSMutableURLRequest請求的時候也要加上Cookie逊笆,并且保證兩個地方的設(shè)置的cookie一致。

坑二:WKWebView的cookie需要設(shè)置domain和path默認(rèn)情況下會帶進(jìn)去不是通用的岂傲。(今天剛發(fā)現(xiàn)的o)

坑三:網(wǎng)頁登錄跳原生之后登錄成功后dimis后你需要重新注入和刷新把cookie塞進(jìn)去难裆,所以你的viewWillAppear每次都需要重新加載WKWebView和重新loadRequest,簡直了镊掖。乃戈。。

KZWWebViewController 是如何做的呢堰乔?

我們知道偏化,app里經(jīng)常跳各種網(wǎng)頁,我們不可能每個網(wǎng)頁都去單獨處理镐侯,所以我們寫一個通用的可配置的KZWWebViewController侦讨,只需要傳url進(jìn)來就可以驶冒,其他你不要管了,是不是完美韵卤。

所以我們需要來設(shè)計一個這樣的KZWWebViewController骗污,首先必須的是跳轉(zhuǎn)的url和其他的配置參數(shù),然后是接入jsbridge沈条,方便我們和網(wǎng)頁的換下調(diào)用需忿,這樣我們的這個KZWWebViewController就基本滿足需求了。

所以我的做法是抽出一個類來管理蜡歹,它叫KZWRouterHelper屋厘,暴露一個方法

+ (void)pushbyPath:(NSString *)path xxx(xxx)xx .....

里面的操作是把你需要的配置的加上,然后轉(zhuǎn)成字典塞入router

NSDictionary *params = @{
                             @"path": [path kzw_urlEncode],
                             @"timestimp":[NSString stringWithFormat:@"%g", [[NSDate date] timeIntervalSince1970]]
                             };
    NSString *url =
    [NSString stringWithFormat:@"%@?%@", KZWWebViewControllerRouterPath, [NSURL elm_queryStringFromParameters:params]];
    return [[ELMRouter sharedRouter] open:url animated:NO showStyle:ELMPageShowStylePush];

param里包含了你所以的配置月而,類如:

NSDictionary *params = @{
                             @"path": path,
                             @"fullScreen": @(NO),
                             @"fullUrl": @(NO),
                             @"title": string?string:@"",
                             @"timestimp":[NSString stringWithFormat:@"%g", [[NSDate date] timeIntervalSince1970]]
                             };

這個根據(jù)業(yè)務(wù)需求來配置就好汗洒,然后在controller里根據(jù)不同的參數(shù)做相應(yīng)的處理就可以了,這樣你的整個項目里所有的網(wǎng)頁跳轉(zhuǎn)就一行代碼就好了:

1
[KZWRouterHelper pushbyURL:@"xxxx" ];
接入的jsbirdge最好是選擇jscore的方式的父款,這樣是同步溢谤,網(wǎng)頁也可以加個配置方法,這個的主要目的憨攒,有的網(wǎng)頁需要由網(wǎng)頁自己來控制一些顯示世杀,原理同上我們自己的配置都是根據(jù)參數(shù)做不同的處理,具體看KZWWebViewController肝集,然后很多時候產(chǎn)品想要跳二級頁面的時候可以有2個返回瞻坝,這時候如果你的leftBarButtonItems是統(tǒng)配的話最好在頁面加載的時候就先設(shè)置一個返回,然后在didFinishNavigation代理設(shè)置成2個返回杏瞻,一個返回上一個網(wǎng)頁一個返回我們上一個控制器湿镀。這樣做主要是你開始設(shè)置成統(tǒng)配后來直接配2個會閃一下。

還有就是WKWebView中的進(jìn)度條伐憾,WKWebView的進(jìn)度條比較簡單你只要寫一個UIProgressView然后監(jiān)聽WKWebView的加載進(jìn)度就好了,然后title的顯示也是監(jiān)聽就好了赫模,如果沒取到記得設(shè)置一個默認(rèn)的树肃。

[self.webView addObserver:self
                   forKeyPath:NSStringFromSelector(@selector(estimatedProgress))
                      options:0
                      context:nil];
    [self.webView addObserver:self forKeyPath:NSStringFromSelector(@selector(title)) options:NSKeyValueObservingOptionNew context:NULL];
然后是適配iPhone X的記得加這行代碼:

if (KZW_iPhoneX) {
        self.webView.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
    }

最后記得釋放你的監(jiān)聽:

- (NSString *)fullString:(NSString *)path {
    NSString *domain = nil;
    switch ([ELMEnvironmentManager environment]) {
        case ELMEnvBeta:
            domain = @"xxxxx";
            break;
        case ELMEnvAlpha:
            domain = @"xxxxx";
            break;
        case ELMEnvProduction:
            domain = @"xxxxx";
            break;
        default:
            domain = @"xxxxx";
            break;
    }
    if ([path containsString:@"http"]) {
        return path;
    }else {
       return [domain stringByAppendingString:path];
    }
}
 
- (void)dealloc {
    self.webView.UIDelegate = nil;
    [self.webView stopLoading];
    [self.webView removeObserver:self forKeyPath:NSStringFromSelector(@selector(estimatedProgress))];
    [self.webView removeObserver:self forKeyPath:NSStringFromSelector(@selector(title))];
    self.webView = nil;
}

組url的時候可以加個環(huán)境的配置。

就完啦瀑罗,希望對你有用胸嘴。具體看KZWFoudation中的KZWWebViewController,KZWRouterHelper和KZWDSJavaScripInterface斩祭。https://github.com/ouyrp/KZWFoundation

哦還有一個cookie的清空和網(wǎng)頁清緩存我也加上吧劣像,前2篇關(guān)于WKWebView的文章就刪了

- (NSString *)readCurrentCookie {
    return @"";
}
 
- (NSString *)setCurrentCookie {
    return @"";
}
 
cookie清空只要這個2個方法里面參數(shù)清了就好了
if ([[UIDevice currentDevice].systemVersion floatValue] >= 9.0) {
        WKWebsiteDataStore *dateStore = [WKWebsiteDataStore defaultDataStore];
        [dateStore fetchDataRecordsOfTypes:[WKWebsiteDataStore allWebsiteDataTypes]
                         completionHandler:^(NSArray<wkwebsitedatarecord *> * __nonnull records) {
                             for (WKWebsiteDataRecord *record  in records)
                             {
                                 if ( [record.displayName containsString:@"xxxxx"])
                                 {
                                     [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:record.dataTypes
                                                                               forDataRecords:@[record]
                                                                            completionHandler:^{
                                                                                NSLog(@"Cookies for %@ deleted successfully",record.displayName);
                                                                            }];
                                 }
                             }
                         }];
    }else {
        NSString *librarypath = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES).firstObject;
        NSString *cookiesFolderPath = [librarypath stringByAppendingString:@"/Cookies"];
        [[NSFileManager defaultManager] removeItemAtPath:cookiesFolderPath error:nil];
    }
    NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    for (NSHTTPCookie *cookie in [cookieJar cookies]) {
        [cookieJar deleteCookie:cookie];
    }</wkwebsitedatarecord *>

這是清緩存,親測有效

之后還是會出KZWFoudation的系列文章摧玫,寫下自己的封裝思路耳奕。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子屋群,更是在濱河造成了極大的恐慌闸婴,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,640評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件芍躏,死亡現(xiàn)場離奇詭異邪乍,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)对竣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評論 3 395
  • 文/潘曉璐 我一進(jìn)店門庇楞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人否纬,你說我怎么就攤上這事吕晌。” “怎么了烦味?”我有些...
    開封第一講書人閱讀 165,011評論 0 355
  • 文/不壞的土叔 我叫張陵聂使,是天一觀的道長。 經(jīng)常有香客問我谬俄,道長柏靶,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,755評論 1 294
  • 正文 為了忘掉前任溃论,我火速辦了婚禮屎蜓,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘钥勋。我一直安慰自己炬转,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,774評論 6 392
  • 文/花漫 我一把揭開白布算灸。 她就那樣靜靜地躺著扼劈,像睡著了一般。 火紅的嫁衣襯著肌膚如雪菲驴。 梳的紋絲不亂的頭發(fā)上荐吵,一...
    開封第一講書人閱讀 51,610評論 1 305
  • 那天,我揣著相機(jī)與錄音赊瞬,去河邊找鬼先煎。 笑死,一個胖子當(dāng)著我的面吹牛巧涧,可吹牛的內(nèi)容都是我干的薯蝎。 我是一名探鬼主播,決...
    沈念sama閱讀 40,352評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼谤绳,長吁一口氣:“原來是場噩夢啊……” “哼占锯!你這毒婦竟也來了袒哥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,257評論 0 276
  • 序言:老撾萬榮一對情侶失蹤烟央,失蹤者是張志新(化名)和其女友劉穎统诺,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體疑俭,經(jīng)...
    沈念sama閱讀 45,717評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡粮呢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,894評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了钞艇。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片啄寡。...
    茶點故事閱讀 40,021評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖哩照,靈堂內(nèi)的尸體忽然破棺而出挺物,到底是詐尸還是另有隱情,我是刑警寧澤飘弧,帶...
    沈念sama閱讀 35,735評論 5 346
  • 正文 年R本政府宣布识藤,位于F島的核電站,受9級特大地震影響次伶,放射性物質(zhì)發(fā)生泄漏痴昧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,354評論 3 330
  • 文/蒙蒙 一冠王、第九天 我趴在偏房一處隱蔽的房頂上張望赶撰。 院中可真熱鬧,春花似錦柱彻、人聲如沸豪娜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瘤载。三九已至,卻和暖如春卖擅,著一層夾襖步出監(jiān)牢的瞬間惕虑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評論 1 270
  • 我被黑心中介騙來泰國打工磨镶, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人健提。 一個月前我還...
    沈念sama閱讀 48,224評論 3 371
  • 正文 我出身青樓琳猫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親私痹。 傳聞我的和親對象是個殘疾皇子脐嫂,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,974評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 在iOS 8.0以后蘋果推出WKWebView统刮,之前有性能問題的UIWebView基本就被棄用了,這里整理下我的W...
    moonCoder閱讀 1,259評論 2 9
  • 導(dǎo)語 WKWebView 是蘋果在 WWDC 2014 上推出的新一代 webView 組件账千,用以替代 UIKit...
    yahoouchen閱讀 4,089評論 8 17
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理侥蒙,服務(wù)發(fā)現(xiàn),斷路器匀奏,智...
    卡卡羅2017閱讀 134,659評論 18 139
  • 前言 關(guān)于UIWebView的介紹鞭衩,相信看過上文的小伙伴們,已經(jīng)大概清楚了吧娃善,如果有問題论衍,歡迎提問。 本文是本系列...
    CoderLF閱讀 8,968評論 2 12
  • iOS 的 Cookie 存取 https://juejin.im/entry/58d4c4cc44d904006...
    Farmers閱讀 5,930評論 0 16