diff --git a/README.md b/README.md index ac0ae09a..2b731f39 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,10 @@ If set to true, links with `target="_blank"` or `window.open` will be opened in Set `sendCookies` to true to copy cookies from `sharedHTTPCookieStorage` when calling loadRequest. This emulates the behavior of react-native's `WebView` component. You can set cookies using `react-native-cookies` Default is false. +- **useWKCookieStore** + +Set `useWKCookieStore` to true to use the webView's `WKHTTPCookieStorage`. All Cookies from `sharedHTTPCookieStorage` will be copied to it. + - **source={{file: '', allowingReadAccessToURL: '' }}** This allows WKWebView loads a local HTML file. Please note the underlying API is only introduced in iOS 9+. So in iOS 8, it will simple ignores these two properties. diff --git a/WKWebView.ios.js b/WKWebView.ios.js index f9a37eb1..aea0ee6d 100644 --- a/WKWebView.ios.js +++ b/WKWebView.ios.js @@ -232,6 +232,10 @@ class WKWebView extends React.Component { * Set this to true to emulate behavior of WebView component. */ sendCookies: PropTypes.bool, + /** + * Initializes the webView's WKHTTPCookieStorage and copies all cookies from sharedHTTPCookieStorage + */ + useWKCookieStore: PropTypes.bool, /** * If set to true, target="_blank" or window.open will be opened in WebView, instead * of new window. Default is false to be backward compatible. @@ -312,18 +316,16 @@ class WKWebView extends React.Component { WKWebViewManager.startLoadWithResult(!!shouldStart, event.nativeEvent.lockIdentifier); }); - let source = this.props.source; - if (this.props.source && typeof this.props.source === 'object') { - source = Object.assign({}, this.props.source, { - sendCookies: this.props.sendCookies, - customUserAgent: this.props.customUserAgent || this.props.userAgent - }); - - if (this.props.html) { - source.html = this.props.html; - } else if (this.props.url) { - source.uri = this.props.url; - } + let source = Object.assign({}, this.props.source || {}, { + sendCookies: this.props.sendCookies, + customUserAgent: this.props.customUserAgent || this.props.userAgent, + useWKCookieStore: this.props.useWKCookieStore, + }); + + if (this.props.html) { + source.html = this.props.html; + } else if (this.props.url) { + source.uri = this.props.url; } const messagingEnabled = typeof this.props.onMessage === 'function'; diff --git a/ios/RCTWKWebView/RCTWKWebView.m b/ios/RCTWKWebView/RCTWKWebView.m index e1348c81..34b3f67a 100644 --- a/ios/RCTWKWebView/RCTWKWebView.m +++ b/ios/RCTWKWebView/RCTWKWebView.m @@ -35,6 +35,7 @@ @interface RCTWKWebView () 0) + [cDesc appendFormat:@"domain=%@;", [cookie domain]]; + if ([cookie.path length] > 0) + [cDesc appendFormat:@"path=%@;", [cookie path]]; + if (cookie.expiresDate != nil) + [cDesc appendFormat:@"expiresDate=%@;", [cookie expiresDate]]; + + + return cDesc; +} + +- (void) copyCookies { + + NSHTTPCookieStorage* storage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; + NSArray* array = [storage cookies]; + + + if (@available(ios 11,*)) { + + // The webView websiteDataStore only gets initialized, when needed. Setting cookies on the dataStore's + // httpCookieStore doesn't seem to initialize it. That's why fetchDataRecordsOfTypes is called. + // All the cookies of the sharedHttpCookieStorage, which is used in react-native-cookie, + // are copied to the webSiteDataStore's httpCookieStore. + // https://bugs.webkit.org/show_bug.cgi?id=185483 + [_webView.configuration.websiteDataStore fetchDataRecordsOfTypes:[NSSet setWithObject:WKWebsiteDataTypeCookies] completionHandler:^(NSArray *records) { + for (NSHTTPCookie* cookie in array) { + [_webView.configuration.websiteDataStore.httpCookieStore setCookie:cookie completionHandler:nil]; + } + }]; + } else { + // Create WKUserScript for each cookie + // Cookies are injected with Javascript AtDocumentStart + for (NSHTTPCookie* cookie in array){ + NSString* cookieSource = [NSString stringWithFormat:@"document.cookie = '%@'", [self cookieDescription:cookie]]; + WKUserScript* cookieScript = [[WKUserScript alloc] + initWithSource:cookieSource + injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO]; + + + [_webView.configuration.userContentController addUserScript:cookieScript]; + } + } +} + - (void)setSource:(NSDictionary *)source { if (![_source isEqualToDictionary:source]) { _source = [source copy]; _sendCookies = [source[@"sendCookies"] boolValue]; + _useWKCookieStore = [source[@"useWKCookieStore"] boolValue]; + + if (_useWKCookieStore) { + [self copyCookies]; + } + if ([source[@"customUserAgent"] length] != 0 && [_webView respondsToSelector:@selector(setCustomUserAgent:)]) { [_webView setCustomUserAgent:source[@"customUserAgent"]]; }