Are cookies in UIWebView accepted?
Asked Answered
R

8

18

I have to question for you.

1 : I'm using UIWebViews in my iPhone App. I wan't the users be able to add comments in the news. But, to comment they have to log-in.

If not, how can I accept cookies in UIWebViews ?

2 : Are the cookies created in on UIWebView available in others UIWebView in an other View ?

Ex : I have my LoginViewController, with an embedded UIWebView, where my user can login/logout. If they log-in in this view, the cookie will be still available in the CommentViewController ?

If not, how can I make this possible ?

Thanks in advance !

Rachmaninoff answered 23/9, 2014 at 22:23 Comment(0)
M
45

The UIWebView will automatically store the cookies in the [NSHTTPCookieStorage sharedHTTPCookieStorage] collection, and should be available in all other UIWebViews within your app, during the same app launch. However the UIWebView class does not automatically store cookies for the pages that are loaded between app launches. You need to manually store cookies when the app is moved into the background and reload the values when the app is brought back into the foreground.

Place the following code in your AppDelegate class:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    //Other existing code

    [self loadHTTPCookies];
    return YES;
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    //Other existing code

    [self saveHTTPCookies];
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    [self loadHTTPCookies];
}

- (void)applicationWillTerminate:(UIApplication *)application
{
    //Other existing code
    [self saveHTTPCookies];
}

-(void)loadHTTPCookies
{
    NSMutableArray* cookieDictionary = [[NSUserDefaults standardUserDefaults] valueForKey:@"cookieArray"];

    for (int i=0; i < cookieDictionary.count; i++)
    {
        NSMutableDictionary* cookieDictionary1 = [[NSUserDefaults standardUserDefaults] valueForKey:[cookieDictionary objectAtIndex:i]];
        NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieDictionary1];
        [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
    }
}

-(void)saveHTTPCookies
{
    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 numberWithUnsignedInteger: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];
}
Mickiemickle answered 23/9, 2014 at 23:15 Comment(3)
@jan it should work, since this code stores the entire cookie collection, regardless of domain.Mickiemickle
Is there a way to implement this solution via php?Poachy
is it working with ios10 and onwards? i am unable to get cookies in ios11.Dibranchiate
I
11

Expanding the other answers:

Since NSHTTPCookieStorage cookies can be archived using NSKeyedArchiver, you don't need to extract every single cookie property yourself. Furthermore, you will want to remove the NSUserDefaults cookie property, when there are no cookies to store.

So you can simplify your cookie storing/loading to this extension:

static NSString *const kCookiesKey = @"cookies";

@implementation NSHTTPCookieStorage (Persistence)

- (void)saveToUserDefaults
{
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    if (self.cookies != nil && self.cookies.count > 0) {
        NSData *cookieData = [NSKeyedArchiver archivedDataWithRootObject:self.cookies];
        [userDefaults setObject:cookieData forKey:kCookiesKey];
    } else {
        [userDefaults removeObjectForKey:kCookiesKey];
    }
    [userDefaults synchronize];
}

- (void)loadFromUserDefaults
{
    NSData *cookieData = [[NSUserDefaults standardUserDefaults] objectForKey:kCookiesKey];
    if (cookieData != nil) {
        NSArray *cookies = [NSKeyedUnarchiver unarchiveObjectWithData:cookieData];
        for (NSHTTPCookie *cookie in cookies) {
            [self setCookie:cookie];
        }
    }
}

@end

Then just use [[NSHTTPCookieStorage sharedHTTPCookieStorage] loadFromUserDefaults]; and [[NSHTTPCookieStorage sharedHTTPCookieStorage] saveToUserDefaults]; in your AppDelegate as mentioned above.

Imbalance answered 27/10, 2015 at 13:4 Comment(0)
E
8

swift 3 clear version

func saveCookies() {
    guard let cookies = HTTPCookieStorage.shared.cookies else {
        return
    }
    let array = cookies.flatMap { (cookie) -> [HTTPCookiePropertyKey: Any]? in
        cookie.properties
    }
    UserDefaults.standard.set(array, forKey: "cookies")
    UserDefaults.standard.synchronize()
}

func loadCookies() {
    guard let cookies = UserDefaults.standard.value(forKey: "cookies") as? [[HTTPCookiePropertyKey: Any]] else {
        return
    }
    cookies.forEach { (cookie) in
        guard let cookie = HTTPCookie.init(properties: cookie) else {
            return
        }
        HTTPCookieStorage.shared.setCookie(cookie)
    }
}
Epa answered 11/1, 2017 at 9:31 Comment(0)
G
8

From all the great other answers to this question I compiled a handy extension on UserDefaults that shortens the necessary code.

UserDefaults Extension for Swift 3

extension UserDefaults {

    /// A dictionary of properties representing a cookie.
    typealias CookieProperties = [HTTPCookiePropertyKey: Any]

    /// The `UserDefaults` key for accessing cookies.
    private static let cookieKey = "cookies"

    /// Saves all cookies currently in the shared `HTTPCookieStorage` to the shared `UserDefaults`.
    func saveCookies() {
        guard let cookies = HTTPCookieStorage.shared.cookies else {
            return
        }
        let cookiePropertiesArray = cookies.flatMap { $0.properties }
        set(cookiePropertiesArray, forKey: UserDefaults.cookieKey)
        synchronize()
    }

    /// Loads all cookies stored in the shared `UserDefaults` and adds them to the current shared `HTTPCookieStorage`.
    func loadCoookies() {
        let cookiePropertiesArray = value(forKey: UserDefaults.cookieKey) as? [CookieProperties]
        cookiePropertiesArray?.forEach {
            if let cookie = HTTPCookie(properties: $0) {
                HTTPCookieStorage.shared.setCookie(cookie)
            }
        }
    }

}

You can add this code to a separate file UserDefaults+Cookies.swift (for example) and then call the methods from your AppDelegate as described by Brian Shamblen in his original answer:

Calls from AppDelegate

func applicationDidBecomeActive(_ application: UIApplication) {
    UserDefaults.standard.loadCoookies()
}

func applicationWillEnterForeground(_ application: UIApplication) {
    UserDefaults.standard.loadCoookies()
}

func applicationDidEnterBackground(_ application: UIApplication) {
    UserDefaults.standard.saveCookies()
}

func applicationWillTerminate(_ application: UIApplication) {
    UserDefaults.standard.saveCookies()
}
Gurtner answered 14/6, 2017 at 13:41 Comment(0)
C
6

Swift 3

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any] ? ) - > Bool {
    loadHTTPCookies()

    return true
}

func applicationDidEnterBackground(_ application: UIApplication) {
    saveCookies()
}

func applicationWillEnterForeground(_ application: UIApplication) {
    loadHTTPCookies()
}

func applicationWillTerminate(_ application: UIApplication) {
    saveCookies()
}

func loadHTTPCookies() {

    if let cookieDict = UserDefaults.standard.value(forKey: "cookieArray") as? NSMutableArray {

        for c in cookieDict {

            let cookies = UserDefaults.standard.value(forKey: c as!String) as!NSDictionary
            let cookie = HTTPCookie(properties: cookies as![HTTPCookiePropertyKey: Any])

            HTTPCookieStorage.shared.setCookie(cookie!)
        }
    }
}

func saveCookies() {

    let cookieArray = NSMutableArray()
    if let savedC = HTTPCookieStorage.shared.cookies {
        for c: HTTPCookie in savedC {

            let cookieProps = NSMutableDictionary()
            cookieArray.add(c.name)
            cookieProps.setValue(c.name, forKey: HTTPCookiePropertyKey.name.rawValue)
            cookieProps.setValue(c.value, forKey: HTTPCookiePropertyKey.value.rawValue)
            cookieProps.setValue(c.domain, forKey: HTTPCookiePropertyKey.domain.rawValue)
            cookieProps.setValue(c.path, forKey: HTTPCookiePropertyKey.path.rawValue)
            cookieProps.setValue(c.version, forKey: HTTPCookiePropertyKey.version.rawValue)
            cookieProps.setValue(NSDate().addingTimeInterval(2629743), forKey: HTTPCookiePropertyKey.expires.rawValue)

            UserDefaults.standard.setValue(cookieProps, forKey: c.name)
            UserDefaults.standard.synchronize()
        }
    }

    UserDefaults.standard.setValue(cookieArray, forKey: "cookieArray")
}
Cicely answered 23/11, 2016 at 12:52 Comment(2)
can you help me here ? this is my question #41861296Patty
There was a typing mistake in the code above i fixed it and i also answered your question thank you for pointing that there was a problemCicely
N
3

Here is a cleaner and more safe Swift version:

private func loadCookies() {
    guard let cookies = NSUserDefaults.standardUserDefaults().valueForKey("cookies") as? [[String: AnyObject]] else {
        return
    }

    for cookieProperties in cookies {
        if let cookie = NSHTTPCookie(properties: cookieProperties) {
            NSHTTPCookieStorage.sharedHTTPCookieStorage().setCookie(cookie)
        }
    }
}

private func saveCookies() {
    guard let cookies = NSHTTPCookieStorage.sharedHTTPCookieStorage().cookies else {
        return
    }

    var array = [[String: AnyObject]]()
    for cookie in cookies {
        if let properties = cookie.properties {
            array.append(properties)
        }
    }
    NSUserDefaults.standardUserDefaults().setValue(array, forKey: "cookies")
    NSUserDefaults.standardUserDefaults().synchronize()
}
Nicolas answered 8/8, 2016 at 9:27 Comment(1)
any way to first time i load webview with manually cookies through API or other way. so automatically login.Malamut
Q
2

Swift 4.2

Please add this extension to your controller

extension UserDefaults {

    /// A dictionary of properties representing a cookie.
    typealias CookieProperties = [HTTPCookiePropertyKey: Any]

    /// The `UserDefaults` key for accessing cookies.
    private static let cookieKey = "cookies"

    /// Saves all cookies currently in the shared `HTTPCookieStorage` to the shared `UserDefaults`.
    func saveCookies() {
        guard let cookies = HTTPCookieStorage.shared.cookies else {
            return
        }
        let cookiePropertiesArray = cookies.compactMap { $0.properties }
        set(cookiePropertiesArray, forKey: UserDefaults.cookieKey)
        synchronize()
    }

    /// Loads all cookies stored in the shared `UserDefaults` and adds them to the current shared `HTTPCookieStorage`.
    func loadCoookies() {
        let cookiePropertiesArray = value(forKey: UserDefaults.cookieKey) as? [CookieProperties]
        cookiePropertiesArray?.forEach {
            if let cookie = HTTPCookie(properties: $0) {
                HTTPCookieStorage.shared.setCookie(cookie)
            }
        }
    }

}

And replace in AppDelegate this code lines:

    func applicationDidEnterBackground(_ application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    }

    func applicationWillTerminate(_ application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    }

with this code lines:

    func applicationDidBecomeActive(_ application: UIApplication) {
        UserDefaults.standard.loadCoookies()
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        UserDefaults.standard.loadCoookies()
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        UserDefaults.standard.saveCookies()
    }

    func applicationWillTerminate(_ application: UIApplication) {
        UserDefaults.standard.saveCookies()
    }
Questionary answered 20/1, 2019 at 11:58 Comment(0)
K
1

Swift 2.0 Version

func loadCookies() {

    let cookieDict : NSMutableArray? = NSUserDefaults.standardUserDefaults().valueForKey("cookieArray") as? NSMutableArray

    if cookieDict != nil {

        for var c in cookieDict! {

            let cookies = NSUserDefaults.standardUserDefaults().valueForKey(c as! String) as! NSDictionary
            let cookie = NSHTTPCookie(properties: cookies as! [String : AnyObject])

            NSHTTPCookieStorage.sharedHTTPCookieStorage().setCookie(cookie!)
        }
    }
}

func saveCookies() {

    var cookieArray = NSMutableArray()
    let savedC = NSHTTPCookieStorage.sharedHTTPCookieStorage().cookies

    for var c : NSHTTPCookie in savedC! {

        var cookieProps = NSMutableDictionary()
        cookieArray.addObject(c.name)
        cookieProps.setValue(c.name, forKey: NSHTTPCookieName)
        cookieProps.setValue(c.value, forKey: NSHTTPCookieValue)
        cookieProps.setValue(c.domain, forKey: NSHTTPCookieDomain)
        cookieProps.setValue(c.path, forKey: NSHTTPCookiePath)
        cookieProps.setValue(c.version, forKey: NSHTTPCookieVersion)
        cookieProps.setValue(NSDate().dateByAddingTimeInterval(2629743), forKey: NSHTTPCookieExpires)

        NSUserDefaults.standardUserDefaults().setValue(cookieProps, forKey: c.name)
        NSUserDefaults.standardUserDefaults().synchronize()

    }

    NSUserDefaults.standardUserDefaults().setValue(cookieArray, forKey: "cookieArray")
}
Kemberlykemble answered 20/9, 2015 at 12:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.