Swift钥匙串和配置文件

Mar*_*ark 5 xcode keychain ios testflight swift

我们在swift中创建了一个使用钥匙串的应用程序.该应用程序在设备或模拟器上运行时工作正常,但在通过Testflight配置时无法访问钥匙串,除非配置到以前从未安装过通过Xcode 6.1安装的应用程序的新设备.

以下是钥匙串代码的摘录:

    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
    }  
  }
Run Code Online (Sandbox Code Playgroud)

在应用程序已经通过Xcode 6.1安装在设备上之后,我注意到" serviceIdentifier " - " com.ourdomain "不正确,并且与配置所需的应用程序包标识符不匹配.

然后我更改了" serviceIdentifier "值以匹配包标识符 - " com.ourdomain.appname ",但是当通过Testflight进行配置时,应用程序将无法在设备上运行.我很肯定这是因为设备已经安装了带有错误标识符的软件包ID的钥匙串,但是我无法理解如何解决这个问题,以便在移除应用程序时移除钥匙串或者使用配置文件来使用现有的钥匙串(标识符不正确)

任何帮助将不胜感激.提前致谢

kis*_*umi 5

使用withUnsafeMutablePointer函数和UnsafeMutablePointer结构来检索数据,如下所示:

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) {
            // ...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

它在发布(最快优化)版本时运行良好.

  • 这是问题的实际解决方案!在许多情况下,接受的禁用编译器优化的答案是不可接受的.对于它的价值,我只看到64位设备上的原始错误. (2认同)