[英]Share between an iOS extension and its containing app with the keychain?
我知道我可以通过启用应用程序组和使用 NSUserDefaults 在我的共享扩展和它包含的应用之间共享数据(请参阅在 iOS 8 共享扩展和主应用之间共享数据)。
但是,我存储的数据是敏感的,所以我希望使用钥匙串。 因此,用户将在包含的应用程序中输入帐户信息,然后共享扩展程序将读取该数据以执行预期的共享操作。
有谁知道这是否可能? 我对它的第一次破解表明扩展程序和包含的应用程序具有单独的钥匙串(在尝试返回扩展程序中该键的数据时,使用包含应用程序中的键保存数据返回 null)。
谢谢!
PS 使用 Lockbox 进行钥匙串访问,但如果它过于抽象而无法正常工作,我可以放弃它。 https://github.com/granoff/Lockbox
使钥匙串在 Xcode 8 中共享。
1) 在 Capabilities 中的 App 目标中找到并打开“钥匙串共享”,添加钥匙串组密钥(反向域样式字符串,如 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
}
}
请注意,您仍需要将“登录名”和“域”传递给扩展程序,以便识别正确的记录。 这可以通过 NSUserDefaults 来完成。 请参阅有关如何执行此操作的答案。
这是可以做到的。 它是创建一个框架来进行钥匙串访问,并在“功能”下打开“激活钥匙串共享”的组合。 这个链接告诉我我需要知道的: http : //swiftandpainless.com/ios8-share-extension-with-a-shared-keychain/
使用标准的 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)]);
不要忘记在“功能”下为同一钥匙串组的手机应用程序和手表套件扩展打开“钥匙串共享”:“group.com.yourcompany.appid”
我为应用程序和共享扩展的目标启用了应用程序组功能。 然后我刚刚添加了属性:
kSecAttrAccessGroup: "group.lolrandomname",
它工作正常:我可以从应用程序和我的共享扩展访问相同的存储项目:)
使用以下链接中的 KeychainItemWrapper 类并将您的组标识符作为访问组传递。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.