feat(iOS cookies): implement sharedCookiesEnabled prop for iOS RNCWKWebView (#175)
We had the problem on iOS WebViews that local cookies (stored in local HTTPCookieStorage, set with [react-native-cookie](https://github.com/shimohq/react-native-cookie) ) were not added in loadRequests. On Android the local stored cookies were sent like expected. This kinda "hacky" solution is the only way we found, that works for us. The stack overview link is in the code below. If someone finds a better solution we would very much like to accept that.
This commit is contained in:
parent
a9c00faf37
commit
cdbfc19cd2
|
@ -50,6 +50,7 @@ This document lays out the current public properties and methods for the React N
|
|||
- [`cacheEnabled`](Reference.md#cacheEnabled)
|
||||
- [`pagingEnabled`](Reference.md#pagingEnabled)
|
||||
- [`allowsLinkPreview`](Reference.md#allowsLinkPreview)
|
||||
- [`sharedCookiesEnabled`](Reference.md#sharedCookiesEnabled)
|
||||
|
||||
## Methods Index
|
||||
|
||||
|
@ -833,6 +834,16 @@ A Boolean value that determines whether pressing on a link displays a preview of
|
|||
| ------- | -------- | -------- |
|
||||
| boolean | No | iOS |
|
||||
|
||||
---
|
||||
|
||||
### `sharedCookiesEnabled`
|
||||
|
||||
Set `true` if shared cookies from `[NSHTTPCookieStorage sharedHTTPCookieStorage]` should used for every load request in the `RNCWKWebView`. The default value is `false`.
|
||||
|
||||
| Type | Required | Platform |
|
||||
| ------- | -------- | -------- |
|
||||
| boolean | No | iOS |
|
||||
|
||||
## Methods
|
||||
|
||||
### `extraNativeComponentConfig()`
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
@property (nonatomic, assign) BOOL messagingEnabled;
|
||||
@property (nonatomic, copy) NSString *injectedJavaScript;
|
||||
@property (nonatomic, assign) BOOL scrollEnabled;
|
||||
@property (nonatomic, assign) BOOL sharedCookiesEnabled;
|
||||
@property (nonatomic, assign) BOOL pagingEnabled;
|
||||
@property (nonatomic, assign) CGFloat decelerationRate;
|
||||
@property (nonatomic, assign) BOOL allowsInlineMediaPlayback;
|
||||
|
|
|
@ -127,6 +127,68 @@ static NSURLCredential* clientAuthenticationCredential;
|
|||
wkWebViewConfig.mediaPlaybackRequiresUserAction = _mediaPlaybackRequiresUserAction;
|
||||
#endif
|
||||
|
||||
if(_sharedCookiesEnabled) {
|
||||
// More info to sending cookies with WKWebView
|
||||
// https://stackoverflow.com/questions/26573137/can-i-set-the-cookies-to-be-used-by-a-wkwebview/26577303#26577303
|
||||
if (@available(iOS 11.0, *)) {
|
||||
// Set Cookies in iOS 11 and above, initialize websiteDataStore before setting cookies
|
||||
// See also https://forums.developer.apple.com/thread/97194
|
||||
// check if websiteDataStore has not been initialized before
|
||||
if(!_incognito && !_cacheEnabled) {
|
||||
wkWebViewConfig.websiteDataStore = [WKWebsiteDataStore nonPersistentDataStore];
|
||||
}
|
||||
for (NSHTTPCookie *cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]) {
|
||||
[wkWebViewConfig.websiteDataStore.httpCookieStore setCookie:cookie completionHandler:nil];
|
||||
}
|
||||
} else {
|
||||
NSMutableString *script = [NSMutableString string];
|
||||
|
||||
// Clear all existing cookies in a direct called function. This ensures that no
|
||||
// javascript error will break the web content javascript.
|
||||
// We keep this code here, if someone requires that Cookies are also removed within the
|
||||
// the WebView and want to extends the current sharedCookiesEnabled option with an
|
||||
// additional property.
|
||||
// Generates JS: document.cookie = "key=; Expires=Thu, 01 Jan 1970 00:00:01 GMT;"
|
||||
// for each cookie which is already available in the WebView context.
|
||||
/*
|
||||
[script appendString:@"(function () {\n"];
|
||||
[script appendString:@" var cookies = document.cookie.split('; ');\n"];
|
||||
[script appendString:@" for (var i = 0; i < cookies.length; i++) {\n"];
|
||||
[script appendString:@" if (cookies[i].indexOf('=') !== -1) {\n"];
|
||||
[script appendString:@" document.cookie = cookies[i].split('=')[0] + '=; Expires=Thu, 01 Jan 1970 00:00:01 GMT';\n"];
|
||||
[script appendString:@" }\n"];
|
||||
[script appendString:@" }\n"];
|
||||
[script appendString:@"})();\n\n"];
|
||||
*/
|
||||
|
||||
// Set cookies in a direct called function. This ensures that no
|
||||
// javascript error will break the web content javascript.
|
||||
// Generates JS: document.cookie = "key=value; Path=/; Expires=Thu, 01 Jan 20xx 00:00:01 GMT;"
|
||||
// for each cookie which is available in the application context.
|
||||
[script appendString:@"(function () {\n"];
|
||||
for (NSHTTPCookie *cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]) {
|
||||
[script appendFormat:@"document.cookie = %@ + '=' + %@",
|
||||
RCTJSONStringify(cookie.name, NULL),
|
||||
RCTJSONStringify(cookie.value, NULL)];
|
||||
if (cookie.path) {
|
||||
[script appendFormat:@" + '; Path=' + %@", RCTJSONStringify(cookie.path, NULL)];
|
||||
}
|
||||
if (cookie.expiresDate) {
|
||||
[script appendFormat:@" + '; Expires=' + new Date(%f).toUTCString()",
|
||||
cookie.expiresDate.timeIntervalSince1970 * 1000
|
||||
];
|
||||
}
|
||||
[script appendString:@";\n"];
|
||||
}
|
||||
[script appendString:@"})();\n"];
|
||||
|
||||
WKUserScript* cookieInScript = [[WKUserScript alloc] initWithSource:script
|
||||
injectionTime:WKUserScriptInjectionTimeAtDocumentStart
|
||||
forMainFrameOnly:YES];
|
||||
[wkWebViewConfig.userContentController addUserScript:cookieInScript];
|
||||
}
|
||||
}
|
||||
|
||||
_webView = [[WKWebView alloc] initWithFrame:self.bounds configuration: wkWebViewConfig];
|
||||
_webView.scrollView.delegate = self;
|
||||
_webView.UIDelegate = self;
|
||||
|
@ -270,37 +332,36 @@ static NSURLCredential* clientAuthenticationCredential;
|
|||
|
||||
- (void)visitSource
|
||||
{
|
||||
// Check for a static html source first
|
||||
NSString *html = [RCTConvert NSString:_source[@"html"]];
|
||||
if (html) {
|
||||
NSURL *baseURL = [RCTConvert NSURL:_source[@"baseUrl"]];
|
||||
if (!baseURL) {
|
||||
baseURL = [NSURL URLWithString:@"about:blank"];
|
||||
// Check for a static html source first
|
||||
NSString *html = [RCTConvert NSString:_source[@"html"]];
|
||||
if (html) {
|
||||
NSURL *baseURL = [RCTConvert NSURL:_source[@"baseUrl"]];
|
||||
if (!baseURL) {
|
||||
baseURL = [NSURL URLWithString:@"about:blank"];
|
||||
}
|
||||
[_webView loadHTMLString:html baseURL:baseURL];
|
||||
return;
|
||||
}
|
||||
[_webView loadHTMLString:html baseURL:baseURL];
|
||||
return;
|
||||
}
|
||||
|
||||
NSURLRequest *request = [RCTConvert NSURLRequest:_source];
|
||||
// Because of the way React works, as pages redirect, we actually end up
|
||||
// passing the redirect urls back here, so we ignore them if trying to load
|
||||
// the same url. We'll expose a call to 'reload' to allow a user to load
|
||||
// the existing page.
|
||||
if ([request.URL isEqual:_webView.URL]) {
|
||||
return;
|
||||
}
|
||||
if (!request.URL) {
|
||||
// Clear the webview
|
||||
[_webView loadHTMLString:@"" baseURL:nil];
|
||||
return;
|
||||
}
|
||||
if (request.URL.host) {
|
||||
[_webView loadRequest:request];
|
||||
}
|
||||
else {
|
||||
[_webView loadFileURL:request.URL allowingReadAccessToURL:request.URL];
|
||||
}
|
||||
|
||||
NSURLRequest *request = [self requestForSource:_source];
|
||||
// Because of the way React works, as pages redirect, we actually end up
|
||||
// passing the redirect urls back here, so we ignore them if trying to load
|
||||
// the same url. We'll expose a call to 'reload' to allow a user to load
|
||||
// the existing page.
|
||||
if ([request.URL isEqual:_webView.URL]) {
|
||||
return;
|
||||
}
|
||||
if (!request.URL) {
|
||||
// Clear the webview
|
||||
[_webView loadHTMLString:@"" baseURL:nil];
|
||||
return;
|
||||
}
|
||||
if (request.URL.host) {
|
||||
[_webView loadRequest:request];
|
||||
}
|
||||
else {
|
||||
[_webView loadFileURL:request.URL allowingReadAccessToURL:request.URL];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)setHideKeyboardAccessoryView:(BOOL)hideKeyboardAccessoryView
|
||||
|
@ -662,11 +723,11 @@ static NSURLCredential* clientAuthenticationCredential;
|
|||
* [_webView reload] doesn't reload the webpage. Therefore, we must
|
||||
* manually call [_webView loadRequest:request].
|
||||
*/
|
||||
NSURLRequest *request = [RCTConvert NSURLRequest:self.source];
|
||||
NSURLRequest *request = [self requestForSource:self.source];
|
||||
|
||||
if (request.URL && !_webView.URL.absoluteString.length) {
|
||||
[_webView loadRequest:request];
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
[_webView reload];
|
||||
}
|
||||
}
|
||||
|
@ -681,4 +742,25 @@ static NSURLCredential* clientAuthenticationCredential;
|
|||
_bounces = bounces;
|
||||
_webView.scrollView.bounces = bounces;
|
||||
}
|
||||
|
||||
- (NSURLRequest *)requestForSource:(id)json {
|
||||
NSURLRequest *request = [RCTConvert NSURLRequest:self.source];
|
||||
|
||||
// If sharedCookiesEnabled we automatically add all application cookies to the
|
||||
// http request. This is automatically done on iOS 11+ in the WebView constructor.
|
||||
// Se we need to manually add these shared cookies here only for iOS versions < 11.
|
||||
if (_sharedCookiesEnabled) {
|
||||
if (@available(iOS 11.0, *)) {
|
||||
// see WKWebView initialization for added cookies
|
||||
} else {
|
||||
NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:request.URL];
|
||||
NSDictionary<NSString *, NSString *> *cookieHeader = [NSHTTPCookie requestHeaderFieldsWithCookies:cookies];
|
||||
NSMutableURLRequest *mutableRequest = [request mutableCopy];
|
||||
[mutableRequest setAllHTTPHeaderFields:cookieHeader];
|
||||
return mutableRequest;
|
||||
}
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -81,6 +81,10 @@ RCT_CUSTOM_VIEW_PROPERTY(scrollEnabled, BOOL, RNCWKWebView) {
|
|||
view.scrollEnabled = json == nil ? true : [RCTConvert BOOL: json];
|
||||
}
|
||||
|
||||
RCT_CUSTOM_VIEW_PROPERTY(sharedCookiesEnabled, BOOL, RNCWKWebView) {
|
||||
view.sharedCookiesEnabled = json == nil ? false : [RCTConvert BOOL: json];
|
||||
}
|
||||
|
||||
RCT_CUSTOM_VIEW_PROPERTY(decelerationRate, CGFloat, RNCWKWebView) {
|
||||
view.decelerationRate = json == nil ? UIScrollViewDecelerationRateNormal : [RCTConvert CGFloat: json];
|
||||
}
|
||||
|
|
|
@ -387,12 +387,20 @@ export interface IOSWebViewProps extends WebViewSharedProps {
|
|||
*/
|
||||
allowsLinkPreview?: boolean;
|
||||
|
||||
/**
|
||||
* Set true if shared cookies from HTTPCookieStorage should used for every load request in the
|
||||
* `RNCWKWebView`. The default value is `false`.
|
||||
* @platform ios
|
||||
*/
|
||||
sharedCookiesEnabled?: boolean;
|
||||
|
||||
/**
|
||||
* A Boolean value that determines whether scrolling is disabled in a particular direction.
|
||||
* The default value is `true`.
|
||||
* @platform ios
|
||||
*/
|
||||
directionalLockEnabled?: boolean;
|
||||
|
||||
}
|
||||
|
||||
export interface AndroidWebViewProps extends WebViewSharedProps {
|
||||
|
|
Loading…
Reference in New Issue