Webpage cookies are not detected by UIWebView - ios

I am developing iOS app that loads a webpage using UIWebView
The web page sets four cookies:
Two for Google Analytics, _ga and _gat
One for my web application unique vistors counter
One for my webpage to detect whether user has voted or not.
If this cookie available then display the poll results.
From Firefox's Storage Inspector I see all my cookies as expected, see screenshot:
However, from iOS I printed NSHTTPCookieStorage.sharedHTTPCookieStorage().cookies from inside webViewDidFinishLoad and there is only two of four expected cookies, also iOS users can vote as many times as they wanted because cookies are not detected (or not stored in iOS device):
if let cookies = NSHTTPCookieStorage.sharedHTTPCookieStorage().cookies {
for c in cookies {
print("*******************")
print("name: \(c.name)")
print("domain: \(c.domain)")
print("value: \(c.value)")
print("path: \(c.path)")
print("expiresDate: \(c.expiresDate)")
}
}
Why my iOS app does not detect my custom cookies and only detects my Google Analytics ones?
NOTE 1: I have also added this code to my app:
func applicationDidBecomeActive(application: UIApplication) {
NSHTTPCookieStorage.sharedHTTPCookieStorage().cookieAcceptPolicy = NSHTTPCookieAcceptPolicy.Always
}
NOTE 2: My backend is SharePoint web application

A few ideas:
The device's Safari "Block Cookies" settings override any changes to the cookieAcceptPolicy. The default policy of this setting on the device is "Allow from Websites I Visit," which depending on your iOS device's version, allows third-party cookies. Testing with iOS 9.3.x shows that third party cookies are persisted in a UIWebView with the default settings, but do not persist with the settings "Allow from Current Website Only" or "Always Block."
Check if the device persists your cookie with the different Safari cookie settings.
Additionally, does your cookie have an expiration date set? I've found that cookies without an expiration date set are treated as session cookies in a UIWebView, which only persist with the lifecycle of the web view that received it.

Related

iOS - WKWebView - Caching the previous state of the application during subsequent app launches

We have an iOS application which uses WkWebView to load a web application on Apple iPod's. It supports auto-login feature without having user to manually enter the credentials. We use a POST html form submission logic with credentials to simulate the auto-login.
The web application has a timeout for 15 mins and after that, uses will be logged out and redirected to the login screen and a message called "Time out" will be displayed on the login screen.
The problem we are seeing is, whenever user launches the app freshly (which is not running at that moment either in background/foreground), the expectation is the Form submission will be loaded as HTML on the webview and either user will login (if credentials are correct) (or) user will be redirected to login screen (with Invalid credentials message).
webview.loadHTMLString(html, baseURL: myURL)
But in this case, user is redirected to login screen with a message "Time Out" (Which is the previous state of the app). User tried to kill the app (double tap home button and swipe up) and re-launch app and after 2-3 attempts, he is successfully getting authenticated and going to home screen. For all the first 2-3 attempts, he is seeing "Time Out" message which is not expected.
Is WKWebView caching the page for some reason (or) iOS app is doing something wrong? Any suggestions on how to debug this will be greatly appreciated.
Note: Our business doesn't want to clear the cache as its taking ~20secs to load without cache every-time. Hence we cache the application.
You can always just test clearing all the WebView data and see if it helps. Try the code below in deinit{} of the ViewController or where you clean up after the app if being closed.
Code below will delete all the data associated with the web session that happened.
for cookie in HTTPCookieStorage.shared.cookies ?? [] {
HTTPCookieStorage.shared.deleteCookie(cookie)
}
URLCache.shared.removeAllCachedResponses()
WKWebsiteDataStore.default().removeData(
ofTypes: WKWebsiteDataStore.allWebsiteDataTypes(),
modifiedSince: Date(timeIntervalSince1970: 0),
completionHandler:{})

iOS - Enable Private Browsing in WebView

I want to show private browsing mode like safari with the help of UIWebView. I want to show the same UI as Safari has for private browsing. Screenshot attached.
I have tried to use web view configuration to nonPersistent for websiteDataStore. But it will only help to not store the data.
According to the NSHTTPCookieStorage docs, cookies are not shared
between applications:
Yes, UIWebView does have the private browsing mode by default. The
Cookie data is accessible by the App only.
NSHTTPCookie's singleton instance stores the Cookie information of
the UIWebView. You may need to use deleteCookie: method to clear the
cached data
I totally agree with #Scriptable For UI like Safari you need to
design as per your requirements

Sync cookies in multiple WKWebViews on iOS 9

I am using 2 ViewControllers with 2 WKWebViews.
The WebViews use a shared WKWebViewConfiguration.
extension WKWebViewConfiguration {
static var Shared : WKWebViewConfiguration{
if sharedConfiguration == nil{
sharedConfiguration = WKWebViewConfiguration()
sharedConfiguration.websiteDataStore = WKWebsiteDataStore.default()
sharedConfiguration.processPool = WKProcessPool()
}
return sharedConfiguration
}
private static var sharedConfiguration : WKWebViewConfiguration!
}
I am passing this on each webView and from what I read this should be the solution for shared Cookies.
But because I am doing a login though the webContent I want to have the webViews SYNCHED if the user is logged in or not.
The problem happens when the user logs in. The steps that I follow are the :
1) I have identify the host and the path, and checking the navigationAction.request.url.host and navigationAction.request.url.path
when the user makes a request, and the request happens ONLY if the credentials are correct (So I know the correct host and path) I create a bool var that indicates that the users has logged in
2) After the WebView didFinish : FINISH , I call a func that reloads the webViews that have to get refreshed but the WebViews are not acting like they have the cookies.
3) after some seconds(different everytime) ,adding manual the code .reload() the web views in each preview , the webViews are synched.
I am working on iOS 9 since these are the requirements.
It looks that the cookies are asynced, and eventually they arrive to the shared processPool or websiteDataStore from my understanding.
Anyone have a solid solution?
You don't need to share same web configuration, you just need to share processPool and KWebsiteDataStore.default() after creating each webview configuration. To verify you can check cookies from Safari developer tool.
As #PS mentioned no workaround is working for him to sync cookies. I also encounter the same problem. but I tried some unexpected things to fix this issue and that is work 100%
Cookie sync takes some time to sync with cookie store for wkwebview. so my fix is just made dummy web request that will sync cookie on app start and after that, wherever you have to use your sign In or Sign Out call you can use without making any further modification.

ios app open safari in background

I have an app that logs you in via opening safari and redirecting you back to the app - however on "Log out" I need to open safari in order to log you out - is there a way to do this in the background instead?
For Log in:
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:[DataService loginURL]]];
However, I would like to not have to do the same for Logout - and simply get safari to run in the background or something similar. The problem is that the cookies are saved, and I need to get rid of them. Can I get safari to open a website without having to open Safari through the application?
Can you open Safari in the background? I'm pretty certain that the answer to that is no. In any case, if your main concern is to delete the cookies then you may not get the chance - the user could just kill the app, and the cookies would sit in Safari.
Is it an option to use a UIWebView or WKWebView to perform authentication? So rather than taking them off to Safari, the user would see the browser content actually inside the app.
That might improve the user experience, and you'd get a lot more control. For example, you could point the web view to your log out url when the time came for it. That might save you some cookie hassles too.
Besides which, I think openURL: is now deprecated because it was involved in some shenanigans.

Why is SFSafariWebViewController not sharing cookies with Safari properly?

I created an incredibly basic app which includes a SFSafariViewController pointing at the URL http://www.w3schools.com/js/js_cookies.asp . This is a test website for reading and writing cookies.
I then loaded the same website into Mobile Safari, and added one cookie. I switched to my app, read the cookie, it's there. I go back to Safari, add another cookie, go back to my app, but the second cookie hasn't appeared. I refresh the pages, no difference. Go back to Safari and read the cookies, they are both read successfully.
Is there anything I need to do between apps in order for the cookies to be written and read properly?
A user on the Apple Dev Forums suggested that it might only work for "persisted cookies" not "session cookies". I wasn't setting an expiry date on my cookies. I changed that by getting a time in the future:
const expireTime = new Date(Date.now() + 1000 * 60 * 60 * 24).toGMTString();
And then setting it in the header:
"Set-Cookie":`query=${uri.query}; path=/; expires=${expireTime}`
And now the cookie value appears in SFSafariViewController.
You could enforce the SFSarfariViewController to dismiss when the app closes. This would ensure the webpage gets refreshed along with any new cookies.
In ViewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(shouldDismiss:) name:UIApplicationDidEnterBackgroundNotification object:nil];
then:
- (void)shouldDismiss:(NSNotification*)notification {
[self.safariViewContollerName dismissViewControllerAnimated:YES completion:nil]
}
Hope this helps,
Liam
As Apple's document said:
The SFSafariViewController class provides a standard interface for browsing the web. The view controller includes Safari features such as Reader, AutoFill, Fraudulent Website Detection, and content blocking. It shares cookies and other website data with Safari. The user's activity and interaction with SFSafariViewController are not visible to your app, which cannot access AutoFill data, browsing history, or website data. You do not need to secure data between your app and Safari.
By default it's shares cookies and other website data with Safari. You don't have to do anything.

Resources