Cely 2.1.3

Cely 2.1.3

Fabian BuentelloAlex Du Bois 维护。



Cely 2.1.3

Swift 4.0 Carthage compatible CocoaPods compatible Cookiecutter-Swift Build Status codecov

发音 Cell-Lee

Cely 的目标是将登录系统添加到您的应用程序中,整个过程不超过 30 秒!

概述

Cely 的目标是将登录系统添加到您的应用程序中,整个过程不超过 30 秒!

背景

无论您是在为客户端构建应用还是为黑客马拉松构建应用,构建一个无论多基础的登录系统都可能非常繁琐且耗时。Cely 的架构在 countless 应用程序中经过了实战测试,Cely 保证以极短的时间为您提供功能完善的登录系统。由于 Cely 是建立在 Locksmith 上,Swift 最受欢迎的 Keychain 包装器,您可以信任 Cely 正确处理登录凭据。

细节

Cely 为您做了什么?

  1. 简单的 API,可以安全地存储用户凭据和信息
  • Cely.save("SUPER_SECRET_STRING", forKey: "token", securely: true)
  1. 使用以下操作管理应用程序主屏幕和登录屏幕之间的切换
  • Cely.changeStatus(to: .loggedIn) // 或 .loggedOut
  1. 可定制的初始登录屏幕(或者您可以使用自己的登录屏幕)

Cely 为您没有做什么?

  1. 网络请求
  2. 处理网络错误
  3. 任何与网络相关的事情

功能需求

  • 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获取usernamepassword?很简单,只需在.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传入。

⚠️⚠️⚠️⚠️确保在Storyboard中设置您的登录屏幕为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文件。