使用 Swift 查询 iOS 钥匙串
Posted
技术标签:
【中文标题】使用 Swift 查询 iOS 钥匙串【英文标题】:Querying iOS Keychain using Swift 【发布时间】:2014-06-10 16:08:58 【问题描述】:我无法使用 Swift 转换钥匙串查询结果。
我的请求似乎奏效了:
let queryAttributes = NSDictionary(objects: [kSecClassGenericPassword, "MyService", "MyAccount", true],
forKeys: [kSecClass, kSecAttrService, kSecAttrAccount, kSecReturnData])
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
var dataTypeRef : Unmanaged<AnyObject>?
let status = SecItemCopyMatching(queryAttributes, &dataTypeRef);
let retrievedData : NSData = dataTypeRef!.takeRetainedValue() as NSData
*** ^^^^can't compile this line^^^^
)
我的问题是,代码无法编译:
Bitcast requires both operands to be pointer or neither
%114 = bitcast %objc_object* %113 to %PSs9AnyObject_, !dbg !487
Bitcast requires both operands to be pointer or neither
%115 = bitcast %PSs9AnyObject_ %114 to i8*, !dbg !487
LLVM ERROR: Broken function found, compilation aborted!
我不知道如何将Unmanaged<AnyObject>
转换为NSData
。
有什么想法吗?
【问题讨论】:
我也在尝试访问 ios 钥匙串,我看到了你的帖子。我不知道如何创建查询字典。我什至将您上面的第一行复制到我的应用程序中,它也说了同样的话。 “找不到接受提供的参数的 'init' 的重载”。我错过了什么吗? 与 2015 年 3 月 11 日最新 XCode 相同的问题 如果你正在寻找一个简单的插入式钥匙串包装器,你可以试试这个:github.com/ashleymills/Keychain.swift 【参考方案1】:使用withUnsafeMutablePointer
函数和UnsafeMutablePointer
结构来检索数据,例如:
var result: AnyObject?
var status = withUnsafeMutablePointer(&result) SecItemCopyMatching(queryAttributes, UnsafeMutablePointer($0))
if status == errSecSuccess
if let data = result as NSData?
if let string = NSString(data: data, encoding: NSUTF8StringEncoding)
// ...
它适用于发布(最快 [-O])构建。
【讨论】:
这是发布应用程序时唯一对我有用的解决方案(其他解决方案在 xcode 中运行良好,但在分发应用程序的 beta 版本时不行)。 这应该是正确的答案。其他的将无法在发布版本中工作。 你是明星,岸川。不幸的是,无法使用您的包装器,因为它需要 8.0,但这让我很满意。 就我而言,这也是发布版本中唯一可行的解决方案。另外,我很想知道为什么其他实现在发布版本中不起作用。 +1 这对我也有用。非常感谢!另一种方法仅适用于 iPhone 5S+。在 iPhone 5 上,它会崩溃。【参考方案2】:您似乎遇到了编译器错误,您应该报告。您可以采用不同的路径来检索该值,例如:
var dataTypeRef :Unmanaged<AnyObject>?
let status = SecItemCopyMatching(queryAttributes, &dataTypeRef);
let opaque = dataTypeRef?.toOpaque()
if let op = opaque?
let retrievedData = Unmanaged<NSData>.fromOpaque(op).takeUnretainedValue()
将AnyObject
用作Unmanaged<T>
的类型参数T
时会出现错误。以下代码 sn-p 编译没有问题,它使用更具体的类型,CFError
:
let url = NSURL(string:"dummy")
var errorRef: Unmanaged<CFError>?
let succeeded = CTFontManagerRegisterFontsForURL(url, .Process, &errorRef)
if errorRef
let error = errorRef!.takeRetainedValue()
由于 Keychain API 根据查询属性返回不同的结果,因此需要使用AnyObject
。
【讨论】:
非常感谢您的回答。然后我会报告它,也许会等着看是否在下一个测试版中修复。如果没有,我将使用此代码。再次感谢! 当您将 Swift 编译器 - 优化级别设置为 -Onone 时,这似乎可以正常工作。但是当你将它设置为 -O 时。不透明将为零。使用 Xcode 6.1(6A1052d) 构建 我在let opaque = dataTypeRef?.toOpaque()
(Xcode 6.1 & 6.2b) 线上遇到了错误的访问异常【参考方案3】:
要使其工作,您需要首先访问每个钥匙串常量的保留值。例如:
let kSecClassValue = kSecClass.takeRetainedValue() as NSString
let kSecAttrAccountValue = kSecAttrAccount.takeRetainedValue() as NSString
let kSecValueDataValue = kSecValueData.takeRetainedValue() as NSString
let kSecClassGenericPasswordValue = kSecClassGenericPassword.takeRetainedValue() as NSString
let kSecAttrServiceValue = kSecAttrService.takeRetainedValue() as NSString
let kSecMatchLimitValue = kSecMatchLimit.takeRetainedValue() as NSString
let kSecReturnDataValue = kSecReturnData.takeRetainedValue() as NSString
let kSecMatchLimitOneValue = kSecMatchLimitOne.takeRetainedValue() as NSString
然后您需要像这样引用您在钥匙串字典对象中创建的常量。
var keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, userAccount, kCFBooleanTrue, kSecMatchLimitOneValue], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecReturnDataValue, kSecMatchLimitValue])
我写了一篇关于它的博客文章:http://rshelby.com/2014/08/using-swift-to-save-and-query-ios-keychain-in-xcode-beta-4/
希望这会有所帮助!
谢尔比
【讨论】:
以上是关于使用 Swift 查询 iOS 钥匙串的主要内容,如果未能解决你的问题,请参考以下文章
升级到 iOS 13 后,钥匙串查询总是返回 errSecItemNotFound