最近研究了一下給webview注入Cookie,主要針對的是WKWebview,畢竟UIWebview到年底蘋果就不再支持了。而且針對WKWebview,蘋果在iOS11之后新出了類WKHTTPCookieStore 以及對應(yīng)的API來操作Cookie。
一、Cookie的生成
首先看下生成Cookie的類 NSHTTPCookie,打開源碼可以看到要生成Cookie所對應(yīng)的key值,里面包括:name、value、url、版本、域名、過期日期等等key值,如下:
FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieName;
FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieValue;
FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieOriginURL;
FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieVersion;
FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieDomain;
FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookiePath;
FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieSecure;
FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieExpires;
FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieComment;
FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieCommentURL;
FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieDiscard;
FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieMaximumAge;
FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookiePort;
FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieSameSitePolicy API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0));
FOUNDATION_EXPORT NSHTTPCookieStringPolicy const NSHTTPCookieSameSiteLax API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0));
FOUNDATION_EXPORT NSHTTPCookieStringPolicy const NSHTTPCookieSameSiteStrict API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0));
還有可以直接獲取Cookie的一些屬性,不過都是只讀的,如下:
@property (nullable, readonly, copy) NSDictionary<NSHTTPCookiePropertyKey, id> *properties;
@property (readonly) NSUInteger version;
@property (readonly, copy) NSString *name;
@property (readonly, copy) NSString *value;
@property (nullable, readonly, copy) NSDate *expiresDate;
@property (readonly, getter=isSessionOnly) BOOL sessionOnly;
@property (readonly, copy) NSString *domain;
@property (readonly, copy) NSString *path;
@property (readonly, getter=isSecure) BOOL secure;
@property (readonly, getter=isHTTPOnly) BOOL HTTPOnly;
@property (nullable, readonly, copy) NSString *comment;
@property (nullable, readonly, copy) NSURL *commentURL;
@property (nullable, readonly, copy) NSArray<NSNumber *> *portList;
@property (nullable, readonly, copy) NSHTTPCookieStringPolicy sameSitePolicy API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0));
下面是生成Cookie的一些方法:
- (nullable instancetype)initWithProperties:(NSDictionary<NSHTTPCookiePropertyKey, id> *)properties;
+ (nullable NSHTTPCookie *)cookieWithProperties:(NSDictionary<NSHTTPCookiePropertyKey, id> *)properties;
其中 properties 就是一個字典,用來設(shè)置生成Cookie的一些鍵值對。
所以可以用以下方式來生成Cookie:
NSMutableDictionary *cookieProperties = [NSMutableDictionary dictionary];
[cookieProperties setObject:@"name" forKey:NSHTTPCookieName];
[cookieProperties setObject:@"value" forKey:NSHTTPCookieValue];
[cookieProperties setObject:@"jianshu.com" forKey:NSHTTPCookieDomain];
[cookieProperties setObject:@"jianshu.com" forKey:NSHTTPCookieOriginURL];
[cookieProperties setObject:@"/" forKey:NSHTTPCookiePath];
[cookieProperties setObject:@"0" forKey:NSHTTPCookieVersion];
/// 設(shè)置失效時間,不要設(shè)置NSHTTPCookieDiscard(設(shè)置sessionOnly,會話操作使用)
[cookieProperties setObject:[NSDate date] forKey:NSHTTPCookieExpires];
NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieProperties];
其中有個需要注意的點,設(shè)置失效時間時,不要設(shè)置NSHTTPCookieDiscard。同時設(shè)置的話,失效時間會為nil,因為NSHTTPCookieDiscard 僅在會話操作時使用。
二、Cookie的注入
對于iOS11之前的系統(tǒng),可以直接使用 NSHTTPCookieStorage 來注入 Cookie,如下:
NSMutableDictionary *cookieProperties = [NSMutableDictionary dictionary];
[cookieProperties setObject:@"name" forKey:NSHTTPCookieName];
[cookieProperties setObject:@"value" forKey:NSHTTPCookieValue];
[cookieProperties setObject:@"jianshu.com" forKey:NSHTTPCookieDomain];
[cookieProperties setObject:@"jianshu.com" forKey:NSHTTPCookieOriginURL];
[cookieProperties setObject:@"/" forKey:NSHTTPCookiePath];
[cookieProperties setObject:@"0" forKey:NSHTTPCookieVersion];
/// 設(shè)置失效時間,不要設(shè)置NSHTTPCookieDiscard(設(shè)置sessionOnly,會話操作使用)
[cookieProperties setObject:[NSDate date] forKey:NSHTTPCookieExpires];
NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieProperties];
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
對于iOS11及之后的系統(tǒng),需要將 NSHTTPCookieStorage中的Cookie信息復(fù)制到 WKHTTPCookieStore 中,以此來達到 WKWebView中注入Cookie 的目的。
這是利用iOS11 API WKHTTPCookieStore 可以解決WKWebView首次請求不攜帶Cookie 的問題。因為WKWebView每次請求都會攜帶WKHTTPCookieStore里的Cookie。
只需要在上述代碼之后加入以下代碼即可:
if (@available(iOS 11, *)) {
NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];
WKHTTPCookieStore *cookieStore = webview.configuration.websiteDataStore.httpCookieStore;
for (NSHTTPCookie *cookie in cookies) {
[cookieStore setCookie:cookie completionHandler:nil];
}
[cookieStore setCookie:cookie completionHandler:nil];
}
三、Cookie的刪除
iOS11之前的系統(tǒng)可以使用下面的方法來刪除Cookie:
[[WKWebsiteDataStore defaultDataStore] fetchDataRecordsOfTypes:[NSSet setWithObjects:WKWebsiteDataTypeCookies, nil] completionHandler:^(NSArray<WKWebsiteDataRecord *> * _Nonnull records) {
[[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] forDataRecords:records completionHandler:^{
}];
}];
或
NSArray * cookArray = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];
for (NSHTTPCookie *cookie in cookArray) {
if ([cookie.domain isEqualToString:@"jianshu.com"]) {
[[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:cookie];
}
}
iOS11及之后的系統(tǒng)可以使用WKHTTPCookieStore的deleteCookie: completionHandler: 方法來操作:
WKHTTPCookieStore *cookieStore = webview.configuration.websiteDataStore.httpCookieStore;
[cookieStore getAllCookies:^(NSArray* cookies) {
for (NSHTTPCookie *cookie in cookies) {
if ([cookie.domain isEqualToString:@"jianshu.com"]) {
[cookieStore deleteCookie:cookie completionHandler:nil];
}
}
}];
以上。