2014-11-01 9 views
11

Capisco che posso condividere i dati tra la mia estensione di condivisione e la sua app contenente abilitando gruppi di app e usando NSUserDefaults (vedi Sharing data between an iOS 8 share extension and main app).Condividi tra un'estensione iOS e contiene l'app con il portachiavi?

Tuttavia, i dati che sto memorizzando sono sensibili, quindi spero di usare il portachiavi. Pertanto, l'utente inserisce le informazioni sull'account nell'app contenente e quindi l'estensione di condivisione legge tali dati per eseguire l'azione di condivisione prevista.

Qualcuno sa se questo è possibile? Il mio primo tentativo suggerisce che l'estensione e l'app contenente abbia portachiavi separati (il salvataggio dei dati con una chiave nell'app contenente restituisce null quando si tenta di restituire i dati per quella chiave nell'estensione).

Grazie!

P.S. Usando Lockbox per l'accesso Portachiavi, ma potrei abbandonarlo se è troppo astrazione per farlo funzionare. https://github.com/granoff/Lockbox

risposta

8

Questo può essere fatto. È una combinazione di creazione di un framework per l'accesso al portachiavi e attivazione di "Activate Keychain Sharing" in "Capabilities". Questo collegamento mi ha detto cosa dovevo sapere: http://swiftandpainless.com/ios8-share-extension-with-a-shared-keychain/

+4

È molto utile non collegare ad altri siti Web o almeno aggiungere la fonte pertinente alla risposta, tale collegamento non è più disponibile. – leolobato

+0

C'è un bel po 'di informazioni lì, non ho intenzione di distillare e incollare, ma ecco la versione di Internet Archive: https://web.archive.org/web/20141028160328/http://dasdev.de/2014/ 08/12/ios8-share-extension-with-a-shared-keychain –

+0

Il repository GitHub è ancora lì https://github.com/dasdom/KeychainDemo anche –

0

Uso della classe Objective-C KeychainItemWrapper di serie e con una voce di #import "KeychainItemWrapper.h" nell'intestazione colmare:

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) 

    } 

Sul lato estensione 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)) 

} 

In Objective C, estensione 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)]); 

Non dimenticare di attivare l'opzione "Condivisione Portachiavi" sotto "Capabilities" sia per l'applicazione del telefono e guardare estensione kit per lo stesso gruppo di portachiavi: "group.com.yourcompany.appid"

4

Per rendere il Portachiavi condiviso in Xcode 8.

1) nel vostro obiettivo App in capacità di trovare e attivare il "portachiavi Sharing", aggiungere una chiave portachiavi Group (una stringa stile reverse-dominio come com.myappdomain.myappname)

2) Fai esattamente lo stesso per il target di estensione. Assicurati che il tasto Keychain Group sia lo stesso per entrambi: l'app e l'estensione.

Aggiungere e recuperare i dati da Keychain nel modo consueto, senza modifiche speciali richieste nel codice. Ad esempio, ecco come ho messo i dati in portachiavi in ​​app principale (un po 'vecchio stile, ma funziona ancora a 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) 

E poi recuperarlo nel prolungamento:

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 
    } 
} 

Nota che dovrai ancora passare "login" e "dominio" sull'estensione per identificare la registrazione corretta. Questo può essere fatto tramite NSUserDefaults. Vedi this answer su come farlo.