Xcode 钥匙链&x2B;临时分配

Xcode 钥匙链&x2B;临时分配,xcode,swift,ios8,keychain,Xcode,Swift,Ios8,Keychain,首先,介绍一些细节:我们正在开发一个iOS应用程序,目前使用Swift/Xcode 6.1 GM 2进行开发 在临时分发应用程序时,我们在密钥链访问方面遇到了一些令人困惑的问题,并且在跟踪原因方面遇到了问题。所有配置文件都与我们应用程序的捆绑包名称匹配。我们使用TestFlight进行分发,尽管我认为这不是问题所在 我们只设法让它在iOS 7设备上工作,而这些设备之前没有安装该应用程序。没有一台iOS 8设备可以临时工作。我们在开始时遇到的错误是25300(errSecItemNotFound)

首先,介绍一些细节:我们正在开发一个iOS应用程序,目前使用Swift/Xcode 6.1 GM 2进行开发

在临时分发应用程序时,我们在密钥链访问方面遇到了一些令人困惑的问题,并且在跟踪原因方面遇到了问题。所有配置文件都与我们应用程序的捆绑包名称匹配。我们使用TestFlight进行分发,尽管我认为这不是问题所在

我们只设法让它在iOS 7设备上工作,而这些设备之前没有安装该应用程序。没有一台iOS 8设备可以临时工作。我们在开始时遇到的错误是25300(errSecItemNotFound),现在在重置配置文件后,我们得到的是一个普通的0(加载时保存,但仍然无法检索数据)。从Xcode部署dev构建时,一切都能完美工作

我已经分离了我们使用的钥匙链包装器的代码:

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
}


}
导入UIKit
进口担保
让serviceIdentifier=“com.Test.KeychainTest”
让kSecClassValue=kSecClass作为NSString
让kSecAttrAccountValue=kSecAttrAccount作为NSString
让kSecValueDataValue=kSecValueData作为NSString
让kSecClassGenericPasswordValue=kSecClassGenericPassword作为NSString
让kSecAttrServiceValue=kSecAttrService作为NSString
让kSecMatchLimitValue=kSecMatchLimit作为NSString
让kSecReturnDataValue=kSecReturnData作为NSString
将kSecMatchLimitOneValue=kSecMatchLimitOne作为NSString
类密钥链管理器{
类func setString(值:NSString,forKey:String){
保存(serviceIdentifier,键:forKey,数据:value)
}
类func stringForKey(键:String)->NSString{
var token=self.load(serviceIdentifier,key:key)
返回令牌
}
类func removeItemForKey(键:字符串){
self.save(serviceIdentifier,key:key,data:)
}
类func save(服务:NSString,键:String,数据:NSString){
var dataFromString:NSData=data.dataUsingEncoding(NSUTF8StringEncoding,allowossyconversion:false)!
//实例化新的默认密钥链查询
var keychainQuery:NSMutableDictionary=NSMutableDictionary(对象:[kSecClassGenericPasswordValue,服务,键,dataFromString],分叉:[kSecClassValue,kSecAttrServiceValue,kSecAttrAccountValue,kSecValueDataValue])
//删除任何现有项目
SecItemDelete(keychainQuery作为CFDictionaryRef)
如果数据==”{return}
//添加新的钥匙链项目
变量状态:OSStatus=SecItemAdd(keychainQuery作为CFDictionaryRef,nil)
var alertView=UIAlertView();
alertView.addButtonWithTitle(“确定”);
alertView.title=“状态”;
alertView.message=“正在保存\(状态)”;
alertView.show();
}
类func load(服务:NSString,键:String)->NSString{
//实例化新的默认密钥链查询
//告诉查询返回一个结果
//将结果限制为一项
var keychainQuery:NSMutableDictionary=NSMutableDictionary(对象:[kSecClassGenericPasswordValue,服务,键,kCFBooleanTrue,kSecMatchLimitOneValue],forKeys:[kSecClassValue,kSecAttrServiceValue,kSecAttrAccountValue,kSecReturnDataValue,kSecMatchLimitValue])
var dataTypeRef:非托管?
//搜索钥匙链项目
let状态:OSStatus=SecItemCopyMatching(keychainQuery和dataTypeRef)
var alertView=UIAlertView();
alertView.addButtonWithTitle(“确定”);
alertView.title=“状态”;
alertView.message=“正在加载\(状态)”;
alertView.show();
设不透明=dataTypeRef?.toOpaque()
var contentsOfKeychain:NSString?
如果让op=不透明{
让retrievedData=Unmanaged.from不透明(op).takeUnrepainedValue()
//将从钥匙链检索的数据转换为字符串
contentsOfKeychain=NSString(数据:retrievedData,编码:NSUTF8StringEncoding)
}否则{
归零
}
返回密钥链的内容
}
}
  • 有什么我们可能错过的吗
  • 解决此问题的最佳方法是什么?logs/iPhone配置实用程序中的keychain没有出现任何错误。目前,我只是在代码中添加了一些简单的警报,以了解操作的状态

  • 确保还为
    ksecattracessible
    指定了值。还可以指定
    ksecattraccescontrol
    的值,即。

    设置配置文件和钥匙链代码中的所有内容都正常。问题是Swift编译器中的设置。。。将“Release”的优化级别从“faster”更改为“None”,这似乎解决了问题


    考虑到Swift在没有优化的情况下速度有多慢,这是一个可怕的解决方案。也许对单个文件关闭优化会更好。@jshier您能解释一下如何对单个文件进行优化吗?在目标“构建阶段”->“编译源代码”中,双击“编译器标志”列并添加-Onone设置。@jshier感谢您的评论。我们将试一试,看看它的表现:)