EventflitSwift 0.1.0

EventflitSwift 0.1.0

Erick Ponce 维护。



 
依赖性
CryptoSwift~> 0.9.0
ReachabilitySwift~> 4.1.0
TaskQueue~> 1.1.1
StarscreamFork~> 3.0.6
 

EventflitSwift eventflit-websocket-swift(以及 Objective-C)

Languages Platform Cocoapods Compatible Carthage Compatible Twitter GitHub license

支持 iOS、macOS (OS X) 和 tvOS!(希望很快支持 watchOS!)

我不想自己编写任何代码,直接开始用

您还想做什么?查看我们的示例应用

目录

安装

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 的使用,这种差异略有不同。主要变化是您需要使用 OCAuthMethodOCEventflitHost 代替 AuthMethodEventflitHost。在您的 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的特定函数,例如membersmefindMember

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"];

您还可以提供当成员被添加到或从通道中删除时将被调用的函数。这些函数作为 subscribesubscribeToPresenceChannel 的参数可用。

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 对象的 membersmyId 属性(以及获取这些属性值的函数)才会被设置。

要找出何时成功订阅了通道,最简单的方法是将关注点的通道绑定到名为 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")

使用自提供的认证值进行订阅

可以通过在调用subscribesubscribeToPresenceChannel时提供认证信息来订阅需要认证的通道。如下所示执行

Swift

let eventflitAuth = EventflitAuth(auth: yourAuthString, channelData: yourOptionalChannelDataString)
let chan = self.eventflit.subscribe(channelName, auth: eventflitAuth)

如果订阅的是私有通道,则可以使用一个仅包含认证(String)值的EventflitAuth对象进行初始化。如果您订阅的是存在通道,则可以使用一个包含auth (String)channelData (String)的值对。

这些authchannelData值是在调用我们的各种服务器库中调用eventflit.authenticate(...)时接收到的值。

请注意,要为订阅生成有效的认证值,必须在使用认证值时提供socketId(即连接到Eventflit服务器的Web套接字的唯一标识)。因此,使用此功能的可能流程涉及在尝试订阅任何需要认证的通道之前,检查连接状态是否变为connected

绑定到事件

事件可以绑定在两个级别;全局和按频道。绑定事件时,您可以选择保存返回值,它是对创建的事件处理程序的唯一标识符。保存这个的唯一原因是如果您将来想要取消绑定此事件。以下是一个示例。

全局事件

您可以为这些事件添加行为,而不管事件被播报到哪个频道。以下是一个示例,演示了一个应用程序如何绑定来自任何频道(您订阅的)的新评论。

Swift

let eventflit = Eventflit(key: "YOUR_APP_KEY")
eventflit.subscribe("my-channel")

eventflit.bind(callback: { (data: Any?) -> Void in
    if let data = data as? [String : AnyObject] {
        if let commenter = data["commenter"] as? String, message = data["message"] as? String {
            print("\(commenter) wrote \(message)")
        }
    }
})

Objective-C

Eventflit *eventflit = [[Eventflit alloc] initWithAppKey:@"YOUR_APP_KEY"];
EventflitChannel *chan = [eventflit subscribeWithChannelName:@"my-channel"];

[eventflit bind: ^void (NSDictionary *data) {
    NSString *commenter = data[@"commenter"];
    NSString *message = data[@"message"];

    NSLog(@"%@ wrote %@", commenter, message);
}];

按频道事件

这些事件绑定到特定频道,意味着您可以在客户端应用程序的不同部分重复使用事件名称。以下可能是一个示例,演示了一个股票追踪应用程序,为不同的公司打开了多个频道。

Swift

let eventflit = Eventflit(key: "YOUR_APP_KEY")
let myChannel = eventflit.subscribe("my-channel")

myChannel.bind(eventName: "new-price", callback: { (data: Any?) -> Void in
    if let data = data as? [String : AnyObject] {
        if let price = data["price"] as? String, company = data["company"] as? String {
            print("\(company) is now priced at \(price)")
        }
    }
})

Objective-C

Eventflit *eventflit = [[Eventflit alloc] initWithAppKey:@"YOUR_APP_KEY"];
EventflitChannel *chan = [eventflit subscribeWithChannelName:@"my-channel"];

[chan bindWithEventName:@"new-price" callback:^void (NSDictionary *data) {
    NSString *price = data[@"price"];
    NSString *company = data[@"company"];

    NSLog(@"%@ is now priced at %@", company, price);
}];

接收错误

错误会发送到相关的客户端,事件名称为eventflit:error。可以使用以下代码接收和处理它们。显然,如何处理它们的细节留给了开发者,但这里显示了通用模式。

Swift

eventflit.bind({ (message: Any?) in
    if let message = message as? [String: AnyObject], eventName = message["event"] as? String where eventName == "eventflit:error" {
        if let data = message["data"] as? [String: AnyObject], errorMessage = data["message"] as? String {
            print("Error message: \(errorMessage)")
        }
    }
})

Objective-C

[eventflit bind:^void (NSDictionary *data) {
    NSString *eventName = data[@"event"];

    if ([eventName isEqualToString:@"eventflit:error"]) {
        NSString *errorMessage = data[@"data"][@"message"];
        NSLog(@"Error message: %@", errorMessage);
    }
}];

可能收到的错误类型

# if attempting to subscribe to an already subscribed-to channel

"{\"event\":\"eventflit:error\",\"data\":{\"code\":null,\"message\":\"Existing subscription to channel presence-channel\"}}"

# if the auth signature generated by your auth mechanism is invalid

"{\"event\":\"eventflit:error\",\"data\":{\"code\":null,\"message\":\"Invalid signature: Expected HMAC SHA256 hex digest of 200557.5043858:presence-channel:{\\\"user_id\\\":\\\"200557.5043858\\\"}, but got 8372e1649cf5a45a2de3cd97fe11d85de80b214243e3a9e9f5cee502fa03f880\"}}"

可以看到它们的一般形式是

{
  "event": "eventflit:error",
  "data": {
    "code": null,
    "message": "Error message here"
  }
}

解除事件处理器绑定

可以使用unbind函数从对象中移除先前绑定的处理器。例如,

Swift

let eventflit = Eventflit(key: "YOUR_APP_KEY")
let myChannel = eventflit.subscribe("my-channel")

let eventHandlerId = myChannel.bind(eventName: "new-price", callback: { (data: Any?) -> Void in
  ...
})

myChannel.unbind(eventName: "new-price", callbackId: eventHandlerId)

Objective-C

Eventflit *eventflit = [[Eventflit alloc] initWithAppKey:@"YOUR_APP_KEY"];
EventflitChannel *chan = [eventflit subscribeWithChannelName:@"my-channel"];

NSString *callbackId = [chan bindWithEventName:@"new-price" callback:^void (NSDictionary *data) {
    ...
}];

[chan unbindWithEventName:@"new-price" callbackId:callbackId];

您可以在全局和按通道级别取消事件绑定。对于这两个对象,您还可以选择调用unbindAll,正如您所猜的那样,它将取消对象上的所有eventHandler绑定。

推送通知

Eventflit 同样支持推送通知。应用程序的实例可以注册推送通知并订阅“兴趣”。然后您的服务器可以发布到这些兴趣,这些兴趣将以推送通知的形式发送到您的应用程序。请参考我们关于设置 APNs 推送通知的指南,了解更多相关信息。

初始化 Eventflit 对象

您应该在 AppDelegate 中设置您的应用程序以使用推送通知。设置方式略微不同,取决于您是使用 Swift 还是 Objective-C,以及您是使用 iOS 还是 macOS (OS X)

Swift for iOS

import EventflitSwift
import UserNotifications

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    let eventflit = Eventflit(key: "YOUR_APP_KEY")
    ...

Objective-C for iOS

#import "AppDelegate.h"
@import UserNotifications;

@interface AppDelegate ()

@end

@implementation AppDelegate
...

Swift for macOS

import Cocoa
import EventflitSwift

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate, EventflitDelegate {
    let eventflit = Eventflit(key: "YOUR_APP_KEY")
    // ...

注册 APNs

为了让您的应用程序能够接收推送通知,它必须首先向 APNs 注册。您应该在与应用程序完成启动时执行此操作。您的应用程序应注册所有类型的通知,如下所示

Swift 在 iOS 上

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
    let center = UNUserNotificationCenter.current()
    center.requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in
        // Enable or disable features based on authorization.
    }
    application.registerForRemoteNotifications()

    return true
}

Objective-C 在 iOS 上

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.eventflit = [[Eventflit alloc] initWithKey:@"YOUR_APP_KEY"];

    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
    [center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionAlert | UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) {
        // Enable or disable features based on authorization.
    }];

    [application registerForRemoteNotifications];
    return YES;
}

Swift 在 macOS 上

func applicationDidFinishLaunching(_ aNotification: Notification) {
    NSApp.registerForRemoteNotifications(matching: [NSRemoteNotificationType.alert, NSRemoteNotificationType.sound, NSRemoteNotificationType.badge])
}

接收您的 APNs 设备令牌并在 Eventflit 中注册

接下来,APNs 将响应并提供一个用于识别您的应用程序实例的设备令牌。然后,您的应用程序应使用设备令牌在 Eventflit 中进行注册。

现在,您的应用程序可以订阅兴趣。以下代码将应用程序注册并订阅兴趣 "donuts"。

Swift 在 iOS 上

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    eventflit.nativeEventflit.register(deviceToken: deviceToken)
    eventflit.nativeEventflit.subscribe(interestName: "donuts")
}

Objective-C 在 iOS 上

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    NSLog(@"Registered for remote notifications; received device token");
    [[[self eventflit] nativeEventflit] registerWithDeviceToken:deviceToken];
    [[[self eventflit] nativeEventflit] subscribeWithInterestName:@"donuts"];
}

Swift 在 macOS 上

func application(_ application: NSApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    self.eventflit.nativeEventflit.register(deviceToken: deviceToken)
    self.eventflit.nativeEventflit.subscribe(interestName: "donuts")
}

接收推送通知

当您的服务器向“甜甜圈”这个兴趣点发布通知时,它会传递到您的应用中。这发生在您的AppDelegate中的调用中,您应该监听它

Swift在iOS上

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    print(userInfo)
}

Objective-C在iOS上

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    NSLog(@"Received remote notification: %@", userInfo);
}

Swift在macOS上

func application(_ application: NSApplication, didReceiveRemoteNotification userInfo: [String: Any]) {
    print("Received remote notification: \(userInfo.debugDescription)" )
}

取消订阅兴趣点

如果您以后希望取消订阅兴趣点,这也将以相同的方式进行

Swift

eventflit.nativeEventflit.unsubscribe(interestName: "donuts")

Objective-C

[[[self eventflit] nativeEventflit] unsubscribeWithInterestName:@"donuts"];

关于工作应用的完整示例,请参阅此存储库中的Example/目录。特别是关于推送通知的代码,请参阅Example/AppDelegate.swift文件。

Eventflit 委托

您还可以实现一些 EventflitDelegate 函数来获取与推送通知交互相关的事件。这些是您在遵循 EventflitDelegate 协议时可以可选实现的函数。

@objc optional func registeredForPushNotifications(clientId: String)
@objc optional func failedToRegisterForPushNotifications(response: URLResponse, responseBody: String?)
@objc optional func subscribedToInterest(name: String)
@objc optional func unsubscribedFromInterest(name: String)

再次强调,函数的名称在很大程度上揭示了其目的,但为了完整性,这里列出。

  • registeredForPushNotifications - 如果您想了解客户端何时成功注册了 Eventflit 推送通知服务,或者如果需要访问成功注册时返回的 clientId,请使用此功能。
  • failedToRegisterForPushNotifications - 如果您想了解客户端何时未能注册 Eventflit 推送通知服务,请使用此功能。
  • subscribedToInterest - 如果您想跟踪成功订阅的兴趣,请使用此功能。
  • unsubscribedFromInterest - 如果您想跟踪成功取消订阅的兴趣,请使用此功能。

设置代理的示例如下

Swift

class ViewController: UIViewController, EventflitDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        let eventflit = Eventflit(key: "APP_KEY")
        eventflit.delegate = self
        // ...
    }
}

Objective-C

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.client = [[Eventflit alloc] initWithAppKey:@"YOUR_APP_KEY"];

    self.client.delegate = self;
    // ...
}

与设置 EventflitDelegate 以接收基于连接的事件通知的过程相同。

测试

有一组库的测试可以用标准方法(Xcode中的Command-U)运行。

交流

  • 如果您发现了错误,请提交问题。
  • 如果您有功能请求,请提交问题。
  • 如果您想贡献,请提交拉取请求(最好附带一些测试🙂 ).

致谢

EventflitSwift 由 Eventflit 拥有和维护。最初由 Hamilton Chapman 创建。

它使用了以下存储库中的代码

这些库的个别许可证包含在与相应 Swift 文件相对应的文件中。

许可证

EventflitSwift 在 MIT 许可证下发布。有关详细信息,请参阅 LICENSE