Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xcode/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios Swift密钥链和配置配置文件_Ios_Xcode_Swift_Keychain_Testflight - Fatal编程技术网

Ios Swift密钥链和配置配置文件

Ios Swift密钥链和配置配置文件,ios,xcode,swift,keychain,testflight,Ios,Xcode,Swift,Keychain,Testflight,我们在swift中创建了一个使用钥匙链的应用程序。该应用程序在设备或模拟器上运行时工作正常,但通过Testflight设置时无法访问密钥链,除非设置到以前从未通过Xcode 6.1安装过该应用程序的新设备 以下是钥匙链代码的摘录: import UIKit import Security let serviceIdentifier = "com.ourdomain" let kSecClassValue = kSecClass as NSString

我们在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
    }  
  }
导入UIKit
进口担保
让serviceIdentifier=“com.ourdomain”
让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)
}
类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)
设不透明=dataTypeRef?.toOpaque()
var contentsOfKeychain:NSString?
如果让op=不透明{
让retrievedData=Unmanaged.from不透明(op).takeUnrepainedValue()
//将从钥匙链检索的数据转换为字符串
contentsOfKeychain=NSString(数据:retrievedData,编码:NSUTF8StringEncoding)
}否则{
归零
}
返回密钥链的内容
}  
}
在通过Xcode 6.1将应用程序安装到设备上后,我注意到“serviceIdentifier”-“com.ourdomain”不正确,并且与配置所需的应用程序包标识符不匹配

然后,我更改了“serviceIdentifier”值以匹配捆绑包标识符-“com.ourdomain.appname”,但是当通过Testflight进行配置时,应用程序无法在设备上运行。我敢肯定,这是因为该设备已经安装了捆绑id的密钥链,并且该密钥链的标识符不正确,但我不知道如何绕过此问题,在删除应用程序时删除密钥链,或者获取配置配置文件以使用现有的密钥链(标识符不正确)


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

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


swift优化器的更改正在起作用,但不是解决问题的好方法。 如评论中所述,这似乎是swift编译器中的一个bug,并进行了优化

这不仅仅是iOS,OSX上也会发生同样的事情(可能会在问题中添加标签)。 OSStatus为0(成功),但优化完成后引用指针为零


最好的解决方法是在objective-c中实现键链通信或使用类似的包装器(仅限OSX,抱歉,目前不知道iOS包装器)

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

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

它适用于发布版(最快的优化)构建。

我也有同样的问题。当您将优化级别设置为-O时,看起来dataTypeRef?.toOpaque()返回nil。但是,我不认为将优化级别设置为-Onone不是一个解决方案,因为它会使您的代码速度慢得多。我在Xcode 6.1(6A1052d)中遇到了同样的问题,并向苹果公司报告了这个bug(bug 19003552,如果有帮助的话)。任何遇到这种情况的人都应该像复制品一样,帮助确定问题的优先级。@JorgeDeCorte-谢谢。也许我们需要尝试显式地打开dataTypeRef。。。你试过了吗我想看看这是否能解决问题,我现在面临的问题与使用Swift IMHO访问密钥链的问题完全相同。我的解决办法是在Objective-C中这样做,因为这是一个Swift特定问题。我使用的是锁盒吊舱,效果很好。这确实会使功能正常工作,但不是一个可行的解决方案。“与Unsafemeutablepointer函数和Unsafemeutablepointer一起使用”是