NSHTTPCookieStorage state not saved on app exit. Any definitive knowledge/documentation out there?

Objective CIosCookiesNshttpcookie

Objective C Problem Overview


Struggling with this problem and loath to implement a custom cookie management system.

It appears some hidden level of iOS's implementation of HTTP fails to manage sessionless cookies properly. Any time an HTTP response sets or deletes a cookie, immediate inspection of NSHTTPCookieStorage cookies will yield the expected results and indicate the correct sessionOnly value.

But if the app quits soon after a response updates cookies, upon relaunch those sessionOnly=FALSE cookies will be reverted to some previous state and the most recent updates lost.

Whether the cookies are set/deleted by a response header or NSHTTPCookieStorage setCookie: makes no difference.

Some caching/syncing voodoo must be going on behind the scenes. The time it takes for the cookie to become persistent can be up to 5 seconds.

ANYONE out there who has or can point to some definitive explanation of this behavior? Is it a bug, plain and simple? Or some undocumented feature whose purpose I can't comprehend?

Some code you can use to reproduce:

- (void)applicationDidBecomeActive:(UIApplication *)application
{

    [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];

    NSHTTPCookie *cookie;
    for (cookie in [NSHTTPCookieStorage sharedHTTPCookieStorage].cookies) {
        NSLog(@"%@=%@", cookie.name, cookie.value);
    }

    NSMutableDictionary *cookieProperties = [NSMutableDictionary dictionary];
    [cookieProperties setObject:@"testCookie" forKey:NSHTTPCookieName];
    [cookieProperties setObject:[NSString stringWithFormat:@"%f", [[NSDate date] timeIntervalSince1970]] forKey:NSHTTPCookieValue];
    [cookieProperties setObject:@"www.example.com" forKey:NSHTTPCookieDomain];
    [cookieProperties setObject:@"www.example.com" forKey:NSHTTPCookieOriginURL];
    [cookieProperties setObject:@"/" forKey:NSHTTPCookiePath];
    [cookieProperties setObject:@"0" forKey:NSHTTPCookieVersion];

    // set expiration to one month from now
    [cookieProperties setObject:[[NSDate date] dateByAddingTimeInterval:2629743] forKey:NSHTTPCookieExpires];
    
    cookie = [NSHTTPCookie cookieWithProperties:cookieProperties];
    [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];

}

This code should output a new value on every launch. Instead you will see that if you quit the app quickly the value is unchanged.

Some possibly related stack overflow questions:

https://stackoverflow.com/questions/4623811/iphone-nshttpcookiestorage-avaible-on-app-reopen

https://stackoverflow.com/questions/2662530/iphone-nshttpcookie-is-not-saved-across-app-restarts

https://stackoverflow.com/questions/5747012/nshttpcookies-refuse-to-be-deleted

https://stackoverflow.com/questions/5070446/deleted-nshttpcookie-returns-if-app-is-terminated

Objective C Solutions


Solution 1 - Objective C

I think the answer lies in one of the SO posts linked to in your question:

> I made a sample project to reproduce this issue — and found that it > would only occur when the app receives a SIGKILL signal, like when the > debugger is stopped from within Xcode. In my experiments, unhandled > exceptions, crashes, exit() and abort() don't cause > NSHTPPCookieStorage to loose data. > > As this looks like a debugging-only issue (it only occurs when using > the debugger), I closed the radar I filled previously.

You can test this by restarting the phone normally and observing that all changes to NSHTTPCookieStorage are correctly persisted and reloaded.

Solution 2 - Objective C

I also got the same problem but i found a solution. I saved the cookies as it get created by the browser and then recreate them as app restarts.

  1. Save cookie when they get created by uiwebview.

    NSMutableArray *cookieArray = [[NSMutableArray alloc] init]; for (NSHTTPCookie *cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]) { [cookieArray addObject:cookie.name]; NSMutableDictionary *cookieProperties = [NSMutableDictionary dictionary]; [cookieProperties setObject:cookie.name forKey:NSHTTPCookieName]; [cookieProperties setObject:cookie.value forKey:NSHTTPCookieValue]; [cookieProperties setObject:cookie.domain forKey:NSHTTPCookieDomain]; [cookieProperties setObject:cookie.path forKey:NSHTTPCookiePath]; [cookieProperties setObject:[NSNumber numberWithInt:cookie.version] forKey:NSHTTPCookieVersion];

         [cookieProperties setObject:[[NSDate date] dateByAddingTimeInterval:2629743] forKey:NSHTTPCookieExpires];
         
         [[NSUserDefaults standardUserDefaults] setValue:cookieProperties forKey:cookie.name];
         [[NSUserDefaults standardUserDefaults] synchronize];
         
     }
     
     [[NSUserDefaults standardUserDefaults] setValue:cookieArray forKey:@"cookieArray"];
     [[NSUserDefaults standardUserDefaults] synchronize];
    
  2. Now recreate them as app restarts:

    • (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

      NSMutableArray* cookieDictionary = [[NSUserDefaults standardUserDefaults] valueForKey:@"cookieArray"]; NSLog(@"cookie dictionary found is %@",cookieDictionary);

      for (int i=0; i < cookieDictionary.count; i++) {

        NSLog(@"cookie found is %@",[cookieDictionary objectAtIndex:i]);
        NSMutableDictionary* cookieDictionary1 = [[NSUserDefaults standardUserDefaults] valueForKey:[cookieDictionary objectAtIndex:i]];
        NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieDictionary1];
        [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
      

    }

     // other code
    

    }

thanks

Solution 3 - Objective C

Sounds like an underlying NSUserDefaults-style "synchronize" call is required. I think your best shot is managing all your app's cookies separately in the standard NSUserDefaults and synching any missing ones into the NSHTTPCookieStorage's at startup. Or see if there's some private synchronize method if you're feeling brave :)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionkballView Question on Stackoverflow
Solution 1 - Objective CNarimanView Answer on Stackoverflow
Solution 2 - Objective CKuldeep SinghView Answer on Stackoverflow
Solution 3 - Objective CZaky GermanView Answer on Stackoverflow