我们在 swift 中创建了一个使用钥匙串(keychain)的应用程序。该应用程序在设备或模拟器中运行时运行良好,但在通过 Testflight 提供时无法访问钥匙串(keychain),除非提供给以前从未通过 Xcode 6.1 安装该应用程序的新设备。
以下是钥匙串(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
}
}
通过 Xcode 6.1 在设备上安装应用程序后,我注意到“serviceIdentifier”-“com.ourdomain”不正确并且与供应所需的应用程序包标识符。
然后我更改了“serviceIdentifier”值以匹配包标识符 - “com.ourdomain.appname”但是当通过 Testflight 提供。我很肯定这是因为设备已经安装了带有不正确标识符的捆绑 ID 的钥匙串(keychain),但我无法理解如何解决这个问题,以便在删除应用程序时删除钥匙串(keychain)或获取要使用的配置文件现有的钥匙串(keychain)(标识符不正确)
如有任何帮助,我们将不胜感激。提前致谢
最佳答案
使用 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) {
// ...
}
}
}
它适用于发布(最快优化)构建。
关于ios - Swift 钥匙串(keychain)和配置文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26355630/