测试已测试 | ✓ |
Lang语言 | SwiftSwift |
许可证 | MIT |
发布最后发布 | 2016年5月 |
SPM支持 SPM | ✗ |
由 Dr. Swifty 维护。
依赖 | |
Alamofire | ~> 3.0 |
SwiftyJSON | ~> 2.3 |
OAuthSwift | ~> 0.5.0 |
Swifter | ~> 1.1.3 |
Locksmith | ~> 2.0.8 |
请注意:此库仍在开发中。可能存在错误或缺失的功能,未来版本的功能可能也会发生变化。在使用之前请注意这一点。
要使用 LctvSwift,您需要在 Livecoding 上注册一个应用。访问 Livecoding 主页以获取有关如何操作的信息。
在注册时,为您的应用选择以下配置
客户端类型:
公共
授权类型:
授权码
重定向 URI:
https://:8080/oauth-callback
在您的 Info.plist 文件中添加以下设置
AppTransportSecuritySettings
这是一个字典类型的条目。向其中添加以下子条目
允许随意加载 = 是
这会禁用强制的 https-only 连接性。在授权过程中,库会启动一个内部 http 服务器,这就是需要这个设置的原因。如果本地服务器支持 https,则可能在未来版本中不再需要。
要运行示例项目,克隆仓库,然后首先从 Example 目录中运行 pod install
。然后编辑 Secret.swift 文件,并插入您的 Livecoding API clientId 和 secret。
请确保您不要将 clientId 和 secret 存储在真实世界的应用程序中,因为在示例应用程序中这样做!
建议在您的应用的AppDelegate
类中初始化LctvSwift。因此,在该类中声明一个新的变量
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var api: LctvApi?
var initialViewController: UIViewController!
您可以使用类似下面的函数来初始化API
func initApi() {
do {
var config = LctvConfig(clientId: clientId, clientSecret: clientSecret)
try api = LctvApi(config: config)
} catch {
print("Could not initialize. Aborting.")
abort()
}
}
init(config: LctvConfig)
函数是获取LctvApi
实例的方法,这是与Livecoding通信的必要条件。该函数接受一个LctvConfig
实例作为参数,其中包含一些关于您如何设置API的基本信息。
在实际应用中,您应该做一些更合适的错误处理,如示例所示。
当API首次初始化时,您目前必须在LctvConfig
实例中指定您的clientId和secret。您有责任以安全的方式执行此操作,以防止滥用此信息。在第一次初始化后,LctvSwift将安全地将其存储到设备的密钥链中,因此不再需要提供。
LctvConfig
类有更多属性
覆盖
:
如果设置为true
,则此初始化将覆盖设备密钥链中存在的任何客户端信息。在这种情况下,您必须再次在配置中提供clientId和secret。默认为false
,并且仅在调试目的时应设置为true
。
授予类型
:
凭据类型可以是AuthorizationCode
或Implicit
。Livecoding建议对于移动设备使用Implicit
,但由于某些依赖,目前LctvSwift仅支持AuthorizationCode
。未来版本中LctvSwift可能会支持Implicit
凭据类型。
密钥链ID
:
该ID将用于从设备的密钥链中存储和加载数据。您应该指定自己的唯一字符串以确保,其他可能也使用LctvSwift的应用不会发生冲突。
内部端口
:
用于授权期间临时http服务器的内部端口。如果有端口冲突,您可以在此处更改端口。
从application:didFinishLaunchingWithOptions:
方法调用initApi
函数
func application(application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
initApi()
}
根据您的需求,在AppDelegate
中可能内置一个开关以决定如果用户尚未授权您的应用,是否显示LoginViewController,或者直接显示您的主要应用视图控制器。
LoginViewController与其他登录屏幕不同,因为它不提供用户名和密码字段。相反,它应仅提供按钮,例如“登录到Livecoding”,然后启动LctvSwift授权过程。
然后,此过程将在Livecoding.TV提供的登录和授权表单中展示一个WebViewController。
要实现此开关,您可以在AppDelegate
的application:didFinishLaunchingWithOptions:
方法中直接在initApi
调用下方执行
// Setup the application window
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
self.initialViewController = storyboard.instantiateInitialViewController()
if !self.api!.hasAccessToken() {
let loginViewController = storyboard.instantiateViewControllerWithIdentifier("LoginViewController")
self.window?.rootViewController = loginViewController
} else {
self.window?.rootViewController = self.initialViewController
}
self.window?.makeKeyAndVisible()
您必须将LoginViewController添加到Storyboard中,并将StoryboardID分配为LoginViewController
。
您可以使用API的hasAccessToken
方法检查是否已经有了访问令牌。
现在,当启动应用时,如果用户尚未授权,它将自动显示“登录”屏幕。否则,它将直接切换到应用的主要视图控制器(这是在Storyboard中定义的初始视图控制器)。
在上一个章节中,您通过在AppDelegate
中创建LctvApi
实例来实例化LctvSwift。为了使此实例对所有的视图控制器可用,创建一个小的UIViewController
扩展是有意义的
import UIKit
import LctvSwift
extension UIViewController {
var lctvApi: LctvApi? {
return (UIApplication.sharedApplication().delegate as! AppDelegate).api
}
}
在第一次初始化API之后,您的应用程序需要从服务器获取一个访问令牌,以便能够访问Livecoding资源。此令牌将与您的机密信息一起存储在设备的密钥链中。
当使用AuthorizationCode
授权类型时,通常此授权过程只需要处理一次。在初始授权之后,当旧令牌过期时,可以通过提供的刷新令牌获取新的访问令牌。授权类型Implicit
不支持刷新令牌,因此可能需要在某个时候重新授权。然而,使用Implicit
您不需要在设备上存储客户端密钥,因此可能更安全。
在您的LoginViewController
中,提供以下函数以处理LctvSwift的授权:
func authorizeClient() {
let viewController = LctvAuthViewController()
viewController.view.frame = self.view.bounds
api.oAuthUrlHandler = viewController
do {
try api.authorize(scope: [.Read, .Chat])
} catch {
print("Could not authorize: \(error)")
}
}
如您所见,在此函数中初始化了一个新的ViewController。这是由LctvSwift提供的,它包含一个UIWebView,为用户提供登录Livecoding并授予应用程序所需权限的机会。
此viewController通过oAuthUrlHandler
属性传递给api。
使用authorize
函数,您可以指定一个定义应用程序需要的权限的scope
,它是一组LctvScope
值的数组。默认为.Read,这是一种有限的读取权限。所有可用权限均在LctvScope
枚举中定义
public enum LctvScope : String {
case Read = "read"
case ReadViewer = "read:viewer"
case ReadUser = "read:user"
case ReadChannel = "read:channel"
case Chat = "chat"
...
}
现在在storyboard中创建一个Login按钮在LoginViewController
中。为视图控制器类中此按钮添加一个动作方法,该方法调用authorizeClient
方法
@IBAction func loginButtonPressed(sender: UIButton) {
authorizeClient()
}
现在当您启动应用程序时,当您按下
LoginViewController
中的登录按钮时,应该出现一个浏览器窗口,并要求您登录到Livecoding。登录成功后,Livecoding将询问您是否希望向应用程序授予所列权限。点击“授权”后,浏览器窗口将消失。
如果一切顺利,您的LctvApi
实例已配置并授权调用Livecoding API函数。
现在将很乐意看到,当用户在成功授权应用程序后,LoginViewController
消失。不幸的是,在调用authorize
后不能直接这样做,因为它是异步处理。
为了处理此问题,LctvApi
提供了两个属性
/// Handler which is called after successfully processing the authorization screen
public var onAuthorizationSuccess: AuthSuccessHandler? = nil
/// Handler for errors during the authorization process
public var onAuthorizationFailure: AuthFailureHandler? = nil
您在此处可以指定两个函数,当授权成功或失败时将被调用,例如在viewDidLoad
override func viewDidLoad() {
self.lctvApi!.onAuthorizationSuccess = authorizationSuccessful
self.lctvApi!.onAuthorizationFailure = authorizationFailure
}
现在创建这两个函数
func authorizationSuccessful() {
// Present the initial view controller
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let viewController = appDelegate.initialViewController
self.presentViewController(viewController, animated: true, completion: nil)
}
func authorizationFailure(message: String) {
// Do some appropriate error handling here
print(message)
}
以下是一些使用LctvApi
实例访问Livecoding API的示例。每个API调用都具有以下结构
api.getCurrentUser(success: { user in
// Do something with the user
print(user.userName)
print(user.yearsProgramming)
}, failure: { message, json in
// Error handling
})
如您所见,每个函数都有一个用于success
和failure
的回调闭包。这是处理HTTP调用异步性质所必需的。
从示例getCurrentUser
函数中,您将在success
闭包内接收到一个LctvUser
实例。
有些API函数以“分页”结构的形式返回大量数据。LctvSwift使用LctvResultContainer
类处理这些结果
api.getCodingCategories(success: {
result in
self.codingCategories = result
print(result.results)
}, failure: { message, json in
self.showAlertWithTitle("ERROR", message: message)
})
传递给success
的result
参数是类型为LctvResultContainer<LctvCodingCategory>
。它的results
属性包含一个包含多个LctvCodingCategory
实例的数组。可以通过设置API的pageSize
属性配置每页的结果数量
api.pageSize = 20
结果容器中也有两个属性 next
和 previous
可用,其中包含了调用下一页或前一页的URL。LctvSwift 提供了方便的函数来实现这一功能。
api.nextPage(self.codingCategories!, success: { result in
self.codingCategories = result
}, failure: { message, json in
self.showAlertWithTitle("ERROR", message: "Could not retrieve next page: \(message)")
})
api.previousPage(self.codingCategories!, success: { result in
self.codingCategories = result
}, failure: { message, json in
self.showAlertWithTitle("ERROR", message: "Could not retrieve previous page: \(message)")
})
一些API函数仅返回包含结果的简单数组。这由 LctvSwift 的 LctvArrayContainer
类处理。
api.getCurrentUserFollowers(success: {
result in
print(result.array)
}, failure: { message, json in
self.showAlertWithTitle("ERROR", message: message)
})
在上面的例子中,传递给 success
闭包的 result
是类型 LctvArrayContainer<LctvUser>
。它有一个属性 array
,其中包含所有接收到的 LctvUser
实例。
LctvSwift 适用于 MIT 许可证。有关更多信息,请参阅 LICENSE 文件。