4.6 KiB
4.6 KiB
SingleValueStorage - протокол для доступа к значению которое может храниться в Keychain, UserDefaults или ещё где-то.
Позволяет:
- инкапсулировать внутри себя логику получения, записи и удаления значения
- добавлять дополнительную логику для получения или изменения значений через композицию или наследование
- ограничить доступ к данным в UserDefaults или Keychain в разных частях приложения
StringValueKeychainStorage
Класс для работы со строковым значением нахоящимся в keychain (самый частый кейс)
import TIKeychainUtils
import TIFoundationUtils
import KeychainAccess
extension StorageKey {
static var apiToken: StorageKey<String> {
.init(rawValue: "apiToken")
}
static var deleteApiToken: StorageKey<Bool> {
.init(rawValue: "deleteApiToken")
}
}
let keychain = Keychain()
let apiTokenKeychainStorage = StringValueKeychainStorage(keychain: keychain, storageKey: .apiToken)
if apiTokenKeychainStorage.hasStoredValue() {
// open auth user flow, perform requests
} else {
// show login screen
// ...
// login
// switch await userService.login() {
// case .success:
// // open auth user flow, perform requests
// case .failure:
// // show login screen
// }
}
AppInstallLifetimeSingleValueStorage<SingleValueStorage>
Класс позволяющий добавить дополнительную функциональность очистки значения по конкретному ключу в keychain после переустановки приложения
import Foundation
let defaults = UserDefaults.standard // or AppGroup defaults
let appReinstallChecker = DefaultAppFirstRunCheckStorage(defaults: defaults,
storageKey: .deleteApiToken)
let appInstallAwareTokenStorage = apiTokenKeychainStorage.appInstallLifetimeStorage(appFirstRunCheckStorage: appReinstallChecker)
if appInstallAwareTokenStorage.hasStoredValue() {
// app wasn't reinstalled, token is exist
} else {
// app was reinstalled or token is empty
// ...
}
SingleValueExpirationStorage<SingleValueStorage>
Класс позволяющий добавить дополнительную функциональность очистки значения по конкретному ключу если истёк срок действия объекта (например refresh token'а)
struct Token: Codable, Equatable {
var value: String
var expiration: Date
init(value: String, expiration: Date) {
self.value = value
self.expiration = expiration
}
}
extension StorageKey {
static var accessToken: StorageKey<Token> {
.init(rawValue: "accessToken")
}
}
let accessTokenStorage = DefaultSingleValueCodableStorage(storage: keychain,
storageKey: .accessToken,
decoder: JSONKeyValueDecoder(),
encoder: JSONKeyValueEncoder())
let expirationCheckStorage = accessTokenStorage.isExpireCheck { $0.expiration.timeIntervalSinceNow > 0 }
switch expirationCheckStorage.getValue() {
case let .success(token):
// use token
break
case let .failure(storageError):
if case .valueNotFound = storageError {
// token is missing or expired, request new token
} else {
// handle storage error
}
break
}
MigratingStorage
При необходимости мигрировать с одного keychain на другой можно воспользоваться классом MigratingSingleValueStorage. При создании "мигрирующего" хранилища необходимо будет указать:
- source storage: хранилище с которого мигрируем
- target storage: хранилище на которое мигрируем
let groupKeychain = Keychain(service: "app.group.identifier")
let targetApiTokenKeychainStorage = StringValueKeychainStorage(keychain: groupKeychain, storageKey: .apiToken)
let migratingApiTokenKeychainStorage = apiTokenKeychainStorage.migrating(to: targetApiTokenKeychainStorage)
let token = migratingApiTokenKeychainStorage.getValue()