简体   繁体   English

Swift钥匙串和配置文件

[英]Swift keychain and provisioning profiles

We've created an app in swift that uses keychain. 我们在swift中创建了一个使用钥匙串的应用程序。 The app works fine when run on a device or in the simulator but can't access the keychain when provisioned via Testflight unless provisioned to a new device that's never had the app previously installed via Xcode 6.1. 该应用程序在设备或模拟器上运行时工作正常,但在通过Testflight配置时无法访问钥匙串,除非配置到以前从未安装过通过Xcode 6.1安装的应用程序的新设备。

Following is an excerpt of the keychain code: 以下是钥匙串代码的摘录:

    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
    }  
  }

After the app was already installed on the device via Xcode 6.1 I noticed that the " serviceIdentifier " - " com.ourdomain " was incorrect and didn't match the app's bundle identifier as required with provisioning. 在应用程序已经通过Xcode 6.1安装在设备上之后,我注意到“ serviceIdentifier ” - “ com.ourdomain ”不正确,并且与配置所需的应用程序包标识符不匹配。

I then changed the " serviceIdentifier " value to match the bundle identifier - " com.ourdomain.appname " however the app just won't work on the device when provisioned via Testflight. 然后我更改了“ serviceIdentifier ”值以匹配包标识符 - “ com.ourdomain.appname ”,但是当通过Testflight进行配置时,应用程序将无法在设备上运行。 I'm positive this is because the device already has the keychain for the bundle id installed with the incorrect identifier but I can't fathom how to get around this to either remove the keychain when the app is removed or get the provisioning profile to use the existing keychain (with the incorrect identifier) 我很肯定这是因为设备已经安装了带有错误标识符的软件包ID的钥匙串,但是我无法理解如何解决这个问题,以便在移除应用程序时移除钥匙串或者使用配置文件来使用现有的钥匙串(标识符不正确)

Any help would be greatly appreciated. 任何帮助将不胜感激。 Thanks in advance 提前致谢

Use withUnsafeMutablePointer function and UnsafeMutablePointer struct to retrieving the data instead, like below: 使用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) {
            // ...
        }
    }
}

it works fine with release (Fastest optimization) build. 它在发布(最快优化)版本时运行良好。

Ok so everything in the provisioning profile and keychain code was fine. 好吧,供应配置文件和钥匙串代码中的所有内容都很好。 The problem was a setting in the Swift compiler! 问题是Swift编译器中的一个设置! Changing the Optimization Level for "Release" from "Fastest" to "None" seemed to resolve the issue. 将“释放”的优化级别从“最快”更改为“无”似乎解决了这个问题。

在此输入图像描述

The change of the swift optimizer is working, but not a good way to solve the problem. swift优化器的更改正在起作用,但不是解决问题的好方法。 As stated in the comments, this seems to be a bug in the swift compiler with the optimization. 正如评论中所述,这似乎是swift编译器中的优化错误。

This is not iOS only, the exact same thing happens on OSX (maybe add a tag to the question). 这不仅仅是iOS,在OSX上完全相同(可能在问题中添加标签)。 The OSStatus is 0 (success) but the referencing pointer is nil as soon as the optimization is done. OSStatus为0(成功),但一旦优化完成,引用指针就为零。

The best workaround is to implement to keychain communication in objective-c or using a wrapper like EMKeychain (OSX only, sorry don't know an iOS Wrapper at the moment) 最好的解决方法是在objective-c中实现keychain通信或使用像EMKeychain这样的包装器(仅限OSX,抱歉暂时不知道iOS Wrapper)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 iOS Keychain访问和配置文件 - iOS Keychain access and Provisioning Profiles iOS 中的钥匙串访问和配置文件 - Keychain access in iOS and provisioning profiles 您可以使用钥匙串在配置文件之间共享数据吗? - Can you share data across provisioning profiles using the keychain? “代码签名错误:找不到包含任何钥匙串签名证书的未过期配置文件” - “Code Sign error: No unexpired provisioning profiles found that contain any of the keychain's signing certificates” 代码签名错误:找不到包含任何钥匙串签名证书的未过期配置文件 - Code Sign error: No unexpired provisioning profiles found that contain any of the keychain's signing certificates ios-未找到未过期的配置文件,其中包含任何钥匙串的签名证书 - ios - No unexpired provisioning profiles found that contain any of the keychain's signing certificates “未找到包含任何钥匙串签名证书的未过期配置文件”恐怖 - "No unexpired provisioning profiles found that contain any of the keychain's signing certificates" Horror 无法在Xcode 7.2上使用Swift的设备上构建(与Provisioning Profiles不相关) - Can't build on device with Swift on Xcode 7.2 (not related to Provisioning Profiles) iOS设置和钥匙串生成 - iOS provisioning and keychain generation 创建配置文件 - creating provisioning profiles
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM