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? // 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.fromOpaque(op).takeUnretainedValue() // Convert the data retrieved from the keychain into a string contentsOfKeychain = NSString(data: retrievedData, encoding: NSUTF8StringEncoding) } else { return nil } return contentsOfKeychain } } 

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

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

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

使用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) { // ... } } } 

它与发布(最快优化)构建一起工作正常。

好吧,供应配置文件和钥匙串代码中的所有内容都很好。 问题是Swift编译器中的一个设置! 将“释放”的优化级别从“最快”更改为“无”似乎解决了这个问题。

在此处输入图像描述

swift优化器的更改正在起作用,但不是解决问题的好方法。 正如评论中所述,这似乎是swift编译器中的优化错误。

这不仅仅是iOS,在OSX上完全相同的事情(可能在问题中添加标签)。 OSStatus为0(成功),但一旦优化完成,引用指针就为零。

最好的解决方法是在objective-c中实现keychain通信或使用像EMKeychain这样的包装器(仅限OSX,抱歉暂时不知道iOS Wrapper)