SessionTools

CI Status Version Carthage compatible License Platform codecov codebeat badge

目的

这个库旨在简化会话管理。它有几个主要目标:

关键概念

用法

SessionTools 开箱即用,使用钥匙串来存储您的会话数据。 为了实现最大的灵活性,您可以使用SessionTools/Base子规范来集成 SessionTools,而无需钥匙串依赖项。接下来,我们假设您在 iOS 上使用它,并且想要使用钥匙串。

准备

1. 创建一个符合Codable协议的模型对象。

您可能已经在代码库中创建了它的某种变体。

struct Model: Codable {
    let firstName: String
    let lastName: String
    let email: String
    let token: String
}
2. 创建一个提供keychainNameKeychainContainerConfig

默认的容器配置使用非托管的钥匙串容器。 这意味着该框架不会尝试为您删除会话的数据,并且您将负责在需要时通过调用Session.deleteItem()来删除此会话的数据。 由于操作系统版本之间的差异,我们无法保证数据在当前安装之外在钥匙串中持续存在的时间。 有关更多讨论,请参阅下面。

let config = KeychainContainerConfig(keychainName: "your.keychain.name")

如果您只希望会话的数据在当前安装中持续存在,请使用生命周期KeychainLifecycle.currentInstall()实例化您的KeychainContainerConfig,并传入安装标识符。 该标识符应在当前安装中保持稳定,但在安装之间发生变化。

此安装标识符在运行钥匙串操作之前会附加到钥匙串名称中。 因为标识符在安装之间发生变化,所以先前的密钥将不再匹配。 理论上,如果您重复使用先前的安装标识符,您仍然可以取回该密钥,但由于操作系统版本之间的差异,我们无法保证数据在当前安装之外在钥匙串中持续存在的时间。 有关更多讨论,请参阅下面。

let managedConfig = KeychainContainerConfig(keychainName: "com.app.name", lifecycle: .currentInstall(identifier: installationIdentifier))
3. 创建一个提供您的KeychainContainerConfigKeychainStorageContainer
let container = KeychainStorageContainer<Model>(config: config)

如果您不想使用默认的钥匙串存储机制,您还可以创建自己的符合SessionContainer的对象并实例化它。

struct MyStorageContainer: SessionContainer {
    func hasItem(forIdentifier identifier: String) -> Bool {
        // ...
    }

    func item(forIdentifier identifier: String, jsonDecoder: JSONDecoder) throws -> Item? {
        // ...
    }

    func removeItem(forIdentifier identifier: String) throws {
        // ...
    }

    func storeItem(_ item: Item, forIdentifier identifier: String, jsonEncoder: JSONEncoder) throws {
        // ...
    }
}
4. 将您的存储容器包装在AnySessionContainer类型擦除容器中。
let anyContainer = AnySessionContainer(container)

现在,您可以通过几种不同的方式使用Session

选项 1 - 按原样使用Session<T>类。

您只需要提供模型对象的类型、存储它的容器以及将在存储容器中与您的对象关联的密钥。

let session = Session<Model>(container: anyContainer, storageIdentifier: "identifier.for.your.model.object")
选项 2 - 创建一个Session<T>的子类,为泛型占位符类型提供您的模型。

可选地,如果您想在模型过期时自动处理刷新(例如,API 令牌),请遵守Refreshable协议。

class ModelSession: Session<Model>, Refreshable {
    // your class code here

    // MARK: - Refreshable

    func refresh(completion: @escaping RefreshCompletion) {
        // your refresh code here
        completion(nil)
    }
}
选项 3 (最常见) - 使用UserSession<T>,一个Session<T>子类,已为您设置好以处理常见的登录/注销操作
let userSession = UserSession<Model>(container: anyContainer, storageIdentifier: "identifier.for.your.model.object", notificationPoster: NotificationCenter.default)

如果您想在模型过期时自动处理刷新(例如,API 令牌),您还可以将refreshHandler提供给 UserSession 初始化器。

private static func userRefreshHandler(_ completion: @escaping RefreshCompletion) -> Void {
    // your refresh code
    completion(nil)
}

let userSession = UserSession<Model>(container: container, storageIdentifier: "identifier.for.your.model.object", notificationPoster: NotificationCenter.default, refreshHandler: userRefreshHandler)

现在,您可以轻松获取对应用程序当前用户的引用。

let currentUser = userSession.currentUser

您还可以检查当前是否有用户登录。

let isUserLoggedIn = userSession.isLoggedIn

UserSession<T>还包含可以调用以在您认为合适时登录、注销或更新信息的方法。

do {
    try userSession.didLogIn(model)
    try userSession.didLogOut(nil) // Optionally provide the error that triggered the logout
    try userSession.didUpdate(model)
} catch {
    // Handle container read/write errors here
}

您的代码部分可以选择通过订阅Notification.Name.userSessionStateDidChange通知来观察这些登录/注销/更新事件。

NotificationCenter.default.addObserver(self, selector: #selector(didUpdateUser:), name: .userSessionStateDidChange, object: nil)

访问通知上的userSessionState属性以轻松获取发生的状态更改。

@objc private func didUpdateUser(_ notification: Notification) {
    guard let sessionState = notification.userSessionState else { return }

    // Do something with the state
    switch sessionState {
    case .loggedIn:
        // ...
    case .loggedOut(let error): // Optionally get a reference to the error that triggered the logout
        // ...
    case .updated:
        // ...
    }
}

示例

要运行示例项目,您首先需要使用 Carthage 来安装 SessionTool 的依赖项 (KeychainAccess

安装 Carthage 后,克隆存储库

git clone https://github.com/BottleRocketStudios/iOS-SessionTools.git

接下来,使用 Carthage 安装依赖项

carthage update

从这里开始,您可以打开SessionTools.xcworkspace并运行示例

要求

安装

Swift Package Manager

dependencies: [
    .package(url: "https://github.com/BottleRocketStudios/iOS-SessionTools.git", from: "1.2.0")
]

CocoaPods

SessionTools 可通过 CocoaPods 获得。 要安装它,只需将以下行添加到您的 Podfile 中

pod 'SessionTools'

或者,如果您不在可以访问钥匙串的环境中工作,请使用基本子规范

pod 'SessionTools/Base'

Carthage

将以下内容添加到您的 Cartfile

github "BottleRocketStudios/iOS-SessionTools"

运行 carthage update 并按照 Carthage 的 README 中描述的步骤操作。

注意:如果您的环境可以访问钥匙串,请不要忘记将SessionTools.frameworkKeychainAccess.framework依赖项都添加到您的项目中。

钥匙串讨论

过去,您从应用程序添加的钥匙串数据会在安装之间持续存在。 虽然现在仍然如此,但我们无法保证这种情况在未来的版本中仍然如此。 这篇文章 总结了这一事实。 在 iOS 10.3 Beta 2 中,Apple 添加了一项功能,可以在卸载时删除所有应用程序钥匙串数据,但在导致现有应用程序出现问题时又恢复了。 如果 Apple 规范化了这种行为,我们也会在这里规范化。

贡献

请参阅 CONTRIBUTING 文档。 谢谢 贡献者