I understand I can share data between my share extension and its containing app by enabling app groups and using NSUserDefaults (see Sharing data between an iOS 8 share extensio
Using the standard Objective-C KeychainItemWrapper class and with an entry of #import "KeychainItemWrapper.h" in the bridging header:
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)
}
On the Watch extension side (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))
}
In Objective C, watchkit extension:
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)]);
Don't forget to turn on "Keychain Sharing" under "Capabilities" for both the phone app and watch kit extension for same keychain group: "group.com.yourcompany.appid"
This can be done. It is a combination of creating a framework to do the Keychain access, and turning on "Activate Keychain Sharing" under "Capabilities". This link told me what I needed to know: http://swiftandpainless.com/ios8-share-extension-with-a-shared-keychain/
To make the Keychain shared in Xcode 8.
1) In your App target in Capabilities find and turn on "Keychain Sharing", add a Keychain Group key (a reverse-domain style string like com.myappdomain.myappname)
2) Do exactly the same for the extension target. Make sure the Keychain Group key is the same for both - the app and the extension.
Add and retrieve data from Keychain in your usual way, no special changes required in the code. For example, here's how I put data into Keychain in the main app (a little old-fashioned but still works in 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)
And then retrieve it in the extension:
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
}
}
Note that you will still need to pass "login" and "domain" over to the extension in order to identify the correct record. This can be done via NSUserDefaults. See this answer on how to do this.
Use KeychainItemWrapper Class from the following link and pass your group identifier as accessgroup.
https://developer.apple.com/library/ios/samplecode/GenericKeychain/Listings/Classes_KeychainItemWrapper_m.html