Reputation: 24375
I'm building a basic iOS app with Xcode that mainly just contains a webview with my web app inside.
I was wondering if there was a decent way to save the users username to the devices storage when logging in so that it can be automatically entered when opening the app next time. Since the app is a webview, I don't believe there is a way to keep the user logged in (like other major apps do, such as Facebook), so I think that auto filling the username will be beneficial for them.
I found this question and answer that could possibly solve my problem, although it's in good ol' Objective C.
My current attempt, that does absolutely nothing:
let savedUsername = "testusername"
let loadUsernameJS = "document.getElementById(\"mainLoginUsername\").value = " + savedUsername + ";"
self.Webview.stringByEvaluatingJavaScriptFromString(loadUsernameJS)
Is this a possibility with Swift?
Upvotes: 1
Views: 4556
Reputation: 6701
for storing the password you should use the keychain, specifically web credentials. if done right, this will allow your app to use any existing keychain entries entered via Safari and will also allow Safari to access the password if saved via your app.
Code for setting and retrieving provided below:
private let domain = "www.youdomain.com"
func saveWebCredentials(username: String, password: String, completion: Bool -> Void) {
SecAddSharedWebCredential(domain, username, password) { error in
guard error == nil else { print("error saving credentials: \(error)"); return completion(false) }
completion(true)
}
}
func getExistingWebCredentials(completion: ((String, String)?, error: String?) -> Void) {
SecRequestSharedWebCredential(domain, nil) { credentials, error in
// make sure we got the credentials array back
guard let credentials = credentials else { return completion(nil, error: String(CFErrorCopyDescription(error))) }
// make sure there is at least one credential
let count = CFArrayGetCount(credentials)
guard count > 0 else { return completion(nil, error: "no credentials stored") }
// extract the username and password from the credentials dict
let credentialDict = unsafeBitCast(CFArrayGetValueAtIndex(credentials, 0), CFDictionaryRef.self)
let username = CFDictionaryGetValue(credentialDict, unsafeBitCast(kSecAttrAccount, UnsafePointer.self))
let password = CFDictionaryGetValue(credentialDict, unsafeBitCast(kSecSharedPassword, UnsafePointer.self))
// return via completion block
completion((String(unsafeBitCast(username, CFStringRef.self)), String(unsafeBitCast(password, CFStringRef.self))), error: nil)
}
}
which is used like this:
// save the credentials
saveWebCredentials("hello", password: "world", completion: { success in
// retrieve the credentials
getExistingWebCredentials { credentials, error in
guard let credentials = credentials else { print("Error: \(error)"); return }
print("got username: \(credentials.0) password: \(credentials.1)")
}
})
UPDATE
Recommend switching to using a WKWebView so you can easily pull out the response headers. Here is boilerplate code:
import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let webView = WKWebView(frame: self.view.bounds)
webView.navigationDelegate = self
self.view.addSubview(webView)
webView.loadRequest(NSURLRequest(URL: NSURL(string: "https://www.google.com")!))
}
func webView(webView: WKWebView, decidePolicyForNavigationResponse navigationResponse: WKNavigationResponse, decisionHandler: (WKNavigationResponsePolicy) -> Void) {
// make sure the response is a NSHTTPURLResponse
guard let response = navigationResponse.response as? NSHTTPURLResponse else { return decisionHandler(.Allow) }
// get the response headers
let headers = response.allHeaderFields
print("got headers: \(headers)")
// allow the request to continue
decisionHandler(.Allow);
}
}
Upvotes: 5
Reputation: 136
You are not passing a string to JavaScript, you should encapsulate the variable in additional quotes
let loadUsernameJS = "document.getElementById(\"mainLoginUsername\").value = \"" + savedUsername + "\";"
or
let loadUsernameJS = "document.getElementById('mainLoginUsername').value = '" + savedUsername + "';"
Upvotes: 0
Reputation: 1341
You code is not working because you did not wrap savedUsername
with quotes.
You should have this instead:
let loadUsernameJS = "document.getElementById(\"mainLoginUsername\").value = \"\(savedUsername)\";"
Also, this library might help you.
Upvotes: 1