I need to read cookies from Safari app to inside the my application. So is there any way to do it by using any SFSafariViewController inside the our application. Please help me on it.
Thanks in advance.
Edited
I have a one URL https://example.com/abc123 and when I open this URL in Safari application it sets some cookies automatically. Now I have to open my application and read those cookies by passing the domain (https://example.com).
NSHTTPCookieStorage *sharedHTTPCookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSArray *cookies = [sharedHTTPCookieStorage cookiesForURL:[NSURL URLWithString:#"https://wwwexample.com"]];
Is it possible to read cookies?
According to the documentation, there's no way you can read cookies using SFSafariViewController. You need to use WKWebView or UIWebView for that. For using UIWebView to retrieve cookies, you can use it delegate method:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSHTTPCookieStorage *cookiesStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSURLRequest *urlReq = webView.request;
NSURL *url = urlReq.URL;
NSArray *cookies = [cookiesStorage [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:url]];
}
Related
We are using WKWebViews in our native iPhone application, on a website that allows login and stores the session information in cookies.
We tried to properly mange web cookies but we have some problems when we kill and reopen the app.
Preamble: the app manages a web login toward two WKWebViews (let's call them WKW_A and WKW_B) in two different sections.
Use case 1: we open the app, the app loads WKW_A, and the user fill in the credentials to login on the website. At this point we stores the related cookies. The user then opens a section of the app loading WKW_B . Here we load the above mentioned cookies. What we see is that the website bring us to the expected screen without asking user credentials i.e. in WKW_B cookies are properly sent to the website.
Use case 2: we open the app, the app loads WKW_A, and the user fill in the credentials to login on the website. At this point the app stores the related cookies. The user kills the app.
The user opens the app again, goes directly to the WKW_B section . Here the app loads the cookies mentioned above. What we see is that the website is asking the user to login again. i.e. it looks like there is something wrong with cookies loaded by WKW_B and sent to the website.
Briefly, cookies management looks like it is working only when we don’t kill the app. We tested the flow and the cookies are stored and reloaded correctly when we kill and reopen the app.
Below some reference code describing the way we manage the store/loading of the Cookies.
a) We’ve added this line in the applicationDidBecomeActive of AppDelegate
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
b) This is the WKWebView loading function in the ViewController managing the WKW_A.
- (void)loadWebView {
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
[config setWebsiteDataStore:[WKWebsiteDataStore defaultDataStore]];
self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
[self.webView setCustomUserAgent:#"Mozilla/5.0 (iPhone; CPU iPhone OS 13_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/79.0.3945.73 Mobile/15E148 Safari/604.1"];
[self.webView setNavigationDelegate:self];
[self.webView evaluateJavaScript:#"window.open = function(open) { return function (url, name, features) { window.location.href = url; return window; }; } (window.open);" completionHandler:nil];
[self.webViewContainer addSubview:self.webView];
[self.webView loadRequest:[NSURLRequest requestWithURL:self.loginURL]];
}
c) This is the WKWebView loading function in the ViewController managing the WKW_B.
- (void)loadWebView {
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
[config setWebsiteDataStore:[WKWebsiteDataStore defaultDataStore]];
self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
[self.webView setCustomUserAgent:#"Mozilla/5.0 (iPhone; CPU iPhone OS 13_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/79.0.3945.73 Mobile/15E148 Safari/604.1"];
[self.webView setNavigationDelegate:self];
[self.webView evaluateJavaScript:#"window.open = function(open) { return function (url, name, features) { window.location.href = url; return window; }; } (window.open);" completionHandler:nil];
[self.webViewContainer addSubview:self.webView];
NSMutableURLRequest *sRequest = [NSMutableURLRequest requestWithURL:self.loginURL];
[WKWebsiteDataStore.defaultDataStore.httpCookieStore getAllCookies:^(NSArray<NSHTTPCookie *> *aCookies) {
NSDictionary *sCookieHeaderFields = [NSHTTPCookie requestHeaderFieldsWithCookies:aCookies];
[sRequest setAllHTTPHeaderFields:sCookieHeaderFields];
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:#"cookie_array"];
NSArray *myArrayCookies = [NSKeyedUnarchiver unarchiveObjectWithData:data];
for (int i=0;i< myArrayCookies.count;i++) {
[WKWebsiteDataStore.defaultDataStore.httpCookieStore setCookie:[myArrayCookies objectAtIndex:i] completionHandler:^{
}];
}
[sRequest setAllHTTPHeaderFields:[NSHTTPCookie requestHeaderFieldsWithCookies:myArrayCookies]];
[self.webView loadRequest:sRequest];
}];
}
d) This is the function to load the cookies inside the decidePolicyForNavigationResponse function in the ViewController managing the WKW_B
[WKWebsiteDataStore.defaultDataStore.httpCookieStore getAllCookies:^(NSArray<NSHTTPCookie *> *aCookies) {
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:aCookies];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:#"cookie_array"];
[[NSUserDefaults standardUserDefaults] synchronize];
for (int i=0;i< aCookies.count;i++) {
[WKWebsiteDataStore.defaultDataStore.httpCookieStore setCookie:[aCookies objectAtIndex:i] completionHandler:^{
}];
}
}];
e) This is the function that we put in the applicationDidEnterBackground function of AppDelegate to store the cookies before kill the app
[WKWebsiteDataStore.defaultDataStore.httpCookieStore getAllCookies:^(NSArray<NSHTTPCookie *> *aCookies) {
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:aCookies];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:#"cookie_array"];
[[NSUserDefaults standardUserDefaults] synchronize];
}];
We think that could be a problem of something behind the WKWebView configuration that can be lost when we kill the app.
We were thinking also to store directly the WKWebView in the UserDefaults instead of the list of cookies but it is impossible.
How could we do to store the WKWebView status for re-uploading after the reopen of the app?
I am migrating from UIWebView to WKWebView and facing problem in cookies management. As app need to support iOS 10 I am not adding cookies through WKHTTPCookieStore instead, I am following the below code:
- (void)loadURL:(NSString *)url
{
NSMutableURLRequest * req = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSArray* cookies = [storage cookiesForURL:[NSURL URLWithString:url]];
NSMutableString *cookieStr = [NSMutableString string];
for (NSHTTPCookie *cookie in cookies) {
if (cookieStr.length) {
[cookieStr appendString:#"; "];
}
[cookieStr appendFormat:#"%#=%#", cookie.name, cookie.value];
}
NSLog(#"Cookie: %#",cookieStr);
[req addValue:cookieStr forHTTPHeaderField:#"Cookie"];
NSMutableString *cookieStrAfterDocLoad = [NSMutableString string];
for (NSHTTPCookie *cookie in cookies) {
[cookieStrAfterDocLoad appendFormat:#"document.cookie = '%#=%#';", cookie.name, cookie.value];
}
WKUserScript *userScript = [[WKUserScript alloc] initWithSource: cookieStrAfterDocLoad
injectionTime: WKUserScriptInjectionTimeAtDocumentStart
forMainFrameOnly:NO];
[self.wkWebView.configuration.userContentController addUserScript:userScript];
[self.wkWebView loadRequest:req];
}
I need to add the cookies after the document load to maintain the session for internal navigation.
This is not the correct way as the new cookies may be added or old may be modified at the time of page load. This needs to be done in many other controllers.
My question is how can I know if the cookies were added at every for loadRequst in UIWebview, or is there any other correct way to handle this situation in WKWebview as some webpage load might not need the cookies?
Is this the correct way to add cookies for every loadRequest?
I am working on an app that needs to download a web page from our iis based website. If I am logged into the domain for my wireless connection on my iPad the site I am connecting to seems to use that login for my credentials. However, if I am not connected to the domain or I am connected as a user who does not have access to the page it does fire the didReceiveAuthenticationChallenge, otherwise it does not. If I use Safari to connect to the same page it asks for authentication regardless. I am hoping to get the app to authenticate each time. Any help would be appreciated.
Code to request page :
NSError *error = nil;
// assign the cmh url from user prefs
NSURL *url = [NSURL URLWithString:cmhUrl];
// Put that URL into an NSURLRequest
NSURLRequest *req = [NSURLRequest requestWithURL:url];
[req setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
// Create a connection that will exchange this request for data from the URL
connection = [[NSURLConnection alloc] initWithRequest:req
delegate:self
startImmediately:YES];
It looks like when you authenticate in Safari the auth-token is saved in NSHTTPCookieStorage. And when you making request from the code, all cookies from the storage are added to the header, so there is no need to ask for a token again.
Try to clear the storage before you making the request:
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (NSHTTPCookie *cookie in cookieStorage.cookies) {
[cookieStorage deleteCookie:cookie];
}
Hope this helps.
Simple question that would be fantastic if somebody could answer.
I have a simple UIWebView used to log in to a certain service. However, when I reload the application, it stays logged in. What I need to be able to do is create the UIWebView like new each and every time the application starts. I'm not sure if there is an option somewhere in the interface builder, or perhaps a method of some kind I can place in the method that gets called when the app terminates, so that it releases the WebView or something.
What you need to do is not save the cache of the UIwebView. You can do this with a simple code like:
NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil];
[NSURLCache setSharedURLCache:sharedCache];
Place the code in the UIwebview code.
Or in ApplicationDidFinishLoad (or something like that, haha) you can remove the cache with:
[[NSURLCache sharedURLCache] removeAllCachedResponses];
Edit:
You've asked something in the comments. You can do something like the code below:
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://www.google.com"]];
UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(0.f, 0.f, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - 20.f)];
[webView setAutoresizingMask:(UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth)];
//No Cache\\
NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil];
[NSURLCache setSharedURLCache:sharedCache];
//No Cache\\
webView.delegate = self;
[webView loadRequest:request];
[self.view addSubview:webView];
Ok,
Remove a specific request
[[NSURLCache sharedURLCache] removeCachedResponseForRequest:NSURLRequest];
Or delete al cookies from the UIWebView
for(NSHTTPCookie *cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]) {
if([[cookie domain] isEqualToString:someNSStringUrlDomain]) {
[[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:cookie];
}
}
Good luck,
Nathan
My answer will be in multiple parts to cover multiple bases.
1 - it's possible the app has a cookie set for the user so even when launching a new app the old cookie remains with the login details and therefore you will still be logged in.
To kill the cookies, try this before the uiwebview loads (ie in the viewwillload or other method)
NSHTTPCookie *cookie;
NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (cookie in [storage cookies]) {
[storage deleteCookie:cookie];
}
2 - Is this on a multithreaded phone (iOS4 or newer on a 3GS or newer)? Are you sure the app is terminating as opposed to just going to background? If this is the case and you are just launching the previous app (where you were still logged in) you will need to hook into the - (void)applicationDidBecomeActive:(UIApplication *)application and remove the old web view and add a new one.
I am trying to develop a custom movie player in iPhone using AVPlayer. But I am just wondering that if the m3u8 url response sends back an authentication challenge, how do I handle that. I do know about didReceiveAuthenticationChallenge and NSURLConnection but no clue about how does it work in this context.
Any help is appreciated.
-Soumya
We've made a different approach to a similar issue as we had to comply with redirects in HTTP, too. We did the authentication in cookies and set them for a whole domain:
NSDictionary *properties = [NSDictionary dictionaryWithObjectsAndKeys:
kAuthCookieDomain, NSHTTPCookieDomain,
kAuthCookiePath, NSHTTPCookiePath,
kAuthCookieName, NSHTTPCookieName,
kAuthCookieValue, NSHTTPCookieValue,
kAuthCookieDiscard, NSHTTPCookieDiscard,
nil];
NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:properties];
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];