2014-11-01 25 views
11

我知道我可以通過啓用應用程序組和使用NSUserDefaults在我的共享擴展和其包含的應用程序之間共享數據(請參閱Sharing data between an iOS 8 share extension and main app)。在iOS擴展之間共享,並且它包含帶鑰匙串的應用程序?

但是,我存儲的數據是敏感的,所以我希望使用鑰匙串。因此,用戶將在包含應用程序中輸入帳戶信息,然後共享擴展將讀取該數據以執行預期的共享操作。

有誰知道這是可能的嗎?我對它的第一個破解表明,擴展和包含的應用程序具有單獨的鑰匙串(在試圖返回擴展中的該密鑰的數據時,用包含應用程序中的鍵保存數據返回null)。

謝謝!

P.S.使用Lockbox進行Keychain訪問,但如果它太抽象以使其工作,我可以拋棄它。 https://github.com/granoff/Lockbox

回答

8

這可以做到。它是創建一個框架來完成鑰匙串訪問,並打開「功能」下的「激活鑰匙串共享」的組合。此鏈接告訴我我需要知道的內容:http://swiftandpainless.com/ios8-share-extension-with-a-shared-keychain/

+4

這是非常有用的不鏈接到其他網站或至少添加相關的來源的答案,該鏈接不再可用。 – leolobato 2015-07-29 14:30:14

+0

這裏有相當多的信息,我不喜歡蒸餾和粘貼,但這裏是Internet Archive版本:https://web.archive.org/web/20141028160328/http://dasdev.de/2014/ 08/12/ios8-share-extension-with-a-shared-keychain – 2015-07-30 15:12:22

+0

GitHub repo仍然存在https://github.com/dasdom/KeychainDemo太 – 2015-10-22 09:55:30

0

使用標準的Objective-C KeychainItemWrapper類和與所述橋接報頭的#進口的條目 「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) 

    } 

在觀看伸展側(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」

4

爲了使鑰匙扣在Xcode 8.

1)共享在你的應用目標在功能找到並打開「鑰匙扣共享」,添加一個鑰匙串組密鑰(反向域風格串等com.myappdomain.myappname)

2 )對擴展目標完全相同。確保鑰匙串組密鑰對於應用和擴展都是相同的。

以通常的方式添加和檢索Keychain中的數據,代碼中無需進行特殊更改。例如,這裏是我如何把數據放到鑰匙串在主應用程序(有點老套,但是在斯威夫特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(keychainQueryForPass 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完成。有關如何操作,請參閱this answer

相關問題