在iOS扩展程序和包含钥匙串的应用程序之间共享?

我了解我可以通过启用应用程序组和使用NSUserDefaults在我的共享扩展程序和其包含的应用程序之间共享数据 (请参阅在iOS 8共享扩展程序和主应用程序之间共享数据 )。

但是,我存储的数据很敏感,所以我希望使用钥匙串。 因此,用户将在包含应用程序中输入帐户信息,然后共享扩展将读取该数据以执行预期的共享操作。

有谁知道这是否可能? 我的第一个破解建议扩展和包含应用程序具有单独的钥匙串(在包含应用程序中保存数据时,在尝试返回扩展中该键的数据时返回null)。

谢谢!

PS使用Lockbox进行Keychain访问,但如果它太过抽象而无法使其工作,我可能会放弃它。 https://github.com/granoff/Lockbox

这可以做到。 它是创建一个框架来进行Keychain访问,并在“Capabilities”下启用“Activate Keychain Sharing”的组合。 这个链接告诉我我需要知道的内容: http : //swiftandpainless.com/ios8-share-extension-with-a-shared-keychain/

使密钥链在Xcode 8中共享。

1)在您的应用程序目标function查找并打开“钥匙串共享”,添加一个钥匙串组密钥(反向域样式字符串,如com.myappdomain.myappname)

2)对扩展目标执行完全相同的操作。 确保钥匙串组密钥对于应用程序和扩展程序都是相同的。

以常规方式从Keychain添加和检索数据,代码中无需进行特殊更改。 例如,以下是我如何将数据放入主应用程序中的Keychain(有点过时但仍可在Swift 3中运行):

let login = loginString let domain = domainString let passwordData: Data = passwordString.data(using: String.Encoding.utf8, allowLossyConversion: false)! let keychainQuery: [NSString: NSObject] = [ kSecClass: kSecClassGenericPassword, kSecAttrAccount: login as NSObject, // login and domain strings help identify kSecAttrService: domain as NSObject, // the required record in the Keychain kSecValueData: passwordData as NSObject] SecItemDelete(keychainQuery as CFDictionary) //Deletes the item just in case it already exists let keychainSaveStatus: OSStatus = SecItemAdd(keychainQuery as CFDictionary, nil) 

然后在扩展中检索它:

 let keychainQuery: [NSString: NSObject] = [ kSecClass: kSecClassGenericPassword, kSecAttrAccount: login as NSObject, kSecAttrService: domain as NSObject, kSecReturnData: kCFBooleanTrue, kSecMatchLimit: kSecMatchLimitOne] var rawResult: AnyObject? let keychain_get_status: OSStatus = SecItemCopyMatching(keychainQuery as CFDictionary, &rawResult) if (keychain_get_status == errSecSuccess) { if let retrievedData = rawResult as? Data, let password = String(data: retrievedData, encoding: String.Encoding.utf8) { // "password" contains the password string now } } 

请注意,您仍需要将“login”和“domain”传递给扩展名,以便识别正确的记录。 这可以通过NSUserDefaults完成。 请参阅此答案 ,了解如何执行此操作。

使用标准的Objective-C KeychainItemWrapper类以及桥接头中#import“KeychainItemWrapper.h”的条目:

  func btnSaveAction() { let appGroupID = "group.com.yourcompany.appid" let keychain = KeychainItemWrapper(identifier: "Password", accessGroup:appGroupID) keychain.setObject(self.txtfldPassword.text!, forKey:kSecValueData) keychain.setObject(self.txtfldEmail.text!, forKey:kSecAttrAccount) } 

在Watch扩展端(Swift):

 override func awakeWithContext(context: AnyObject?) { super.awakeWithContext(context) let appGroupID = "group.com.yourcompany.appid" let keychain = KeychainItemWrapper(identifier: "Password", accessGroup:appGroupID) println(keychain.objectForKey(kSecAttrAccount)) println(keychain.objectForKey(kSecValueData)) } 

在Objective C中,watchkit扩展:

 NSString *appGroupID = @"group.com.yourcompany.appid"; KeychainItemWrapper *keychain = [[KeychainItemWrapper alloc] initWithIdentifier:@"Password" accessGroup:appGroupID]; [keychain setObject:(__bridge id)(kSecAttrAccessibleWhenUnlocked) forKey:(__bridge id)(kSecAttrAccessible)]; NSLog(@"account = %@", [keychain objectForKey:(__bridge id)(kSecAttrAccount)]); NSLog(@"password =%@", [keychain objectForKey:(__bridge id)(kSecValueData)]); 

不要忘记为同一个钥匙串组的手机应用和手表套件扩展打开“function”下的“钥匙串共享”:“group.com.yourcompany.appid”

使用以下链接中的KeychainItemWrapper类,并将您的组标识符作为accessgroup传递。

https://developer.apple.com/library/ios/samplecode/GenericKeychain/Listings/Classes_KeychainItemWrapper_m.html