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
}
}
- C'è qualcosa che potremmo avere perso?
- 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.
Considerato quanto lento Swift è senza ottimizzazione questa è una soluzione orribile. Forse disattivare l'ottimizzazione per un singolo file sarebbe meglio. –
@jshier puoi spiegare come farlo per un singolo file? – Turowicz
Nelle tue "Fasi di costruzione" target -> "Fonti di compilazione", fai doppio clic sulla colonna "Flag del compilatore" e aggiungi l'impostazione -Onone. –