2014-10-16 4 views
5

Per iniziare, alcuni dettagli: stiamo sviluppando un'applicazione iOS che utilizza attualmente Swift/Xcode 6.1 GM 2 per lo sviluppo.Keychain + distribuzione ad hoc

Stiamo riscontrando alcuni problemi di confusione con l'accesso a portachiavi quando si distribuiscono applicazioni ad hoc e si riscontrano problemi nel rintracciare il motivo. Tutti i profili di provisioning corrispondono al nome del bundle della nostra app. Usiamo TestFlight per la distribuzione anche se non penso che sia il problema.

Siamo riusciti a farlo funzionare solo su dispositivi iOS 7 che non avevano l'app installata in precedenza. Non un singolo dispositivo iOS 8 funzionava ad hoc. Gli errori che stavamo ottenendo all'inizio erano 25300 (errSecItemNotFound) e ora, dopo aver resettato i profili di provisioning, otteniamo un 0 normale (sia per il salvataggio sul caricamento che ancora non è possibile recuperare dati). Tutto funziona perfettamente quando si distribuiscono le versioni di sviluppo di Xcode.

ho separato il codice per il wrapper portachiavi che usiamo:

import UIKit 
import Security 

let serviceIdentifier = "com.Test.KeychainTest" 

let kSecClassValue = kSecClass as NSString 
let kSecAttrAccountValue = kSecAttrAccount as NSString 
let kSecValueDataValue = kSecValueData as NSString 
let kSecClassGenericPasswordValue = kSecClassGenericPassword as NSString 
let kSecAttrServiceValue = kSecAttrService as NSString 
let kSecMatchLimitValue = kSecMatchLimit as NSString 
let kSecReturnDataValue = kSecReturnData as NSString 
let kSecMatchLimitOneValue = kSecMatchLimitOne as NSString 

class KeychainManager { 

class func setString(value: NSString, forKey: String) { 
    self.save(serviceIdentifier, key: forKey, data: value) 
} 

class func stringForKey(key: String) -> NSString? { 
    var token = self.load(serviceIdentifier, key: key) 

    return token 
} 

class func removeItemForKey(key: String) { 
    self.save(serviceIdentifier, key: key, data: "") 
} 



class func save(service: NSString, key: String, data: NSString) { 
    var dataFromString: NSData = data.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! 
    // Instantiate a new default keychain query 
    var keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, key, dataFromString], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecValueDataValue]) 

    // Delete any existing items 
    SecItemDelete(keychainQuery as CFDictionaryRef) 

    if data == "" { return } 

    // Add the new keychain item 
    var status: OSStatus = SecItemAdd(keychainQuery as CFDictionaryRef, nil) 
    var alertView = UIAlertView(); 
    alertView.addButtonWithTitle("Ok"); 
    alertView.title = "Status"; 
    alertView.message = "Saving \(status)"; 
    alertView.show(); 
} 

class func load(service: NSString, key: String) -> NSString? { 
    // Instantiate a new default keychain query 
    // Tell the query to return a result 
    // Limit our results to one item 
    var keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, key, kCFBooleanTrue, kSecMatchLimitOneValue], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecReturnDataValue, kSecMatchLimitValue]) 

    var dataTypeRef :Unmanaged<AnyObject>? 

    // Search for the keychain items 
    let status: OSStatus = SecItemCopyMatching(keychainQuery, &dataTypeRef) 
    var alertView = UIAlertView(); 
    alertView.addButtonWithTitle("Ok"); 
    alertView.title = "Status"; 
    alertView.message = "Loading \(status)"; 
    alertView.show(); 

    let opaque = dataTypeRef?.toOpaque() 

    var contentsOfKeychain: NSString? 

    if let op = opaque? { 
     let retrievedData = Unmanaged<NSData>.fromOpaque(op).takeUnretainedValue() 

     // Convert the data retrieved from the keychain into a string 
     contentsOfKeychain = NSString(data: retrievedData, encoding: NSUTF8StringEncoding) 
    } else { 
     return nil 
    } 

    return contentsOfKeychain 
} 


} 
  1. C'è qualcosa che potremmo avere perso?
  2. Qual è il modo migliore per risolvere questo problema? Non riceviamo errori dal portachiavi nei registri/utilità di configurazione iPhone. Al momento ho appena inserito alcuni semplici avvisi nel codice per capire qual è lo stato dell'operazione.

risposta

3

Tutto nel profilo di provisioning e nel codice portachiavi sembra essere a posto. Il problema è un ambiente nel compilatore Swift ... Cambiare il livello di ottimizzazione per "uscita" da "veloce" a "Nessuno" e questo sembra risolvere il problema

enter image description here

+0

Considerato quanto lento Swift è senza ottimizzazione questa è una soluzione orribile. Forse disattivare l'ottimizzazione per un singolo file sarebbe meglio. –

+0

@jshier puoi spiegare come farlo per un singolo file? – Turowicz

+0

Nelle tue "Fasi di costruzione" target -> "Fonti di compilazione", fai doppio clic sulla colonna "Flag del compilatore" e aggiungi l'impostazione -Onone. –

1

Assicurarsi di specificare anche il valore per kSecAttrAccessible. Forse anche specificare il valore per kSecAttrAccessControl, che era added in iOS8.