在设备或 iOS 目标上运行时钥匙串单元测试失败

Har*_*lue 5 keychain ios keychainitemwrapper swift

我有一个 iOS 项目。

我今天提取了一些身份验证代码并将其移至它自己的项目中。

该项目支持 macOS 和 iOS。

我创建了一个包含 iOS 项目和 Auth 项目的工作区,并且我已通过面板将 auth 添加.framework到我的 iOS 项目中Frameworks, Libraries, and Embedded Content

我可以构建和使用我的服务。我还设置了一个自定义方案CI_iOS,允许我为这些项目运行测试。

我现在已经在我的身份验证模块中添加了一些集成测试,这样我就可以KeychainTokenStore根据真正的钥匙串测试我的类。

这些在针对 macOS 测试我的模块时有效,但是尝试在 iOS 模拟器上运行它们时,它们都失败了。

我可以看到,当尝试与钥匙串交互时,会返回一个错误代码-34018,我相信这表明了这一点errSecMissingEntitlement

我读过很多帖子,似乎建议我需要启用钥匙串共享。

然而我似乎无法完成这项工作。

我的KeychainTokenStore样子是这样的


import Foundation


public protocol TokenStore {
  typealias DeleteCacheResult = Result<Void, Error>
  typealias DeleteCacheCompletion = (DeleteCacheResult) -> Void

  typealias InsertCacheResult = Result<Void, Error>
  typealias InsertCacheCompletion = (InsertCacheResult) -> Void

  typealias RetrieveCacheResult = Result<String?, Error>
  typealias RetrieveCacheCompletion = (RetrieveCacheResult) -> Void

  /// The completion handler can be invoked in any thread.
  /// Clients are responsible for dispatching to the appropriate thread, if needed.
  func insert(_ token: String, key: String, completion: @escaping InsertCacheCompletion)

  /// The completion handler can be invoked in any thread.
  /// Clients are responsible for dispatching to the appropriate thread, if needed.
  func delete(_ key: String, completion: @escaping DeleteCacheCompletion)

  /// The completion handler can be invoked in any thread.
  /// Clients are responsible for dispatching to the appropriate thread, if needed.
  func retrieve(_ key: String, completion: @escaping RetrieveCacheCompletion)
}


public final class KeychainTokenStore: TokenStore {

  public enum Error: Swift.Error {
    case saveFailed
  }

  public init() { }

  private lazy var queue = DispatchQueue(label: "KeychainTokenStore.queue", qos: .userInitiated, attributes: .concurrent)

  public func insert(_ token: String, key: String, completion: @escaping InsertCacheCompletion) {
    queue.async(flags: .barrier) {
      completion(Result {
        let query = [
          kSecClass: kSecClassGenericPassword,
          kSecAttrAccount: key,
          kSecValueData: Data(token.utf8)
          ] as CFDictionary

        SecItemDelete(query)

        guard SecItemAdd(query, nil) == noErr else { throw Error.saveFailed }
      })
    }
  }

  public func delete(_ key: String, completion: @escaping DeleteCacheCompletion) {
    queue.async(flags: .barrier) {
      completion(Result {
        let query = [
          kSecClass: kSecClassGenericPassword,
          kSecAttrAccount: key,
          ] as CFDictionary

        SecItemDelete(query)
      })
    }
  }

  public func retrieve(_ key: String, completion: @escaping RetrieveCacheCompletion) {
    queue.async {
      let query = [
        kSecClass: kSecClassGenericPassword,
        kSecAttrAccount: key,
        kSecReturnData: kCFBooleanTrue as Any,
        kSecMatchLimit: kSecMatchLimitOne
        ] as CFDictionary

      var result: AnyObject?
      let status = SecItemCopyMatching(query, &result)

      guard status == noErr, let data = result as? Data else {
        return completion(.success(.none))
      }

      completion(Result {
        String(decoding: data, as: UTF8.self)
      })
    }
  }
}

Run Code Online (Sandbox Code Playgroud)

在我的 iOS 应用程序中,我启用了共享,如下所示:

共享钥匙串

然而,当我尝试在我的身份验证框架中启用共享时,我看到以下内容

错误

如何确保我的DigiAuth框架可以在运行项目时访问钥匙串DigiApp

小智 1

我遇到了类似的问题并设法用这个答案修复它:/sf/answers/2841117121/

您需要做的就是

  1. 将新的应用程序目标添加到您的项目中
  2. 为此目标启用钥匙串共享
  3. 转到项目的测试目标并将主机应用程序设置为您在步骤 1 中创建的应用程序