最近研究了一下给webview注入Cookie,主要针对的是WKWebview,毕竟UIWebview到年底苹果就不再支持了。而且针对WKWebview,苹果在iOS11之后新出了类WKHTTPCookieStore 以及对应的API来操作Cookie。
一、Cookie的生成
首先看下生成Cookie的类 NSHTTPCookie,打开源码可以看到要生成Cookie所对应的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 就是一个字典,用来设置生成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];
/// 设置失效时间,不要设置NSHTTPCookieDiscard(设置sessionOnly,会话操作使用)
[cookieProperties setObject:[NSDate date] forKey:NSHTTPCookieExpires];
NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieProperties];
其中有个需要注意的点,设置失效时间时,不要设置NSHTTPCookieDiscard。同时设置的话,失效时间会为nil,因为NSHTTPCookieDiscard 仅在会话操作时使用。
二、Cookie的注入
对于iOS11之前的系统,可以直接使用 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];
/// 设置失效时间,不要设置NSHTTPCookieDiscard(设置sessionOnly,会话操作使用)
[cookieProperties setObject:[NSDate date] forKey:NSHTTPCookieExpires];
NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieProperties];
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
对于iOS11及之后的系统,需要将 NSHTTPCookieStorage中的Cookie信息复制到 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之前的系统可以使用下面的方法来删除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及之后的系统可以使用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];
}
}
}];
以上。
网友评论