Keychain + adhoc distribution

2019-03-21 04:52发布

问题:

To begin, some details : we are developing an iOS application currently using Swift/Xcode 6.1 GM 2 for development.

We are having some confusing problems with keychain access when distributing applications ad hoc and have issues with tracking down what's the reason. All the provisioning profiles are matching the bundle name of our app. We use TestFlight for distribution although I don't think it's the problem.

We have only managed to get it to work on iOS 7 devices that didn't have the app installed earlier. Not a single iOS 8 device worked ad hoc. The errors we were getting in the beginning were 25300 (errSecItemNotFound) and now after resetting provisioning profiles we are getting a plain 0 (both on saving on loading and still no data can be retrieved). Everything works perfectly when deploying dev builds from Xcode.

I have separated the code for the keychain wrapper that we use :

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
}


}
  1. Is there anything that we might have missed?
  2. What is the best way to troubleshoot this problem? We are not getting any errors from keychain in the logs / iPhone configuration utility. At the moment I just put some simple alerts into the code to figure out what the status of the operation is.

回答1:

Everything in the provisioning profile and keychain code appears to be fine. The problem is a setting in the Swift compiler ... Change the Optimization Level for "Release" from "Fastest" to "None" and this seems to resolve the problem



回答2:

Make sure you also specify value for kSecAttrAccessible. Maybe also specify value for kSecAttrAccessControl, which was added in iOS8.