Ably 1.2.33

Ably 1.2.33

测试经过测试
语言语言 Obj-CObjective C
许可证 Apache-2.0
发布日期最后发布日期2024年7月

AblyIkbal KayaQuintin WillisonOwen PearsonStephane MoreauMarat AlekperovLawrence ForooghianUmair 维护。



 
依赖项
msgpack= 0.4.0
AblyDeltaCodec= 1.3.3
 

Ably 1.2.33

Ably iOS、tvOS 和 macOS Objective-C 和 Swift 客户端库 SDK

Check Pod Integration Test: iOS 14.4 Integration Test: macOS 10.15 Integration Test: tvOS 14.3 Features

CocoaPods SPM Swift Compatibility SPM Platform Compatibility

Ably 是一个平台,它可以实现实时同步的数字体验。无论是参加虚拟场所的活动,接收实时金融信息,还是监控实时汽车性能数据,消费者都期望标准化的实时数字体验。每月,Ably 为 80 个国家的超过 2.5 亿台设备提供一套 API,以构建、扩展和实时提供强大的数字体验。像 Bloomberg、HubSpot、Verizon 和 Hopin 这样的组织依赖 Ably 的平台来进行全球规模的业务关键实时数据同步的日益增长的复杂性。有关更多信息,请参阅 Ably 文档

这是为 Ably 编写的 iOS、tvOS 和 macOS Objective-C 和 Swift 客户端库 SDK,用 Objective-C 编写。库目前针对的 Ably 客户端库功能规范 版本 1.2。您可以通过跳转到 '已知的局限性' 部分来看这个客户端库目前不支持的功能,或者 查看我们的客户端库 SDK 功能支持矩阵,以查看所有可用的功能列表。

支持的平台

此 SDK 与以下目标项目兼容

  • iOS 10.0+
  • tvOS 10.0+
  • macOS 10.12+

我们保持与这些平台版本的兼容性,并明确支持这些版本。

我们不明确维护与旧平台版本的兼容性。关于旧版本已知的不兼容性,可以在以下位置找到:这里

如果您找到与不支持的平台版本相关的问题,请在此存储库中提出问题,或联系 Ably 客户支持寻求建议。

持续集成测试

我们在以下操作系统上执行 CI 测试

已知限制

此客户端库当前不与 Ably 的以下功能兼容

功能
自定义 transportParams
记住失败时的回退主机
错误信息 URL 有助于调试问题

文档

访问ably.com/docs,以获取完整的API参考和更多示例。

安装指南

您可以通过软件包管理器、CocoaPods、Carthage或手动方式安装Ably for iOS和macOS。

通过Swift Package Manager安装

  • 要将ably-cocoa软件包安装到您的Xcode项目
    • https://github.com/ably/ably-cocoa粘贴到Swift Packages搜索框中。(在项目下Swift Packages ..+按钮)
    • 选择为您的目标选择Ably SDK。
    • 本Apple指南详细说明了这些步骤。
  • 要在其他Swift包中安装ably-cocoa软件包,请将以下内容添加到您的Package.swift
 .package(url: "https://github.com/ably/ably-cocoa", from: "1.2.20"),

通过CocoaPods安装

如果您打算使用Swift,建议在Podfile中包含use_frameworks!(这将创建一个可以原生在Swift中使用的框架)。

将此行添加到您应用程序的Podfile中

# For Xcode 7.3 and newer
pod 'Ably', '>= 1.2'

然后安装依赖项

$ pod install

通过Carthage安装

将此行添加到您的应用程序的 Cartfile 中

# For Xcode 7.3 and newer
github "ably/ably-cocoa" >= 1.2

然后运行

  • iOScarthage update --use-xcframeworks --platform iOS --no-use-binaries
  • macOScarthage update --use-xcframeworks --platform macOS --no-use-binaries
  • tvOScarthage update --use-xcframeworks --platform tvOS --no-use-binaries

来构建框架并将生成的 (在 [项目根目录]/Carthage/Build)

  • Ably.xcframework
  • AblyDeltaCodec.xcframework
  • msgpack.xcframework

拖入您的 Xcode 项目中。

如果例如您看到 dyld: Library not loaded: @rpath/AblyDeltaCodec.framework/AblyDeltaCodec 错误,那么很可能您忘记将所有依赖项添加到项目中了。您可以在 此处 找到更多信息。

注意: 对于 macOS 目标,您必须在选择您的目标时选择 不嵌入 选项,并确保 Ably.xcframework 出现在 构建阶段 选项卡中的 链接二进制与库 列表中。

手动安装

  1. 从 GitHub 的发布页 获取代码,或克隆它以获取最新、不稳定且可能未充分文档化的版本: git clone [email protected]:ably/ably-cocoa.git
  2. 将目录 ably-cocoa/ably-cocoa 作为组拖入您的项目中。
  3. Ably 依赖于我们的 MessagePack Fork 0.2.0;从 发布页面 获取它,并将其链接到您的项目中。

线程安全

该库提供以下线程安全保证

  • 整个公共接口可以从任何线程安全地访问,无论是读取还是写入。
  • 由库返回的 "值" 对象(例如 ARTTokenDetails,来自消息的数据)可以从和写入是安全的。
  • 传递给库的对象之后不得进行修改。它们可以安全地传递或读取;库不会将数据写入它们。

所有内部操作都调度到单个串行 GCD 队列。您可以使用 ARTClientOptions.internalDispatchQueue 指定自定义队列。

默认情况下,将用户提供的回调的所有调用调度到主队列。这允许您通过执行 UI 操作直接响应 Ably 的输出。您可以使用 ARTClientOptions.dispatchQueue 指定不同的队列。这个队列不应该与 ARTClientOptions.internalDispatchQueue 相同,因为这可能导致死锁。

推送通知

如果您还没有,请首先查看详细的文档。推送通知的示例应用程序也可用。

激活和设备注册

更多信息,请参阅推送通知 - 设备激活和订阅

ARTPushRegistererDelegate定义了处理推送激活、去激活和更新事件的3个委托方法。默认情况下,Ably SDK将检查是否UIApplication.sharedApplication.delegate遵循ARTPushRegistererDelegate,并在适当的时候调用委托方法。因此,指定ARTPushRegistererDelegate是可选的。要使用实现了ARTPushRegistererDelegate的另一个类,必须通过设置ARTClientOptions#pushRegistererDelegate委托将其提供给Ably。在SwiftUI应用程序中,必须设置ARTClientOptions#pushRegistererDelegate委托属性。

不要忘记,ARTPush有两个对应的方法,您应从您的application(_:didRegisterForRemoteNotificationsWithDeviceToken:)application(_:didFailToRegisterForRemoteNotificationsWithError:)中调用这些方法,并将ARTRestARTRealtime实例传递给它们,该实例已配置您所需的身份验证设置和其他选项

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    ARTPush.didRegisterForRemoteNotifications(withDeviceToken: deviceToken, rest: rest)
}

func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
    ARTPush.didFailToRegisterForRemoteNotificationsWithError(error, rest: rest)
}

在任一时刻只能激活一个ARTRestARTRealtime实例以接收推送通知。
在不必要的时刻激活多个实例可能导致意外的后果。

macOS & tvOS

请注意,目前不支持macOS和tvOS的推送通知。您可以只能使用推送管理功能,例如

let recipient: [String: Any] = [
    "clientId": "C04BC116-8004-4D78-A71F-8CA3122734DB"
]
let data: [String: Any] = [
    "notification": [
        "title": "Hello from Ably!",
        "body": "Example push notification from Ably."
    ],
    "data": [
        "foo": "bar",
        "baz": "qux"
    ]
]
realtime.push.admin.publish(recipient, data: data) { error in
    print("Push published:", error ?? "nil")
}

可用的示例:macOStvOS

使用实时API

简介

所有示例都假设已经创建了一个客户端,如下所示

Swift

// basic auth with an API key
let client = ARTRealtime(key: "xxxx:xxxx")

// using token auth
let client = ARTRealtime(token: "xxxx")

Objective-C

// basic auth with an API key
ARTRealtime* client = [[ARTRealtime alloc] initWithKey:@"xxxx:xxxx"];

// using token auth
ARTRealtime* client = [[ARTRealtime alloc] initWithToken:@"xxxx"];

连接

通过实例化 ARTRealtime 默认开始一个连接。你可以通过监听连接状态变化来捕获连接成功或错误

Swift

client.connection.on { stateChange in
    let stateChange = stateChange!
    switch stateChange.current {
    case .Connected:
        print("connected!")
    case .Failed:
        print("failed! \(stateChange.reason)")
    default:
        break
    }
}

Objective-C

[client.connection on:^(ARTConnectionStateChange *stateChange) {
    switch (stateChange.current) {
        case ARTRealtimeConnected:
            NSLog(@"connected!");
            break;
        case ARTRealtimeFailed:
            NSLog(@"failed! %@", stateChange.reason);
            break;
        default:
            break;
    }
}];

你也可以通过设置适当的选项手动连接。

Swift

let options = ARTClientOptions(key: "xxxx:xxxx")
options.autoConnect = false
let client = ARTRealtime(options: options)
client.connection.connect()

Objective-C

ARTClientOptions *options = [[ARTClientOptions alloc] initWithKey:@"xxxx:xxxx"];
options.autoConnect = false;
ARTRealtime *client = [[ARTRealtime alloc] initWithOptions:options];
[client.connection connect];

订阅频道

给定

Swift

let channel = client.channels.get("test")

Objective-C

ARTRealtimeChannel *channel = [client.channels get:@"test"];

订阅所有事件

Swift

channel.subscribe { message in
    print(message.name)
    print(message.data)
}

Objective-C

[channel subscribe:^(ARTMessage *message) {
    NSLog(@"%@", message.name);
    NSLog(@"%@", message.data);
}];

仅订阅某些事件

Swift

channel.subscribe("myEvent") { message in
    print(message.name)
    print(message.data)
}

Objective-C

[channel subscribe:@"myEvent" callback:^(ARTMessage *message) {
    NSLog(@"%@", message.name);
    NSLog(@"%@", message.data);
}];

以增量模式订阅频道

在delta模式下订阅频道可以启用delta压缩。这是一种客户端订阅频道的方式,消息有效负载只包含当前消息和通道上之前消息之间的差异(即delta)。

获取频道时,使用频道选项请求Vcdiff格式的delta流。

Swift

let channelOptions = ARTRealtimeChannelOptions()
channelOptions.params = [
    "delta": "vcdiff"
]

let channel = client.channels.get("test", options: channelOptions)

Objective-C

ARTRealtimeChannelOptions *channelOptions = [[ARTRealtimeChannelOptions alloc] init];
channelOptions.params = @{
    @"delta": @"vcdiff"
};

ARTRealtimeChannel *channel = [client.channels get:@"test" options:channelOptions];

除了指定频道选项之外,其余内容是透明的,无需对您的应用程序进行任何进一步更改。发送到您的订阅回调函数的message.data实例仍然包含最初发布的值。

如果您想检查ARTMessage实例以确定它们呈现的data是否由Ably的delta消息渲染,您可以查看message.extras["delta"]["format"]是否等于"vcdiff"

发布到频道

Swift

channel.publish("greeting", data: "Hello World!")

Objective-C

[channel publish:@"greeting" data:@"Hello World!"];

查询历史

Swift

channel.history { messagesPage, error in
    let messagesPage = messagesPage!
    print(messagesPage.items)
    print(messagesPage.items.first)
    print((messagesPage.items.first as? ARTMessage)?.data) // payload for the message
    print(messagesPage.items.count) // number of messages in the current page of history
    messagesPage.next { nextPage, error in
        // retrieved the next page in nextPage
    }
    print(messagesPage.hasNext) // true, there are more pages
}

Objective-C

[channel history:^(ARTPaginatedResult<ARTMessage *> *messagesPage, ARTErrorInfo *error) {
    NSLog(@"%@", messagesPage.items);
    NSLog(@"%@", messagesPage.items.firstObject);
    NSLog(@"%@", messagesPage.items.firstObject.data); // payload for the message
    NSLog(@"%lu", (unsigned long)[messagesPage.items count]); // number of messages in the current page of history
    [messagesPage next:^(ARTPaginatedResult<ARTMessage *> *nextPage, ARTErrorInfo *error) {
        // retrieved the next page in nextPage
    }];
    NSLog(@"%d", messagesPage.hasNext); // true, there are more pages
}];

频道上的存在状态

Swift

let channel = client.channels.get("test")

channel.presence.enter("john.doe") { errorInfo in
    channel.presence.get { members, errorInfo in
        // members is the array of members present
    }
}

Objective-C

[channel.presence enter:@"john.doe" callback:^(ARTErrorInfo *errorInfo) {
    [channel.presence get:^(ARTPaginatedResult<ARTPresenceMessage *> *result, ARTErrorInfo *error) {
        // members is the array of members present
    }];
}];

查询存在状态历史

Swift

channel.presence.history { presencePage, error in
    let presencePage = presencePage!
    if let first = presencePage.items.first as? ARTPresenceMessage {
        print(first.action) // Any of .Enter, .Update or .Leave
        print(first.clientId) // client ID of member
        print(first.data) // optional data payload of member
        presencePage.next { nextPage, error in
            // retrieved the next page in nextPage
        }
    }
}

Objective-C

[channel.presence history:^(ARTPaginatedResult<ARTPresenceMessage *> *presencePage, ARTErrorInfo *error) {
    ARTPresenceMessage *first = (ARTPresenceMessage *)presencePage.items.firstObject;
    NSLog(@"%lu", (unsigned long)first.action); // Any of ARTPresenceEnter, ARTPresenceUpdate or ARTPresenceLeave
    NSLog(@"%@", first.clientId); // client ID of member
    NSLog(@"%@", first.data); // optional data payload of member
    [presencePage next:^(ARTPaginatedResult<ARTPresenceMessage *> *nextPage, ARTErrorInfo *error) {
        // retrieved the next page in nextPage
    }];
}];

使用 authCallback

调用以获取已签名令牌请求的回调。
可以根据以下方式实例化 ARTClientOptionsARTRealtime 对象

Swift

let clientOptions = ARTClientOptions()
clientOptions.authCallback = { params, callback in
    getTokenRequestJSONFromYourServer(params) { json, error in
        //handle error
        do {
            callback(try ARTTokenRequest.fromJson(json), nil)
        } catch let error as NSError {
            callback(nil, error)
        }
    }
}

let client = ARTRealtime(options:clientOptions)

Objective-C

ARTClientOptions *clientOptions = [[ARTClientOptions alloc] init];
clientOptions.authCallback = ^(ARTTokenParams *params, void(^callback)(id<ARTTokenDetailsCompatible>, NSError*)) {
    [self getTokenRequestJSONFromYourServer:params completion:^(NSDictionary *json, NSError *error) {
        //handle error
        ARTTokenRequest *tokenRequest = [ARTTokenRequest fromJson:json error:&error];
        callback(tokenRequest, error);
    }];
};

ARTRealtime *client = [[ARTRealtime alloc] initWithOptions:clientOptions];

使用 REST API

介绍

所有示例假设已经创建了客户端和/或频道,如下所示

Swift

let client = ARTRest(key: "xxxx:xxxx")
let channel = client.channels.get("test")

Objective-C

ARTRest *client = [[ARTRest alloc] initWithKey:@"xxxx:xxxx"];
ARTRestChannel *channel = [client.channels get:@"test"];

向频道发布消息

Swift

channel.publish("myEvent", data: "Hello!")

Objective-C

[channel publish:@"myEvent" data:@"Hello!"];

查询历史记录

Swift

channel.history { messagesPage, error in
    let messagesPage = messagesPage!
    print(messagesPage.items.first)
    print((messagesPage.items.first as? ARTMessage)?.data) // payload for the message
    messagesPage.next { nextPage, error in
        // retrieved the next page in nextPage
    }
    print(messagesPage.hasNext) // true, there are more pages
}

Objective-C

[channel history:^(ARTPaginatedResult<ARTMessage *> *messagesPage, ARTErrorInfo *error) {
    NSLog(@"%@", messagesPage.items.firstObject);
    NSLog(@"%@", messagesPage.items.firstObject.data); // payload for the message
    NSLog(@"%lu", (unsigned long)[messagesPage.items count]); // number of messages in the current page of history
    [messagesPage next:^(ARTPaginatedResult<ARTMessage *> *nextPage, ARTErrorInfo *error) {
        // retrieved the next page in nextPage
    }];
    NSLog(@"%d", messagesPage.hasNext); // true, there are more pages
}];

频道中的存在状态

Swift

channel.presence.get { membersPage, error in
    let membersPage = membersPage!
    print(membersPage.items.first)
    print((membersPage.items.first as? ARTPresenceMessage)?.data) // payload for the message
    membersPage.next { nextPage, error in
        // retrieved the next page in nextPage
    }
    print(membersPage.hasNext) // true, there are more pages
}

Objective-C

[channel.presence get:^(ARTPaginatedResult<ARTPresenceMessage *> *membersPage, ARTErrorInfo *error) {
    NSLog(@"%@", membersPage.items.firstObject);
    NSLog(@"%@", membersPage.items.firstObject.data); // payload for the message
    [membersPage next:^(ARTPaginatedResult<ARTMessage *> *nextPage, ARTErrorInfo *error) {
        // retrieved the next page in nextPage
    }];
    NSLog(@"%d", membersPage.hasNext); // true, there are more pages
}];

查询存在历史

Swift

channel.presence.history { presencePage, error in
    let presencePage = presencePage!
    if let first = presencePage.items.first as? ARTPresenceMessage {
        print(first.clientId) // client ID of member
        presencePage.next { nextPage, error in
            // retrieved the next page in nextPage
        }
    }
}

Objective-C

[channel.presence history:^(ARTPaginatedResult<ARTPresenceMessage *> *presencePage, ARTErrorInfo *error) {
    ARTPresenceMessage *first = (ARTPresenceMessage *)presencePage.items.firstObject;
    NSLog(@"%@", first.clientId); // client ID of member
    NSLog(@"%@", first.data); // optional data payload of member
    [presencePage next:^(ARTPaginatedResult<ARTPresenceMessage *> *nextPage, ARTErrorInfo *error) {
        // retrieved the next page in nextPage
    }];
}];

生成令牌

Swift

client.auth.requestToken(nil, withOptions: nil) { tokenDetails, error in
    let tokenDetails = tokenDetails!
    print(tokenDetails.token) // "xVLyHw.CLchevH3hF....MDh9ZC_Q"
    let client = ARTRest(token: tokenDetails.token)
}

Objective-C

[client.auth requestToken:nil withOptions:nil callback:^(ARTTokenDetails *tokenDetails, NSError *error) {
    NSLog(@"%@", tokenDetails.token); // "xVLyHw.CLchevH3hF....MDh9ZC_Q"
    ARTRest *client = [[ARTRest alloc] initWithToken:tokenDetails.token];
}];

检索您的应用统计

Swift

client.stats { statsPage, error in
    let statsPage = statsPage!
    print(statsPage.items.first)
    statsPage.next { nextPage, error in
        // retrieved the next page in nextPage
    }
}

Objective-C

[client stats:^(ARTPaginatedResult<ARTStats *> *statsPage, ARTErrorInfo *error) {
    NSLog(@"%@", statsPage.items.firstObject);
    [statsPage next:^(ARTPaginatedResult<ARTStats *> *nextPage, ARTErrorInfo *error) {
        // retrieved the next page in nextPage
    }];
}];

检索Ably服务时间

Swift

client.time { time, error in
    print(time) // 2016-02-09 03:59:24 +0000
}

Objective-C

[client time:^(NSDate *time, NSError *error) {
    NSLog(@"%@", time); // 2016-02-09 03:59:24 +0000
}];

支持、反馈和故障排除

请访问https://support.ably.com/以访问我们的知识库并寻求任何协助。

您还可以查看社区报告的 Github 问题

贡献

详细信息请见CONTRIBUTING.md