EventflitSwift eventflit-websocket-swift(以及 Objective-C)
支持 iOS、macOS (OS X) 和 tvOS!(希望很快支持 watchOS!)
我不想自己编写任何代码,直接开始用
您还想做什么?查看我们的示例应用
- 对于 Swift 编写的 iOS,请查看 ViewController.swift
- 对于 Objective-C 编写的 iOS,请查看 ViewController.m
- 对于 Swift 编写的 macOS,请查看 AppDelegate.swift
目录
安装
CocoaPods
CocoaPods 是 Cocoa 项目的依赖管理器,同时也是我们推荐安装 EventflitSwift 及其依赖的方法。
如果您还没有安装 CocoaPods gem,请运行以下命令
$ gem install cocoapods
要使用 CocoaPods 将 EventflitSwift 集成到您的 Xcode 项目中,请在其 Podfile
中指定
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '10.0'
use_frameworks!
pod 'EventflitSwift', '~> 0.1'
然后,运行以下命令
$ pod install
如果您在运行 pod install
时发现安装的不是最新版本,请尝试运行
$ pod cache clean
$ pod repo update EventflitSwift
$ pod install
同时,您还需要确保您的 Podfile.lock
文件中未锁定 EventflitSwift 到旧的版本。
Carthage
Carthage 是一个去中心化的依赖管理器,它自动化了将框架添加到您的 Cocoa 应用程序的过程。
您可以使用以下命令使用 Homebrew 安装 Carthage
$ brew update
$ brew install carthage
要使用 Carthage 将 EventflitSwift 集成到您的 Xcode 项目中,请在其 Cartfile
中指定
github "eventflit/eventflit-websocket-swift"
配置
有多个配置参数可以用于 Eventflit 客户端。对于 Swift 使用它们是
authMethod (AuthMethod)
- 客户端用于对需要身份验证的通道的订阅请求进行身份验证的方法(下面提供更多详情)attemptToReturnJSONObject (Bool)
- 是否想让库尝试将您的数据解析为 JSON(或者不解析,直接返回字符串)encrypted (Bool)
- 是否使用加密传输,默认为true
autoReconnect (Bool)
- 设置是否让库在断开连接时尝试自动重连host (EventflitHost)
- 为要连接的服务器设置自定义值,例如:EventflitHost.host("ws-test.eventflit.com")
port (Int)
- 为要连接的端口号设置自定义值activityTimeout (TimeInterval)
- 在指定时间(秒)内没有从服务器接收到任何消息后,将发送ping消息以检查连接是否仍然有效;默认值由服务器提供,低值会导致不必要的流量。
authMethod
参数必须是AuthMethod
类型。这是一个定义如下枚举:
public enum AuthMethod {
case endpoint(authEndpoint: String)
case authRequestBuilder(authRequestBuilder: AuthRequestBuilderProtocol)
case inline(secret: String)
case authorizer(authorizer: Authorizer)
case noMethod
}
endpoint(authEndpoint: String)
- 客户端将向您指定的端点发送POST
请求,其中包含客户端的socket ID和尝试订阅的频道名称authRequestBuilder(authRequestBuilder: AuthRequestBuilderProtocol)
- 您指定一个符合AuthRequestBuilderProtocol
(如下文定义)的对象,该对象必须生成用于进行认证请求的URLRequest
对象inline(secret: String)
- 您应用程序的密钥,以便认证请求不必发送到您的认证端点,而是可以在库内部直接进行订阅认证(这主要是为了开发使用)authorizer(authorizer: Authorizer)
- 您指定一个符合Authorizer
协议的对象,该对象必须能够提供适当的认证信息noMethod
- 如果您只使用公共频道,则不需要设置authMethod
(这是默认值)
以下是AuthRequestBuilderProtocol
的定义
public protocol AuthRequestBuilderProtocol {
func requestFor(socketID: String, channelName: String) -> URLRequest?
}
以下是Authorizer
协议的定义
public protocol Authorizer {
func fetchAuthValue(socketID: String, channelName: String, completionHandler: (EventflitAuth?) -> ())
}
其中EventflitAuth
定义为:
public class EventflitAuth: NSObject {
public let auth: String
public let channelData: String?
public init(auth: String, channelData: String? = nil) {
self.auth = auth
self.channelData = channelData
}
}
假设认证过程成功,您需要调用提供的completionHandler
函数,传入一个EventflitAuth
对象,以使订阅过程完成。
如果在任何原因下认证过程失败,则只需调用completionHandler
函数,并将nil
作为唯一参数。
请注意,如果您要指定要连接的集群,则使用以下方法的host
属性
Swift
let options = EventflitClientOptions(
host: .cluster("eu")
)
Objective-C
OCAuthMethod *authMethod = [[OCAuthMethod alloc] initWithAuthEndpoint:@"https://your.authendpoint/eventflit/auth"];
OCEventflitHost *host = [[OCEventflitHost alloc] initWithCluster:@"eu"];
EventflitClientOptions *options = [[EventflitClientOptions alloc]
initWithOcAuthMethod:authMethod
attemptToReturnJSONObject:YES
autoReconnect:YES
ocHost:host
port:nil
encrypted:YES];
所有这些配置选项都需要传递给一个EventflitClientOptions
对象,然后将其传递给Eventflit对象,在实例化时,例如
Swift
let options = EventflitClientOptions(
authMethod: .endpoint(authEndpoint: "https://:9292/eventflit/auth")
)
let eventflit = Eventflit(key: "APP_KEY", options: options)
Objective-C
OCAuthMethod *authMethod = [[OCAuthMethod alloc] initWithAuthEndpoint:@"https://your.authendpoint/eventflit/auth"];
OCEventflitHost *host = [[OCEventflitHost alloc] initWithCluster:@"eu"];
EventflitClientOptions *options = [[EventflitClientOptions alloc]
initWithOcAuthMethod:authMethod
attemptToReturnJSONObject:YES
autoReconnect:YES
ocHost:host
port:nil
encrypted:YES];
eventflit = [[Eventflit alloc] initWithAppKey:@"YOUR_APP_KEY" options:options];
如您可能已注意到,对于 Objective-C 的使用,这种差异略有不同。主要变化是您需要使用 OCAuthMethod
和 OCEventflitHost
代替 AuthMethod
和 EventflitHost
。在您的 Objective-C 代码中可以调用以下 OCAuthMethod
类的功能。
public init(authEndpoint: String)
public init(authRequestBuilder: AuthRequestBuilderProtocol)
public init(secret: String)
public init()
OCAuthMethod *authMethod = [[OCAuthMethod alloc] initWithSecret:@"YOUR_APP_SECRET"];
EventflitClientOptions *options = [[EventflitClientOptions alloc] initWithAuthMethod:authMethod];
OCEventflitHost
的情况类似。您可以获得以下函数实用
public init(host: String)
public init(cluster: String)
[[OCEventflitHost alloc] initWithCluster:@"YOUR_CLUSTER_SHORTCODE"];
认证信道示例
Swift
class AuthRequestBuilder: AuthRequestBuilderProtocol {
func requestFor(socketID: String, channelName: String) -> URLRequest? {
var request = URLRequest(url: URL(string: "https://:9292/builder")!)
request.httpMethod = "POST"
request.httpBody = "socket_id=\(socketID)&channel_name=\(channel.name)".data(using: String.Encoding.utf8)
request.addValue("myToken", forHTTPHeaderField: "Authorization")
return request
}
}
let options = EventflitClientOptions(
authMethod: AuthMethod.authRequestBuilder(authRequestBuilder: AuthRequestBuilder())
)
let eventflit = Eventflit(
key: "APP_KEY",
options: options
)
Objective-C
@interface AuthRequestBuilder : NSObject <AuthRequestBuilderProtocol>
- (NSURLRequest *)requestForSocketID:(NSString *)socketID channelName:(NSString *)channelName;
@end
@implementation AuthRequestBuilder
- (NSURLRequest *)requestForSocketID:(NSString *)socketID channelName:(NSString *)channelName {
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[[NSURL alloc] initWithString:@"https://:9292/eventflit/auth"]];
NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL: [[NSURL alloc] initWithString:@"https://:9292/eventflit/auth"]];
NSString *dataStr = [NSString stringWithFormat: @"socket_id=%@&channel_name=%@", socketID, channelName];
NSData *data = [dataStr dataUsingEncoding:NSUTF8StringEncoding];
mutableRequest.HTTPBody = data;
mutableRequest.HTTPMethod = @"POST";
[mutableRequest addValue:@"myToken" forHTTPHeaderField:@"Authorization"];
request = [mutableRequest copy];
return request;
}
@end
OCAuthMethod *authMethod = [[OCAuthMethod alloc] initWithAuthRequestBuilder:[[AuthRequestBuilder alloc] init]];
EventflitClientOptions *options = [[EventflitClientOptions alloc] initWithAuthMethod:authMethod];
其中 "Authorization"
和 "myToken"
是服务器期望在请求头的字段和值。
连接
通过在构造函数中提供您的 API 密钥来建立 Websocket 连接
Swift
let eventflit = Eventflit(key: "APP_KEY")
eventflit.connect()
Objective-C
Eventflit *eventflit = [[Eventflit alloc] initWithAppKey:@"YOUR_APP_KEY"];
[eventflit connect];
这返回一个客户端对象,然后可以使用它来订阅频道,然后调用 connect()
触发连接过程开始。
您还可以在连接对象上设置一个 userDataFetcher
。
userDataFetcher (() -> EventflitPresenceChannelMember)
- 如果您正在订阅一个认证频道并希望提供一个函数来返回用户数据
设置方式如下
Swift
let eventflit = Eventflit(key: "APP_KEY")
eventflit.connection.userDataFetcher = { () -> EventflitPresenceChannelMember in
return EventflitPresenceChannelMember(userId: "123", userInfo: ["twitter": "hamchapman"])
}
Objective-C
Eventflit *eventflit = [[Eventflit alloc] initWithAppKey:@"YOUR_APP_KEY"];
eventflit.connection.userDataFetcher = ^EventflitPresenceChannelMember* () {
NSString *uuid = [[NSUUID UUID] UUIDString];
return [[EventflitPresenceChannelMember alloc] initWithUserId:uuid userInfo:nil];
};
Connection delegate
存在一个EventflitDelegate
,您可以用来通知连接相关的信息。当符合EventflitDelegate
协议时,您可以选择实现以下功能
@objc optional func changedConnectionState(from old: ConnectionState, to new: ConnectionState)
@objc optional func subscribedToChannel(name: String)
@objc optional func failedToSubscribeToChannel(name: String, response: URLResponse?, data: String?, error: NSError?)
@objc optional func debugLog(message: String)
函数的名称在很大程度上说明了它们的作用,但仅为完整性起见
changedConnectionState
- 如果您想使用连接状态变化来执行不同的操作/UI更新,请使用此功能subscribedToChannel
- 如果您想知道通道成功订阅的情况,这非常有用,如果您想要执行只在订阅成功后才相关的操作,例如注销存在通道的成员failedToSubscribeToChannel
- 如果您想知道订阅尝试失败的情况,可以使用该结果再次尝试订阅或调用用于跟踪错误的您使用的服务debugLog
- 如果您想记录Eventflit相关的事件,例如底层的WebSocket收到一条消息,请使用此功能
设置代理的示例如下
Swift
class ViewController: UIViewController, EventflitDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let eventflit = Eventflit(key: "APP_KEY")
eventflit.connection.delegate = self
// ...
}
}
Objective-C
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.client = [[Eventflit alloc] initWithAppKey:@"YOUR_APP_KEY"];
self.client.connection.delegate = self;
// ...
}
下面是设置具有每个可选协议函数的类的示例
Swift
class DummyDelegate: EventflitDelegate {
func changedConnectionState(from old: ConnectionState, to new: ConnectionState) {
// ...
}
func debugLog(message: String) {
// ...
}
func subscribedToChannel(name: String) {
// ...
}
func failedToSubscribeToChannel(name: String, response: URLResponse?, data: String?, error: NSError?) {
// ...
}
}
Objective-C
@interface DummyDelegate : NSObject <EventflitDelegate>
- (void)changedConnectionState:(enum ConnectionState)old to:(enum ConnectionState)new_
- (void)debugLogWithMessage:(NSString *)message
- (void)subscribedToChannelWithName:(NSString *)name
- (void)failedToSubscribeToChannelWithName:(NSString *)name response:(NSURLResponse *)response data:(NSString *)data error:(NSError *)error
@end
@implementation DummyDelegate
- (void)changedConnectionState:(enum ConnectionState)old to:(enum ConnectionState)new_ {
// ...
}
- (void)debugLogWithMessage:(NSString *)message {
// ...
}
- (void)subscribedToChannelWithName:(NSString *)name {
// ...
}
- (void)failedToSubscribeToChannelWithName:(NSString *)name response:(NSURLResponse *)response data:(NSString *)data error:(NSError *)error {
// ...
}
@end
连接可以处于不同的状态(括号内为 Objective-C 整数枚举案例)
连接中(0)
- 连接即将尝试建立已连接(1)
- 连接已成功建立即将断开连接(2)
- 连接已被指令断开,即将执行断开操作已断开连接(3)
- 连接已断开,不会尝试自动重新连接重新连接(4)
- 将尝试重新建立连接
有一个 stringValue()
函数可以在 ConnectionState
对象上调用,以获取状态的字符串表示,例如 "连接中"
。
重新连接
断开连接主要有三种情况
- 客户端显式调用断开连接,并通过 WebSocket 连接发送关闭帧
- 客户端经历某种形式的网络退化,导致心跳(ping/pong)消息丢失,从而客户端断开连接
- Eventflit 服务器关闭 WebSocket 连接;通常这只会发生在 Eventflit 服务器重启时,并且应该立即进行重新连接
在第一类断开情况下,库(正如你所期待的那样)不会尝试重新连接。
库使用 Reachability 尝试检测导致断开连接的网络退化事件。如果检测到这种情况,库将尝试以指数退避(默认情况下)无限期地重新连接(重新连接尝试的最长时间默认为 120 秒)。reconnectAttemptsMax
的值是 EventflitConnection
的公共属性,因此如果需要可以更改重新连接尝试的最大次数。
如果 Eventflit 服务器关闭 WebSocket,或者由于 Reachability 没有涵盖的网络事件导致的断开连接,库仍然会尝试按上述方式重新连接。
如果将客户端选项 autoReconnect
设置为 true
(默认情况下为 true),则所有这些都将成立。如果重新连接策略不适合您的用例,则可以将 autoReconnect
设置为 false
并根据连接状态更改实现自己的重新连接策略。
连接(EventflitConnection
)上有几个属性可以设置,这些属性会影响到重连行为的运作方式。这些属性包括:
public var reconnectAttemptsMax: Int? = 6
- 如果将此设置为nil
,则没有最大重连尝试次数限制,并且重连尝试将继续进行,采用指数退避(根据尝试次数),否则只会尝试与该属性值相同的次数,然后连接状态将移动到.disconnected
状态。public var maxReconnectGapInSeconds: Double? = nil
- 如果您想设置重连尝试之间最大时间间隔(以秒为单位),则适当设置此属性。
请注意,一旦建立成功的连接,重连尝试次数将重置为0。
订阅
公开频道
订阅频道的默认方法是通过调用您的客户端对象的 subscribe
方法。
Swift语言
let myChannel = eventflit.subscribe("my-channel")
Objective-C语言
EventflitChannel *myChannel = [eventflit subscribeWithChannelName:@"my-channel"];
这返回了一个EventflitChannel对象,可以将其绑定到事件上。
私有频道
私有频道与公开频道创建方式完全一样,只是在 'private-' 命名空间中。这意味着需要在频道名称前加前缀。
Swift
let myPrivateChannel = eventflit.subscribe("private-my-channel")
Objective-C
EventflitChannel *myPrivateChannel = [eventflit subscribeWithChannelName:@"private-my-channel"];
订阅私有频道需要客户端验证。有关详细信息,请参阅配置部分中的已验证频道示例。
Presence channels
Presence channels是名称以presence-
为前缀的频道。
推荐使用subscribeToPresenceChannel
函数订阅presence channel,而不是标准subscribe
函数。使用subscribeToPresenceChannel
函数意味着你会得到一个EventflitPresenceChannel
对象,而不是标准EventflitChannel
。此EventflitPresenceChannel
对象有一些额外的、针对presence channel的特定函数,例如members
、me
和findMember
。
Swift
let myPresenceChannel = eventflit.subscribeToPresenceChannel(channelName: "presence-my-channel")
Objective-C
EventflitPresenceChannel *myPresenceChannel = [eventflit subscribeToPresenceChannelWithChannelName:@"presence-my-channel"];
如前所述,您仍然可以使用subscribe
方法订阅presence channel,但返回的channel对象将无法访问针对presence channel的特定函数,除非您选择将该channel对象转换为EventflitPresenceChannel
。
Swift
let myPresenceChannel = eventflit.subscribe("presence-my-channel")
Objective-C
EventflitChannel *myPresenceChannel = [eventflit subscribeWithChannelName:@"presence-my-channel"];
您还可以提供当成员被添加到或从通道中删除时将被调用的函数。这些函数作为 subscribe
和 subscribeToPresenceChannel
的参数可用。
Swift
let onMemberChange = { (member: EventflitPresenceChannelMember) in
print(member)
}
let chan = eventflit.subscribeToPresenceChannel("presence-channel", onMemberAdded: onMemberChange, onMemberRemoved: onMemberChange)
Objective-C
void (^onMemberChange)(EventflitPresenceChannelMember*) = ^void (EventflitPresenceChannelMember *member) {
NSLog(@"%@", member);
};
EventflitChannel *myPresenceChannel = [eventflit subscribeWithChannelName:@"presence-my-channel" onMemberAdded:onMemberChange onMemberRemoved:onMemberChange];
注意:只有当成功订阅通道后,EventflitPresenceChannel
对象的 members
和 myId
属性(以及获取这些属性值的函数)才会被设置。
要找出何时成功订阅了通道,最简单的方法是将关注点的通道绑定到名为 eventflit:subscription_succeeded
的事件。其外观可能如下所示
Swift
let eventflit = Eventflit(key: "YOUR_APP_KEY")
let chan = eventflit.subscribeToPresenceChannel("presence-channel")
chan.bind(eventName: "eventflit:subscription_succeeded", callback: { data in
print("Subscribed!")
print("I can now access myId: \(chan.myId)")
print("And here are the channel members: \(chan.members)")
})
Objective-C
Eventflit *eventflit = [[Eventflit alloc] initWithAppKey:@"YOUR_APP_KEY"];
EventflitPresenceChannel *chan = [eventflit subscribeToPresenceChannelWithChannelName:@"presence-channel"];
[chan bindWithEventName:@"eventflit:subscription_succeeded" callback: ^void (NSDictionary *data) {
NSLog(@"Subscribed!");
NSLog(@"I can now access myId: %@", chan.myId);
NSLog(@"And here are my channel members: %@", chan.members);
}];
还可以通过使用包含在 EventflitDelegate
协议中的 subscriptionDidSucceed
代理方法来通知成功的订阅。
以下是一个使用代理的示例
Swift
class DummyDelegate: EventflitDelegate {
func subscribedToChannel(name: String) {
if channelName == "presence-channel" {
if let presChan = eventflit.connection.channels.findPresence(channelName) {
// in here you can now have access to the channel's members and myId properties
print(presChan.members)
print(presChan.myId)
}
}
}
}
let eventflit = Eventflit(key: "YOUR_APP_KEY")
eventflit.connection.delegate = DummyDelegate()
let chan = eventflit.subscribeToPresenceChannel("presence-channel")