使用UIApplicationLaunchOptionsLocationKey在后台启动应用程序时,NSURLCredentialStorage不返回凭据

时间:2014-05-22 19:27:04

标签: ios objective-c nsurlcredential

我的应用程序在登录或登录时存储用户的凭据。当应用程序启动时,如果我们存储了凭据,我会检查didFinishLaunchingWithOptions。这可以通过点击应用程序图标或从Xcode启动它来启动应用程序。

但是,当应用程序在后台被杀死并由于位置更改更新而被系统重新启动时,defaultCredentialForProtectionSpace返回的凭据为零。当我再次正常重新启动应用程序时,凭证又会重新开始。

因此当[launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]为真时,NSURLCredential返回的NSURLCredentialStorage为零;如果它是假的,我们会获得预期的凭证。

以下是一些代码:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Other init things happen here, including setting up the NSURLProtectionSpace

    NSURLCredentialStorage *credentialStorage = [NSURLCredentialStorage sharedCredentialStorage];
    NSURLCredential *credential = [credentialStorage defaultCredentialForProtectionSpace:self.protectionSpace];
    if (credential) {
        // do something - XXX this does not happen when app is launched in background
    }
} 

1 个答案:

答案 0 :(得分:3)

事实证明,钥匙串中的NSURLCredentialStoragekSecAttrAccessibleWhenUnlocked用于存储凭据。这意味着当用户设置密码以解锁手机并且手机被锁定时,无法访问凭据。

--- --- EDIT

以上解释了为什么它不起作用,这是我最终实现的解决方案:将钥匙串中的kSecAttrAccessible更改为kSecAttrAccessibleAfterFirstUnlock并处理无法访问凭证的问题在极少数情况下,手机重新启动但尚未解锁。

当应用程序位于前台时,钥匙串将以NSURLCredentialStoragekSecAttrAccessibleWhenUnlocked使用的模式解锁。因此,在applicationDidBecomeActive:中,我们可以从NSURLCredentialStorage访问Keychain条目并进行更改:

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"server.com" accessGroup:nil];
    [wrapper setObject:(__bridge id)kSecAttrAccessibleAfterFirstUnlock forKey:(__bridge id)kSecAttrAccessible];

    // ...
}

上面的代码使用了KeychainItemWrapper的改编版本。原始版本来自Apple,但我的解决方案基于ARCified版本:https://gist.github.com/dhoerl/1170641。您仍然需要更改该版本才能使用kSecClassInternetPassword代替kSecClassGenericPassword,这主要意味着您无法使用kSecAttrGeneric来查询Keychain项目,而是{{1} }。

--- --- EDIT

上述方法适用于iOS 7.x但在iOS 8.x上不再有效。代码运行正常,但Keychain仍使用kSecAttrServer

现在唯一的解决方案是只有当你知道你只在前台使用它时才使用kSecAttrAccessibleWhenUnlocked。否则,您需要使用https://gist.github.com/dhoerl/1170641中的KeychainItemWrapper将凭据自己存储在Keychain中。然后,您可以在存储凭据时自己设置NSURLCredentialStorage

示例代码:

kSecAttrAccessibleAfterFirstUnlock