2014-10-14 9 views
5

Stworzyliśmy aplikację w Swift, która używa pęku kluczy. Aplikacja działa poprawnie, gdy działa na urządzeniu lub w symulatorze, ale nie może uzyskać dostępu do pęku kluczy po udostępnieniu za pośrednictwem aplikacji Testflight, chyba że zostanie udostępniona nowemu urządzeniu, które nigdy wcześniej nie miało zainstalowanej aplikacji za pośrednictwem Xcode 6.1.Błyskawiczne pęki kluczy i profile udostępniania

Poniżej znajduje się fragment kodu keychain:

import UIKit 
    import Security 

    let serviceIdentifier = "com.ourdomain" 

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

    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) 

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

Po aplikacja została zainstalowana na urządzeniu poprzez Xcode 6.1 zauważyłem, że „serviceIdentifier” - „com.ourdomain” był Niepoprawny i nie pasuje do identyfikatora pakietu aplikacji zgodnie z wymaganiami dotyczącymi udostępniania.

Potem zmienił „serviceIdentifier” wartość pasujące do identyfikatora bundle - „com.ourdomain.appname” Jednak aplikacja po prostu nie będzie działać na urządzeniu, gdy zabezpieczony poprzez Testflight. Jestem pewien, że to dlatego, że urządzenie ma już pęku kluczy do identyfikatora pakunku zainstalowanego z niepoprawnym identyfikatorem, ale nie mam pojęcia, jak to obejść, aby usunąć pęk kluczy po usunięciu aplikacji lub użyć profilu udostępniania istniejący pęku kluczy (z niepoprawnym identyfikatorem)

Każda pomoc zostanie bardzo doceniona. Z góry dziękuję

Odpowiedz

5

Zastosowanie withUnsafeMutablePointer funkcja i UnsafeMutablePointer do struct pobieranie danych zamiast, jak poniżej:

var result: AnyObject? 
var status = withUnsafeMutablePointer(&result) { SecItemCopyMatching(keychainQuery, UnsafeMutablePointer($0)) } 

if status == errSecSuccess { 
    if let data = result as NSData? { 
     if let string = NSString(data: data, encoding: NSUTF8StringEncoding) { 
      // ... 
     } 
    } 
} 

działa dobrze z wersją (Najszybsza optymalizacja) kompilacji.

+2

To jest rzeczywiste rozwiązanie problemu! Przyjęta odpowiedź na wyłączenie optymalizacji kompilatora w wielu przypadkach nie do zaakceptowania. Co jest warte, widzę tylko oryginalny błąd na 64-bitowych urządzeniach. – alexkent

+1

To zadziałało dla mnie po wielu godzinach uderzania głową o ścianę. Dzięki. – Nick

+0

Nie działa, iPhone 6, 6+ i iPad Air 2 nadal wykazują problem podczas używania 'withUnsafeMutablePointer'. '-Onone' jest nadal jedyną realną opcją dla wszystkich urządzeń, dopóki Swift 1.2 nie będzie stabilny –

2

Dobrze, więc wszystko w profilu udostępniania i w kodzie pęku kluczy było w porządku. Problemem było ustawienie w kompilatorze Swift! Zmiana poziomu optymalizacji dla "Zwolnienie" z "Najszybsza" na "Brak" wydawało się rozwiązać problem.

enter image description here

+2

Mam dokładnie ten sam problem. Wygląda na to, że dataTypeRef? .toOpaque() zwraca zero, gdy ustawisz poziom optymalizacji na -O. Nie uważam jednak, że ustawienie poziomu optymalizacji na -Onone nie jest rozwiązaniem, ponieważ znacznie spowolni to działanie kodu. I uwe Xcode 6.1 (6A1052d) – JorgeDeCorte

+0

Wystąpiłem w tym samym problemie i zgłosiłem ten błąd do Apple (błąd 19003552, jeśli jest to pomocne). Każdy, kto się na to przygotuje, powinien zrobić to samo, co duplikaty, co powinno pomóc w ustaleniu priorytetów. – kolizz

+0

@JorgeDeCorte - Dzięki. Być może musimy spróbować i jawnie odwijać dataTypeRef ... czy próbowałeś tego?- Zobaczę, czy może to rozwiązuje problem. – Mark

0

Zmiana szybkiej optymalizator działa, ale nie jest to dobry sposób, aby rozwiązać problem. Jak stwierdzono w komentarzach, wydaje się, że jest to błąd w szybkim kompilatorze z optymalizacją.

To nie jest tylko iOS, dokładnie to samo dzieje się na OSX (może dodać znacznik do pytania). OSStatus ma wartość 0 (powodzenie), ale wskaźnik odwołania jest zerowy zaraz po zakończeniu optymalizacji.

Najlepszym rozwiązaniem jest wdrożenie do keychain komunikację w Objective-C lub przy użyciu opakowanie jak EMKeychain (OSX tylko, przepraszam, nie wiem jak iOS Wrapper w tej chwili)

Powiązane problemy