Skip to content

Commit b03e48a

Browse files
committed
Apply changes from CRAlpha#171
1 parent 21091d9 commit b03e48a

File tree

3 files changed

+81
-19
lines changed

3 files changed

+81
-19
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ If set to true, links with `target="_blank"` or `window.open` will be opened in
6161

6262
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.
6363

64+
- **useWKCookieStore**
65+
Set `useWKCookieStore` to true to use the webView's `WKHTTPCookieStorage`. All Cookies from `sharedHTTPCookieStorage` will be copied to it.
66+
6467
- **source={{file: '', allowingReadAccessToURL: '' }}**
6568

6669
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.

WKWebView.ios.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,10 @@ class WKWebView extends React.Component {
237237
* Set this to true to emulate behavior of WebView component.
238238
*/
239239
sendCookies: PropTypes.bool,
240+
/**
241+
* Initializes the webView's WKHTTPCookieStorage and copies all cookies from sharedHTTPCookieStorage
242+
*/
243+
useWKCookieStore: PropTypes.bool,
240244
/**
241245
* If set to true, target="_blank" or window.open will be opened in WebView, instead
242246
* of new window. Default is false to be backward compatible.
@@ -321,7 +325,8 @@ class WKWebView extends React.Component {
321325
if (this.props.source && typeof this.props.source === 'object') {
322326
source = Object.assign({}, this.props.source, {
323327
sendCookies: this.props.sendCookies,
324-
customUserAgent: this.props.customUserAgent || this.props.userAgent
328+
customUserAgent: this.props.customUserAgent || this.props.userAgent,
329+
useWKCookieStore: this.props.useWKCookieStore
325330
});
326331

327332
if (this.props.html) {

ios/RCTWKWebView/RCTWKWebView.m

Lines changed: 72 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ @interface RCTWKWebView () <WKNavigationDelegate, RCTAutoInsetsProtocol, WKScrip
3838
@property (nonatomic, copy) RCTDirectEventBlock onUrlChanged;
3939
@property (nonatomic, copy) RCTDirectEventBlock onNavigationResponse;
4040
@property (assign) BOOL sendCookies;
41+
@property (assign) BOOL useWKCookieStore;
4142
@property (nonatomic, strong) WKUserScript *atStartScript;
4243
@property (nonatomic, strong) WKUserScript *atEndScript;
4344

@@ -348,6 +349,50 @@ - (void)stopLoading
348349
[_webView stopLoading];
349350
}
350351

352+
- (NSString *) cookieDescription:(NSHTTPCookie *)cookie {
353+
NSMutableString *cDesc = [[NSMutableString alloc] init];
354+
[cDesc appendFormat:@"%@=%@;",
355+
[[cookie name] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
356+
[[cookie value] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
357+
if ([cookie.domain length] > 0)
358+
[cDesc appendFormat:@"domain=%@;", [cookie domain]];
359+
if ([cookie.path length] > 0)
360+
[cDesc appendFormat:@"path=%@;", [cookie path]];
361+
if (cookie.expiresDate != nil)
362+
[cDesc appendFormat:@"expiresDate=%@;", [cookie expiresDate]];
363+
if (cookie.HTTPOnly == YES)
364+
[cDesc appendString:@"HttpOnly;"];
365+
if (cookie.secure == YES)
366+
[cDesc appendString:@"Secure;"];
367+
return cDesc;
368+
}
369+
- (void) copyCookies {
370+
NSHTTPCookieStorage* storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
371+
NSArray* array = [storage cookies];
372+
if (@available(ios 11,*)) {
373+
// The webView websiteDataStore only gets initialized, when needed. Setting cookies on the dataStore's
374+
// httpCookieStore doesn't seem to initialize it. That's why fetchDataRecordsOfTypes is called.
375+
// All the cookies of the sharedHttpCookieStorage, which is used in react-native-cookie,
376+
// are copied to the webSiteDataStore's httpCookieStore.
377+
// https://bugs.webkit.org/show_bug.cgi?id=185483
378+
[_webView.configuration.websiteDataStore fetchDataRecordsOfTypes:[NSSet<NSString *> setWithObject:WKWebsiteDataTypeCookies] completionHandler:^(NSArray<WKWebsiteDataRecord *> *records) {
379+
for (NSHTTPCookie* cookie in array) {
380+
[_webView.configuration.websiteDataStore.httpCookieStore setCookie:cookie completionHandler:nil];
381+
}
382+
}];
383+
} else {
384+
// Create WKUserScript for each cookie
385+
// Cookies are injected with Javascript AtDocumentStart
386+
for (NSHTTPCookie* cookie in array){
387+
NSString* cookieSource = [NSString stringWithFormat:@"document.cookie = '%@'", [self cookieDescription:cookie]];
388+
WKUserScript* cookieScript = [[WKUserScript alloc]
389+
initWithSource:cookieSource
390+
injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
391+
[_webView.configuration.userContentController addUserScript:cookieScript];
392+
}
393+
}
394+
}
395+
351396
- (void)setSource:(NSDictionary *)source
352397
{
353398
if (!_webView) {
@@ -358,6 +403,11 @@ - (void)setSource:(NSDictionary *)source
358403
if (![_source isEqualToDictionary:source]) {
359404
_source = [source copy];
360405
_sendCookies = [source[@"sendCookies"] boolValue];
406+
_useWKCookieStore = [source[@"useWKCookieStore"] boolValue];
407+
if (_useWKCookieStore) {
408+
[self copyCookies];
409+
}
410+
361411
if ([source[@"customUserAgent"] length] != 0 && [_webView respondsToSelector:@selector(setCustomUserAgent:)]) {
362412
[_webView setCustomUserAgent:source[@"customUserAgent"]];
363413
}
@@ -512,6 +562,28 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView
512562

513563
#pragma mark - WKNavigationDelegate methods
514564

565+
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {
566+
if (_sendCookies) {
567+
NSHTTPURLResponse *response = (NSHTTPURLResponse *)navigationResponse.response;
568+
NSArray *cookies = [NSHTTPCookie cookiesWithResponseHeaderFields:[response allHeaderFields] forURL:response.URL];
569+
for (NSHTTPCookie *cookie in cookies) {
570+
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
571+
}
572+
}
573+
if (_onNavigationResponse) {
574+
NSDictionary *headers = ((NSHTTPURLResponse *)navigationResponse.response).allHeaderFields;
575+
NSInteger statusCode = ((NSHTTPURLResponse *)navigationResponse.response).statusCode;
576+
NSMutableDictionary<NSString *, id> *event = [self baseEvent];
577+
[event addEntriesFromDictionary:@{
578+
@"headers": headers,
579+
@"status": [NSHTTPURLResponse localizedStringForStatusCode:statusCode],
580+
@"statusCode": @(statusCode),
581+
}];
582+
_onNavigationResponse(event);
583+
}
584+
decisionHandler(WKNavigationResponsePolicyAllow);
585+
}
586+
515587
#if DEBUG
516588
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler {
517589
NSURLCredential * credential = [[NSURLCredential alloc] initWithTrust:[challenge protectionSpace].serverTrust];
@@ -666,22 +738,4 @@ - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView
666738
RCTLogWarn(@"Webview Process Terminated");
667739
}
668740

669-
- (void)webView:(__unused WKWebView *)webView
670-
decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
671-
decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
672-
if (_onNavigationResponse) {
673-
NSDictionary *headers = ((NSHTTPURLResponse *)navigationResponse.response).allHeaderFields;
674-
NSInteger statusCode = ((NSHTTPURLResponse *)navigationResponse.response).statusCode;
675-
NSMutableDictionary<NSString *, id> *event = [self baseEvent];
676-
[event addEntriesFromDictionary:@{
677-
@"headers": headers,
678-
@"status": [NSHTTPURLResponse localizedStringForStatusCode:statusCode],
679-
@"statusCode": @(statusCode),
680-
}];
681-
_onNavigationResponse(event);
682-
}
683-
684-
decisionHandler(WKNavigationResponsePolicyAllow);
685-
}
686-
687741
@end

0 commit comments

Comments
 (0)