Skip to content

Commit

Permalink
Apply changes from CRAlpha#171
Browse files Browse the repository at this point in the history
  • Loading branch information
robinheinze committed Oct 5, 2018
1 parent 21091d9 commit b03e48a
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 19 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ 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.
Expand Down
7 changes: 6 additions & 1 deletion WKWebView.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,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.
Expand Down Expand Up @@ -321,7 +325,8 @@ class WKWebView extends React.Component {
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
customUserAgent: this.props.customUserAgent || this.props.userAgent,
useWKCookieStore: this.props.useWKCookieStore
});

if (this.props.html) {
Expand Down
90 changes: 72 additions & 18 deletions ios/RCTWKWebView/RCTWKWebView.m
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ @interface RCTWKWebView () <WKNavigationDelegate, RCTAutoInsetsProtocol, WKScrip
@property (nonatomic, copy) RCTDirectEventBlock onUrlChanged;
@property (nonatomic, copy) RCTDirectEventBlock onNavigationResponse;
@property (assign) BOOL sendCookies;
@property (assign) BOOL useWKCookieStore;
@property (nonatomic, strong) WKUserScript *atStartScript;
@property (nonatomic, strong) WKUserScript *atEndScript;

Expand Down Expand Up @@ -348,6 +349,50 @@ - (void)stopLoading
[_webView stopLoading];
}

- (NSString *) cookieDescription:(NSHTTPCookie *)cookie {
NSMutableString *cDesc = [[NSMutableString alloc] init];
[cDesc appendFormat:@"%@=%@;",
[[cookie name] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
[[cookie value] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
if ([cookie.domain length] > 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]];
if (cookie.HTTPOnly == YES)
[cDesc appendString:@"HttpOnly;"];
if (cookie.secure == YES)
[cDesc appendString:@"Secure;"];
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<NSString *> setWithObject:WKWebsiteDataTypeCookies] completionHandler:^(NSArray<WKWebsiteDataRecord *> *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 (!_webView) {
Expand All @@ -358,6 +403,11 @@ - (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"]];
}
Expand Down Expand Up @@ -512,6 +562,28 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView

#pragma mark - WKNavigationDelegate methods

- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {
if (_sendCookies) {
NSHTTPURLResponse *response = (NSHTTPURLResponse *)navigationResponse.response;
NSArray *cookies = [NSHTTPCookie cookiesWithResponseHeaderFields:[response allHeaderFields] forURL:response.URL];
for (NSHTTPCookie *cookie in cookies) {
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
}
}
if (_onNavigationResponse) {
NSDictionary *headers = ((NSHTTPURLResponse *)navigationResponse.response).allHeaderFields;
NSInteger statusCode = ((NSHTTPURLResponse *)navigationResponse.response).statusCode;
NSMutableDictionary<NSString *, id> *event = [self baseEvent];
[event addEntriesFromDictionary:@{
@"headers": headers,
@"status": [NSHTTPURLResponse localizedStringForStatusCode:statusCode],
@"statusCode": @(statusCode),
}];
_onNavigationResponse(event);
}
decisionHandler(WKNavigationResponsePolicyAllow);
}

#if DEBUG
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler {
NSURLCredential * credential = [[NSURLCredential alloc] initWithTrust:[challenge protectionSpace].serverTrust];
Expand Down Expand Up @@ -666,22 +738,4 @@ - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView
RCTLogWarn(@"Webview Process Terminated");
}

- (void)webView:(__unused WKWebView *)webView
decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
if (_onNavigationResponse) {
NSDictionary *headers = ((NSHTTPURLResponse *)navigationResponse.response).allHeaderFields;
NSInteger statusCode = ((NSHTTPURLResponse *)navigationResponse.response).statusCode;
NSMutableDictionary<NSString *, id> *event = [self baseEvent];
[event addEntriesFromDictionary:@{
@"headers": headers,
@"status": [NSHTTPURLResponse localizedStringForStatusCode:statusCode],
@"statusCode": @(statusCode),
}];
_onNavigationResponse(event);
}

decisionHandler(WKNavigationResponsePolicyAllow);
}

@end

0 comments on commit b03e48a

Please sign in to comment.