34

I'm building an iPhone app that is just a UIWebView of an existing mobile site that has a form-based login. When I login to the mobile site on iPhone Safari, I'm prompted to save my username/password, and it's then autofilled when I go back to the site later.

I'd like to enable the same functionality in the UIWebView, but for the life of me, I can't figure out how to do it. Any ideas?


Solution

Following Michael's basic model (see accepted answer), I was able to get this done. Here's what I did:

SETTING DATA

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType; {

    //save form data
    if(navigationType == UIWebViewNavigationTypeFormSubmitted) {
    
        //grab the data from the page
        NSString *username = [self.webView stringByEvaluatingJavaScriptFromString: @"document.myForm.username.value"];
        NSString *password = [self.webView stringByEvaluatingJavaScriptFromString: @"document.myForm.password.value"];
    
        //store values locally
        [[NSUserDefaults standardUserDefaults] setObject:username forKey:@"username"];
        [SFHFKeychainUtils storeUsername:username andPassword:password forServiceName:@"MyService" updateExisting:YES error:nil];
    
    }    

}

GETTING DATA

- (void)webViewDidFinishLoad:(UIWebView *)webView{
    
    //verify view is on the login page of the site (simplified)
    NSURL *requestURL = [self.webView.request URL];
    if ([requestURL.host isEqualToString:@"www.mydomain.com"]) {

        //check for stored login credentials
        NSString *username = [[NSUserDefaults standardUserDefaults] objectForKey:@"username"];
    
        if (username.length != 0 ) {
        
            //create js strings
            NSString *loadUsernameJS = [NSString stringWithFormat:@"document.myForm.username.value ='%@'", username];
            NSString *password = [SFHFKeychainUtils getPasswordForUsername: username andServiceName:@"MyService" error:nil];
            if (password.length == 0 ) password = @"";
            NSString *loadPasswordJS = [NSString stringWithFormat:@"document.myForm.password.value ='%@'", password];
        
            //autofill the form
            [self.webView stringByEvaluatingJavaScriptFromString: loadUsernameJS];
            [self.webView stringByEvaluatingJavaScriptFromString: loadPasswordJS];
        
        }
    }   
}

Note that I'm using Buzz Andersen's awesome SFHFKeychainUtils package to store sensitive data to the iOs Keychain.

In order to get SFHFKeychainUtils working, you need to do a few things:

  1. Add SFHFKeychainUtils.h and SFHFKeychainUtils.m to your project
  2. Add the Security.framework to your project
  3. #import <Security/Security.h> and #import "SFHFKeychainUtils.h"
Community
  • 1
  • 1
byron
  • 984
  • 3
  • 14
  • 26
  • Is this code only work for the specific website you are trying to load? I have been trying to figure this out for my app as well; but my problem is a little more complicated because I have about 5 different links in my app where I would like it to save the passwords. I attempted what you are doing above, but I cannot get any of website to print out the username that you receive in the webView delegate method. Any suggestions? – RyanG May 18 '11 at 13:12
  • @ryan, have you verified that you're actually storing the data correctly on the initial form submit on each of your forms? also, double check the form names on retrieval...i had a hard-to-see misspelling that caused me some headaches. – byron May 23 '11 at 00:17
  • 3
    Thanks so much for posting your solution (+1)! I had to use `@"document.getElementById('username').value"` and `@"document.getElementById('password').value"` to get it to work. Hope this helps! – Stunner Mar 17 '12 at 22:15
  • Is this a very serious vulnerability if every app can retrieve your username/password when you log in every website with the embedded UIWebview? – NeoWang Aug 24 '14 at 08:04
  • it is a bit cumbersome to implement at times, and of course it is not possible to find a general way to apply this to any website, but still this can save your life in some specific situations, like it did for me. thanks – Fabio Napodano Jun 30 '15 at 11:02
  • @byron you can always post answer to your own question. – rptwsthi Apr 06 '16 at 16:10
  • 1
    @rptwsthi I know. I wanted to give Michael the credit for the answer since he gave me the path to the eventual solution. – byron Apr 11 '16 at 00:33
  • @byron Good thinking! Appreciate it :-). – rptwsthi Apr 12 '16 at 05:56

1 Answers1

4

From my looking I don't think there is an easy way to do it. Here is an idea of what might work though:

  • create your uiwebview
  • create a nsurlrequest
  • after your webview delegate page loaded function fires look in the request's http body
  • find the form for login (regex for common login forms?)
  • retrieve give the user the option to save it and then retrieve later
Michael Dillon
  • 1,037
  • 6
  • 16
  • 1
    Michael, thanks. I followed this basic model and was able to make it work. I'll update with more details as soon as I test a bit more. – byron Jan 24 '11 at 04:11
  • Nice perseverance! I'm not sure how you are saving the user's data, but definitely check the apple docs for a suggestion / requirement on how to do that. I'm not that familiar with that. – Michael Dillon Jan 24 '11 at 14:33
  • what if I need this for every webpage, which user visit? Can I still show the suggestion according to previously entered value. for example if user visit gmail and enter some email id, next time he visit gmail page again, how can I show him previously entered email id as suggestion? @byron – Suryakant Sharma Mar 16 '16 at 07:38