发音 Cell-Lee
Cely 的目标是将登录系统添加到您的应用程序中,整个过程不超过 30 秒!
概述
Cely 的目标是将登录系统添加到您的应用程序中,整个过程不超过 30 秒!
背景
无论您是在为客户端构建应用还是为黑客马拉松构建应用,构建一个无论多基础的登录系统都可能非常繁琐且耗时。Cely 的架构在 countless 应用程序中经过了实战测试,Cely 保证以极短的时间为您提供功能完善的登录系统。由于 Cely 是建立在 Locksmith 上,Swift 最受欢迎的 Keychain 包装器,您可以信任 Cely 正确处理登录凭据。
细节
Cely 为您做了什么?
- 简单的 API,可以安全地存储用户凭据和信息
Cely.save("SUPER_SECRET_STRING", forKey: "token", securely: true)
- 使用以下操作管理应用程序主屏幕和登录屏幕之间的切换
Cely.changeStatus(to: .loggedIn) // 或 .loggedOut
- 可定制的初始登录屏幕(或者您可以使用自己的登录屏幕)
Cely 为您没有做什么?
- 网络请求
- 处理网络错误
- 任何与网络相关的事情
功能需求
- iOS 11.0+
- Xcode 9.0+
- Swift 4.0+
使用指南
设置(30秒)
用户模型(《User.swift》)
让我们首先创建一个遵循CelyUser
协议的User
模型
// User.swift
import Cely
struct User: CelyUser {
enum Property: CelyProperty {
case token = "token"
}
}
登录重定向(《AppDelegate.swift》)
Cely的简易设置功能将使您在几秒钟内启动。在您的《AppDelegate.swift》中,只需导入Cely
并调用位于didFinishLaunchingWithOptions
方法内的setup(_:)
功能。
// AppDelegate.swift
import Cely
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: Any]?) -> Bool {
Cely.setup(with: window, forModel: User(), requiredProperties: [.token])
...
}
单击RUN!!
CelyOptions
处理登录凭据
现在我们如何从Cely的默认LoginViewController获取username
和password
?很简单,只需在.loginCompletionBlock
中传递一个完成块。关于更多信息,请查看CelyOptions
。
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
Cely.setup(with: window!, forModel: User(), requiredProperties: [.token], withOptions: [
.loginCompletionBlock: { (username: String, password: String) in
if username == "asdf" && password == "asdf" {
Cely.save(username, forKey: "username")
Cely.save("FAKETOKEN:\(username)\(password)", forKey: "token", securely: true)
Cely.changeStatus(to: .loggedIn)
}
}
])
return true
}
自定义默认登录屏
创建一个符合CelyStyle
协议的对象,并在调用Cely的setup(_:)
方法时,将其设置为CelyOptions
字典中的.loginStyle
。
// LoginStyles.swift
struct CottonCandy: CelyStyle {
func backgroundColor() -> UIColor {
return UIColor(red: 86/255, green: 203/255, blue: 249/255, alpha: 1) // Changing Color
}
func buttonTextColor() -> UIColor {
return .white
}
func buttonBackgroundColor() -> UIColor {
return UIColor(red: 253/255, green: 108/255, blue: 179/255, alpha: 1) // Changing Color
}
func textFieldBackgroundColor() -> UIColor {
return UIColor.white.withAlphaComponent(0.4)
}
func appLogo() -> UIImage? {
return UIImage(named: "CelyLogo")
}
}
...
// AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
Cely.setup(with: window!, forModel: User.ref, requiredProperties: [.token], withOptions: [
.loginStyle: CottonCandy(), // <--- HERE!!
.loginCompletionBlock: { ... }
])
return true
}
自定义转换
为了创建自定义转换,创建一个符合CelyAnimator
协议的对象,并在调用Cely的setup(_:)
方法时,将其设置为CelyOptions
字典中的.celyAnimator
。
struct DefaultAnimator: CelyAnimator {
func loginTransition(to destinationVC: UIViewController?, with celyWindow: UIWindow) {
guard let snapshot = celyWindow.snapshotView(afterScreenUpdates: true) else {
return
}
destinationVC?.view.addSubview(snapshot)
// Set the rootViewController of the `celyWindow` object
celyWindow.setCurrentViewController(to: destinationVC)
// Below here is where you can create your own animations
UIView.animate(withDuration: 0.5, animations: {
// Slide login screen to left
snapshot.transform = CGAffineTransform(translationX: 600.0, y: 0.0)
}, completion: {
(value: Bool) in
snapshot.removeFromSuperview()
})
}
func logoutTransition(to destinationVC: UIViewController?, with celyWindow: UIWindow) {
guard let snapshot = celyWindow.snapshotView(afterScreenUpdates: true) else {
return
}
destinationVC?.view.addSubview(snapshot)
// Set the rootViewController of the `celyWindow` object
celyWindow.setCurrentViewController(to: destinationVC)
// Below here is where you can create your own animations
UIView.animate(withDuration: 0.5, animations: {
// Slide home screen to right
snapshot.transform = CGAffineTransform(translationX: -600.0, y: 0.0)
}, completion: {
(value: Bool) in
snapshot.removeFromSuperview()
})
}
}
...
// AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
Cely.setup(with: window!, forModel: User.ref, requiredProperties: [.token], withOptions: [
.celyAnimator: CustomAnimator(), // <--- HERE!!
.loginCompletionBlock: { ... }
])
return true
}
使用自定屏幕
要使用自己的登录屏幕,请简单地创建一个包含您的登录屏幕的Storyboard,并在调用Cely的setup(_:)
方法时,将其作为CelyOptions
字典中的.loginStoryboard
传入。
最后,如果您应用使用的是除Main.storyboard
以外的Storyboard,您可以将其作为.homeStoryboard
传入。
InitialViewController
!
// AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
Cely.setup(with: window!, forModel: User.ref, requiredProperties: [.token], withOptions: [
.loginStoryboard: UIStoryboard(name: "MyCustomLogin", bundle: nil),
.homeStoryboard: UIStoryboard(name: "NonMain", bundle: nil)
])
return true
}
推荐用户模式
import Cely
struct User: CelyUser {
enum Property: CelyProperty {
case username = "username"
case email = "email"
case token = "token"
func securely() -> Bool {
switch self {
case .token:
return true
default:
return false
}
}
func persisted() -> Bool {
switch self {
case .username:
return true
default:
return false
}
}
func save(_ value: Any) {
Cely.save(value, forKey: rawValue, securely: securely(), persisted: persisted())
}
func get() -> Any? {
return Cely.get(key: rawValue)
}
}
}
// MARK: - Save/Get User Properties
extension User {
static func save(_ value: Any, as property: Property) {
property.save(value: value)
}
static func save(_ data: [Property : Any]) {
data.forEach { property, value in
property.save(value)
}
}
static func get(_ property: Property) -> Any? {
return property.get()
}
}
采用这种模式的原因是使数据的保存尽可能
// Pseudo network code, NOT REAL CODE!!!
ApiManager.logUserIn("username", "password") { json in
let apiToken = json["token"].string
// REAL CODE!!!
User.save(apiToken, as: .token)
}
和获取数据尽可能简单
let token = User.get(.token)
API
Cely
Cely是为了帮助轻松处理用户凭据和登录而设计的。以下将提供Cely框架的文档。如果有什么不清楚或不完整的地方,请毫不犹豫地提出问题。
变量
store
一个遵循CelyStorageProtocol
协议的类。默认情况下设置为CelyStorage
的单例实例。
方法
setup(with:forModel:requiredProperties:withOptions:)
在您的应用程序中设置Cely
示例
Cely.setup(with: window, forModel: User(), requiredProperties:[.token])
// or
Cely.setup(with: window, forModel: User(), requiredProperties:[.token], withOptions:[
.loginStoryboard: UIStoryboard(name: "MyCustomLogin", bundle: nil),
.HomeStoryboard: UIStoryboard(name: "My_NonMain_Storyboard", bundle: nil),
.loginCompletionBlock: { (username: String, password: String) in
if username == "asdf" && password == "asdf" {
print("username: \(username): password: \(password)")
}
}
])
参数
键 | 类型 | 必需? | 描述 |
---|---|---|---|
window |
UIWindow |
您的应用程序的window。 | |
forModel |
CelyUser |
Cely存储数据的模型。 | |
requiredProperties |
[CelyProperty] |
否 | Cely针对这些属性进行测试,以确定用户是否已登录。 默认值:空数组。 |
options |
[CelyOption] |
否 | 传入一组CelyOptions 以对cely进行额外自定义的数组。 |
currentLoginStatus(requiredProperties:fromStorage:)
将返回当前用户的CelyStatus
。
示例
let status = Cely.currentLoginStatus()
参数
键 | 类型 | 必需? | 描述 |
---|---|---|---|
属性 |
[CelyProperty ] |
否 | 需要存储中存在的必需属性数组。 |
store |
CelyStorage |
否 | Cely将使用的存储。默认为CelyStorage 。 |
返回
类型 | 描述 |
---|---|
CelyStatus |
如果requiredProperties 都存储在其中,则返回.loggedIn ,否则返回.loggedOut 。 |
get(_:fromStorage:)
返回键的存储数据。
示例
let username = Cely.get(key: "username")
参数
键 | 类型 | 必需? | 描述 |
---|---|---|---|
key |
String | 您要检索值的键。 | |
store |
CelyStorage | 否 | Cely将使用的存储。默认为CelyStorage 。 |
返回
类型 | 描述 |
---|---|
Any? |
如果值nil(未找到),则返回Any? 对象。 |
save(_:forKey:toStorage:securely:persisted:)
將數據保存到存储中
示例
Cely.save("[email protected]", forKey: "email")
Cely.save("testUsername", forKey: "username", persisted: true)
Cely.save("token123", forKey: "token", securely: true)
参数
键 | 类型 | 必需? | 描述 |
---|---|---|---|
value |
Any? |
您想保存到存储中的值。 | |
key |
String |
您想保存的值的鍵。 | |
store |
CelyStorage |
否 | 存储Cely 将使用的。默认为CelyStorage 。 |
secure |
布尔值 |
否 | 如果您想安全地存储值。 |
persisted |
布尔值 |
否 | 在注销后保持数据。 |
返回
类型 | 描述 |
---|---|
StorageResult |
您的值是否成功设置。 |
changeStatus(to:)
使用 执行如 已登录
或 已注销
等操作。
示例
changeStatus(to: .loggedOut)
参数
键 | 类型 | 必需? | 描述 |
---|---|---|---|
状态 |
CelyStatus |
枚举值 |
logout(usesStorage:)
使用 方便的登出用户的方法。等价于 changeStatus(to: .loggedOut)
示例
Cely.logout()
参数
键 | 类型 | 必需? | 描述 |
---|---|---|---|
store |
CelyStorage |
否 | 存储Cely 将使用的。默认为CelyStorage 。 |
isLoggedIn()
返回用户是否登录
示例
Cely.isLoggedIn()
返回
类型 | 描述 |
---|---|
布尔值 |
返回用户是否登录 |
常量
协议
CelyUser
模型类实现的 protocol
示例
import Cely
struct User: CelyUser {
enum Property: CelyProperty {
case token = "token"
}
}
必需
value | 类型 | 描述 |
---|---|---|
属性 |
相关类型 |
包含您希望保存为模型的全部属性的枚举 |
CelyStorageProtocol
协议
一个存储类必须遵守,以便Cely可以使用它
必需
func set(_ value: Any?, forKey key: String, securely secure: Bool, persisted: Bool) -> StorageResult
func get(_ key: String) -> Any?
func removeAllData()
CelyStyle
一个对象必须遵守的协议
,以便自定义Cely的默认登录界面。由于所有方法都是可选的,Cely将为任何未实现的方法使用默认值。
方法
func backgroundColor() -> UIColor
func textFieldBackgroundColor() -> UIColor
func buttonBackgroundColor() -> UIColor
func buttonTextColor() -> UIColor
func appLogo() -> UIImage?
CelyAnimator
一个对象必须遵守的协议
,以便自定义主界面和登录界面之间的转换。
方法
func loginTransition(to destinationVC: UIViewController?, with celyWindow: UIWindow)
func logoutTransition(to destinationVC: UIViewController?, with celyWindow: UIWindow)
Typealias
CelyProperty
String
类型别名。用于用户模型
CelyCommands
String
类型别名。Cely执行命令
枚举
CelyOptions
enum
你可以在 Cely 中的 setup(with:forModel:requiredProperties:withOptions:)
方法中传递的选项
选项
Case | 描述 |
---|---|
storage |
如果您希望不使用 Cely 的默认存储,请传入您自己的存储类。类必须符合 CelyStorage 协议。 |
homeStoryboard |
如果您应用的主故事板不是“Main”,请传入您应用的默认故事板。 |
loginStoryboard |
传入您自己的登录故事板。 |
loginStyle |
传入符合 CelyStyle 的对象来定制默认登录屏幕。 |
loginCompletionBlock |
(String,String) -> Void 当您在 Cely 的默认登录控制器中的登录按钮被按下时将运行的代码块 |
celyAnimator |
传入符合 CelyAnimator 的对象来定制默认登录屏幕。 |
CelyStatus
enum
Cely 执行动作的状态
状态
Case | 描述 |
---|---|
loggedIn |
表示用户现在已登录。 |
loggedOut |
表示用户现在已登出。 |
StorageResult
enum
表示 Cely 是否成功保存您的数据的结果。
结果
Case | 描述 |
---|---|
success |
成功保存您的数据 |
fail(error) |
未能保存数据,并伴随一个 LocksmithError 。 |
安装
CocoaPods
CocoaPods 是 Cocoa 项目的依赖管理器。您可以使用以下命令安装它:
$ gem install cocoapods
构建 Cely 2.0.0+ 需要 CocoaPods 1.1.0+。
要使用 CocoaPods 将 Cely 整合到您的 Xcode 项目中,请在您的 Podfile
中指定它。
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!
pod 'Cely', '~> 2.1'
然后,运行以下命令:
$ pod install
Carthage
Carthage 是一个去中心化的依赖管理器,可以自动化将框架添加到您的 Cocoa 应用程序的过程。
您可以使用以下命令通过 Homebrew 安装 Carthage:
$ brew update
$ brew install carthage
要使用 Carthage 将 Cely 整合到您的 Xcode 项目中,请在您的 Cartfile
中指定它。
github "initFabian/Cely" ~> 2.1
手动
如果您不希望使用上述任何依赖管理器,您也可以手动将 Cely 整合到项目中。
Git Submodules
- 打开终端,使用
cd
进入您的顶级项目目录,然后运行以下命令(如果您的项目尚未初始化为 Git 仓库):
$ git init
- 通过运行以下命令将 Cely 添加为 git submodule:
$ git submodule add https://github.com/initFabian/Cely.git
$ git submodule update --init --recursive
-
打开新的
Cely
文件夹,并将Cely.xcodeproj
拖放到您应用程序 Xcode 项目的 Project Navigator 中。它应该位于您应用程序蓝色项目图标之下。它是否位于所有其他 Xcode 组之上或之下并不重要。
-
在 Project Navigator 中选择
Cely.xcodeproj
,并验证部署目标与您的应用程序目标相匹配。 -
接下来,在 Project Navigator 中选择您的应用程序项目(蓝色项目图标),进入目标配置窗口,并在侧边栏的“Targets”标题下选择应用程序目标。
-
在此窗口顶部标签栏中,打开“General”面板。
-
在“Embedded Binaries”部分下单击
+
按钮。 -
您将看到两个不同的
Cely.xcodeproj
文件夹,每个文件夹中都包含 Products 文件夹下的两个不同版本的Cely.framework
。您可以选择哪一个
Products
文件夹并不重要。 -
选择
Cely.framework
。 -
就这些了!
Cely.framework
将自动作为目标依赖项添加,链接框架以及在复制文件构建阶段嵌入,这正是您在模拟器和设备上构建所需的一切。
嵌入二进制码
- 从https://github.com/initFabian/Cely/releases下载最新版本。
- 接下来,在 Project Navigator 中选择您的应用程序项目(蓝色项目图标),进入目标配置窗口,并在侧边栏的“Targets”标题下选择应用程序目标。
- 在此窗口顶部标签栏中,打开“General”面板。
- 在“Embedded Binaries”部分下单击
+
按钮。 - 添加下载的
Cely.framework
。 - 就这些了!
许可协议
Cely遵循MIT许可协议。有关更多信息,请参阅LICENSE文件。