I know this has been answered in several related forms, but I have been twisting my brain for days trying to figure this out to no avail. I have tried every single solution I could find that seemed to be even remotely related.
I am using a WKWebView and loading the url of a website. On that website, a user will log in. In order to keep the user logged in, we need to maintain the session with a cookie. I have got this working perfectly on Android (using webview and cookies).
I need to figure the following out for iOS:
1) How to find cookie (if it already exists) and send it with the URLRequest.
2) How to make sure cookies are maintained between the app being opened and closed.
Ok, getting back to this months later :/
It was ridiculously simple. In the login page of the website I had embedded in the WKWebView, I was not clicking the 'remember me' checkbox. I went down a whole rabbit hole thinking that it had something to do with the cookie/s for the website never being saved, but I was never actually instructing it to do that.
Hope that helps anyone. My face is bruised from multiple facepalmings.
This Code Work For me -
Add this code in ViewDidLoad Method
let preferences = WKPreferences()
preferences.javaScriptEnabled = true
preferences.javaScriptCanOpenWindowsAutomatically = true
let wkUController = WKUserContentController()
let cookieScript = WKUserScript(source: "document.cookie = 'Set-Cookie: sessionId =\(Defaults[AppConstants.UD_SESSION_ID].string!)';", injectionTime: WKUserScriptInjectionTime.atDocumentStart, forMainFrameOnly: false)
wkUController.addUserScript(cookieScript)
let wkWebConfig = WKWebViewConfiguration()
wkWebConfig.userContentController = wkUController
wkWebConfig.preferences = preferences
// Adding webview
webView = WKWebView(frame: self.view.bounds, configuration: wkWebConfig)
var request = URLRequest(url: url)
request.addValue("Set-Cookie: sessionId = \(Defaults[AppConstants.UD_SESSION_ID].string!)", forHTTPHeaderField: "Cookie")
webView?.load(request)
Related
While using web view to convert my webpage to an app using Xcode the login button does not return to the designated page after login it kind of stays stuck in the login page(The behaviours works okay in a browser though)
Similar behaviour has been observed whoever there is a return to a different page
This is for making my website accessible as an iOS app using web view
I tried using this code snippet:
var backNavigation: WKNavigation?
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
if backNavigation?.isEqual(navigation) ?? false {
webView.reload()
backNavigation = nil}
The idea is to allow the application get redirected to the correct page as in the website after login or say cancellation. (The functionality works ok on the website)
I think the solution might be to Allow Arbitrary Loads to yes under app transport security settings. kindly check the link below:
Transport security has blocked a cleartext HTTP
try adding this code
let preferences = WKPreferences()
preferences.javaScriptEnabled = true
let configuration = WKWebViewConfiguration()
configuration.preferences = preferences
let webview = WKWebView(frame: .zero, configuration: configuration)
I want obtain all cookies from WKWebView. Why? I have been started a project that use web-based auth. As result, I should intercept cookies to be sure that user is logged in and for some other purposes. Another case - imagine if user logged in, and than he "kill" the app - due to some delay in storing this cookie session will be lost :(.
The problem seems to be that the cookies are cached and not saved out
to a file immediately.
(#Kemenaran from here - p.5 below)
The point where I try to catch them -
webView:decidePolicyForNavigationResponse:decisionHandler:,
func webView(webView: WKWebView, decidePolicyForNavigationResponse navigationResponse: WKNavigationResponse, decisionHandler: (WKNavigationResponsePolicy) -> Void) {
if let httpResponse = navigationResponse.response as? NSHTTPURLResponse {
if let headers = httpResponse.allHeaderFields as? [String: String], url = httpResponse.URL {
let cookies = NSHTTPCookie.cookiesWithResponseHeaderFields(headers, forURL: url {
for cookie in cookies {
NSHTTPCookieStorage.shared.set(cookie)
}
}
}
}
but not all request are navigation, so one cookie (in my case) is skipped, see details below
Few words about other option I tried...
Yes, i Know that starting from iOS 11, we can use WKHTTPCookieStore as mention here. But my project should support iOS 9+
I for 100% sure, that after 5-10 sec from login, required cookie will be saved to NSHttpCookieStorage (at least all my tests during few days confirm that)
I try to use provided observer NSHTTPCookieManagerCookiesChangedNotification, but it provide me callback only for cookies that comes within webView:decidePolicyForNavigationResponse:decisionHandler
I also try to get cookies using some JS like mentioned here and also test all suggestion from here - really great article by the way. Result - negative
I also found this radar bug, and this SO question, and Sample project, but I want to prevent even this case. (described in this post applicable not only for remove but and for save) Also this situation true and when user kill the app, so case when user login, kill app and relaunch, may be present. And preventing this (simply by checking NSHttpCookieStorage for required cookies are also not good idea, because exactly after login required cookie can be stored with some delay, so this approach requires some bool-powered solution, that looks like weird..
I also read few more SO post for some related problem, and the most usefull are
This one
Another one
One more
But still without good solution...
So, is any way exist to obtain or at least force to immediately store cookies?
I ended with simple "force-like" saving Cookie from webpage.
To get all cookie i use
stringByEvaluatingJavaScriptFromString
with JS string like document.cookie();. As result i able to receive all cookies as a string with ; separator. All i need to do - parse string, create cookie and set it to NSHttpSharedStorage
I am using URL Session to get Data from a web API and load them in a tableView.
Every thing is working fine except that whenever I get the data the first time, the data is always returned the same even if it was changed in the backend side.
The data is only returned new when I delete the application and install it again.
Any idea on how to solve this please?
If you are saying that when deleting the application your problem is solved then the issue is in caching.
To solve this either add:
URLCache.shared.removeAllCachedResponses()
or:
let config = URLSessionConfiguration.default
config.requestCachePolicy = .reloadIgnoringLocalCacheData
let session: URLSession = URLSession(configuration: config)
This will solve your problem and ignore caching so that the data will be returned new everytime.
I'm trying to update my app to work correctly with the new features of GameCenter in iOS10.
I create a new GKGameSession on device1, get a share URL, and all that works fine. I send the share URL out via a share sheet to device 2.
Device2 clicks the link, the device briefly displays 'Retrieving...' and then launches my app. Great! But, now what? Is there context information available for this URL that I can somehow access? Otherwise I have no way how to respond when the app is launched.
Previously you'd get a callback to something adhering to the GKLocalPlayerListener protocol, to the method player:didAcceptInvite:, and you could join the match that way. But with these iCloud-based messages, the player might not be even logged into GameCenter, right? This part seems to have been glossed over in the WWDC presentation.
Also, as of today (12/28/2016) there is no Apple documentation on these new methods.
Since the GKGameSessionEventListener callback session:didAddPlayer: only fires if the game is already running, to be sure you can process this callback every time requires a work around. I've tested this and it works.
When you send out an iMessage or email invite to the game, don't include the Game Session Invite URL directly in the message. Instead use a registered URL that will open your app when opened on a device on which your app is installed. Check here to see how:
Complete Tutorial on iOS Custom URL Schemes
But add a percent escaped encoding of the game invite URL as a parameter to this URL thusly (I'm assuming the registration of a url e.g. newGameRequest but it will be best to make this quite unique, or even better - though it requires more setup, try Universal Link Support as this will allow you to direct users who don't have your app installed to a webpage with a download link)
let openOverWordForPlayerChallenge = "newGameRequest://?token="
gameState.gameSession?.getShareURL { (url, error) in
guard error == nil else { return }
// No opponent so we need to issue an invite
let encodedChallengeURL = url!.absoluteString.addingPercentEncoding(withAllowedCharacters:.urlHostAllowed)
let nestedURLString = openOverWordForPlayerChallenge + encodedChallengeURL!
let nestedURL = URL(string: nestedURLString)!
}
send the URL in a message or email or WhatsApp or whatever. Then in your app delegate, add the following:
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
var success = false
if let queryString = url.query {
if let urlStringToken = queryString.removingPercentEncoding {
let token = "token="
let startIndex = urlStringToken.startIndex
let stringRange = startIndex..<urlStringToken.index(startIndex, offsetBy: token.characters.count)
let urlString = urlStringToken.replacingOccurrences(of: token, with: "", options: .literal, range: stringRange)
if let url = URL(string: urlString) {
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
success = true
}
}
}
}
return success
}
Now you can be sure the session:didAddPlayer: will be called. What's the betting this workarround is good for about 2 weeks, and they fix this in the next release of iOS showcased at WWDC 2017 ! Update: this problem hasn't been fixed - so the workaround above remains good!
I agree, the lack of documentation is frustrating. From what I can see, we have to:
add <GKGameSessionEventListener> protocol in the class' header
Then session:didAddPlayer: fires on the joining player's device after accepting an invite link.
update:
Unfortunately, I'm not surprised to hear your results. I hadn't tried all of those scenarios, but GKTurnBasedMatch had similar shortcomings. The way I got around it there was: I added a list of player statuses to match data (invited, active, quit, etc). I gave the player a view of "pending invitations." When they opened that view, I would load all of their matches and display the entries where the player was in invited state. With GKGameSession, that should work too.
Or, it might be easier if you could maintain a local list of sessions that you are aware of. Whenever the game becomes active, pull the entire list of sessions from the server and look for a new entry. The new entry would have to be the match the player just accepted by clicking the share URL.
I write this code:
#IBOutlet weak var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
let url = NSURL (string: "http://google.com");
let requestObj = NSURLRequest(URL: url!);
webView.loadRequest(requestObj);
self.view.addSubview(webView)
}
run the code, iPhone simulator display white page only but no warning error
and I change the code to:
let url = NSURL (string: "http://apple.com");
just change google to apple, then it works - simulator displayed apple site
So I put the other site url but it's same like first one, only it displays apple.com
I don't know what is wrong about this code please help me! thank you :)
You should get the error:
App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.
Find Info as the image below shows and do the steps:
1.On the last line add the +
2.Enter the name of the group: App Transport Security
3.Right click on the group and select Add Row
4.Enter Allow Arbitrary Loads
5.Set the value on the right to YES
no need this line if you have connect it from storyboard
self.view.addSubview(webView)
App Transport Security has prevented your web view from loading the page over http. You can either disable it, per William Hu's answer, or switch over to using https links (which is the recommended option).