### Complete Secure Channel Example with Keychain Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/channel-options.md This Swift example demonstrates how to generate, store, and retrieve an encryption key from the Keychain to create a secure, encrypted Ably channel. It shows the full lifecycle of key management and channel setup. ```swift import Security import CommonCrypto class SecureChannelManager { private let keyIdentifier = "com.example.ably.encryption.key" func generateAndStoreKey() throws -> String { let key = generateEncryptionKey() try storeKeyInKeychain(key) return key } func getOrCreateKey() -> String? { if let existing = loadKeyFromKeychain() { return existing } do { return try generateAndStoreKey() } catch { print("Failed to create key: \(error)") return nil } } func createSecureChannel(realtime: ARTRealtime, name: String) -> ARTRealtimeChannel? { guard let key = getOrCreateKey() else { return nil } let options = ARTRealtimeChannelOptions() options.cipherKey = key options.encrypted = true return realtime.channels.get(name, options: options) } private func generateEncryptionKey() -> String { var key = [UInt8](repeating: 0, count: 32) _ = SecRandomCopyBytes(kSecRandomDefault, 32, &key) return Data(key).base64EncodedString() } private func storeKeyInKeychain(_ key: String) throws { let data = key.data(using: .utf8) ?? Data() let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: keyIdentifier, kSecValueData as String: data ] // Try to delete existing first SecItemDelete(query as CFDictionary) // Add new let status = SecItemAdd(query as CFDictionary, nil) guard status == errSecSuccess else { throw NSError(domain: "Keychain", code: Int(status)) } } private func loadKeyFromKeychain() -> String? { let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: keyIdentifier, kSecReturnData as String: true ] var result: AnyObject? let status = SecItemCopyMatching(query as CFDictionary, &result) guard status == errSecSuccess, let data = result as? Data else { return nil } return String(data: data, encoding: .utf8) } } // Usage let manager = SecureChannelManager() let channel = manager.createSecureChannel(realtime: realtime, name: "secure-channel") channel?.subscribe { message in print("Decrypted message: \(message.data ?? "")") } ``` -------------------------------- ### Setup, Build, and Test Ably Cocoa SDK Source: https://github.com/ably/ably-cocoa/blob/main/CLAUDE.md Commands for initial setup, building the SDK, and running tests. Ensure submodules are updated before building. ```bash git submodule update --init --recursive ``` ```bash swift build ``` ```bash swift test --filter AuthTests ``` ```bash swift test ``` -------------------------------- ### Complete Push Activation Example in Swift Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/push.md This Swift code demonstrates the full setup for push notifications within an AppDelegate. It includes Ably client initialization, requesting user permissions for notifications, registering for remote notifications, and handling the device token. It also implements the ARTPushRegistererDelegate to confirm push activation and deactivation status. ```swift import UIKit import UserNotifications import Ably class AppDelegate: UIResponder, UIApplicationDelegate, ARTPushRegistererDelegate { var realtime: ARTRealtime! func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Setup Ably with push delegate let options = ARTClientOptions(key: "your-ably-key") options.clientId = "user-123" options.pushRegistererDelegate = self realtime = ARTRealtime(options: options) // Request user permission UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in if granted { DispatchQueue.main.async { UIApplication.shared.registerForRemoteNotifications() } } } return true } func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { // Pass token to Ably ARTPush.didRegisterForRemoteNotificationsWithDeviceToken(deviceToken, realtime: realtime) } func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { ARTPush.didFailToRegisterForRemoteNotificationsWithError(error as NSError, realtime: realtime) } // MARK: - ARTPushRegistererDelegate func didActivateAblyPush(_ error: ARTErrorInfo?) { if let error = error { print("Push activation failed: \(error.message)") } else { print("✓ Push notifications activated") } } func didDeactivateAblyPush(_ error: ARTErrorInfo?) { if let error = error { print("Deactivation error: \(error.message)") } else { print("✓ Push notifications deactivated") } } } // In ViewController class ViewController: UIViewController { let realtime: ARTRealtime func enablePush() { realtime.push.activate() } func disablePush() { realtime.push.deactivate() } } ``` -------------------------------- ### Multi-Channel Publishing Example Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/channels.md Shows how to obtain multiple channel instances and publish messages to them independently. ```swift let channels = realtime.channels let updates = channels.get("updates") let alerts = channels.get("alerts") let logs = channels.get("logs") // Publish to multiple channels updates.publish("user-action", data: action) if isAlert { alerts.publish("alert", data: alertData) } logs.publish("event", data: eventData) ``` -------------------------------- ### Install Carthage Source: https://github.com/ably/ably-cocoa/blob/main/CONTRIBUTING.md Install Carthage dependency manager using Homebrew. This is a prerequisite for setting up the development environment. ```bash brew install carthage ``` -------------------------------- ### Setup Development Environment Source: https://github.com/ably/ably-cocoa/blob/main/CONTRIBUTING.md Run this command to set up or update your development machine, including fetching Git submodules and dependencies. ```bash make update ``` -------------------------------- ### Initialize ARTRest with API Key Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/rest-client.md Use this initializer for a quick setup with your Ably API key. ```swift let rest = ARTRest(key: "your-ably-key") ``` -------------------------------- ### Install Gems Source: https://github.com/ably/ably-cocoa/blob/main/CONTRIBUTING.md Install Ruby gems required for development. This command should be run after cloning the repository. ```bash bundle install ``` -------------------------------- ### Install Ably Cocoa Dependency with CocoaPods Source: https://github.com/ably/ably-cocoa/blob/main/README.md After adding the Ably dependency to your Podfile, run the `pod install` command to install the Ably Cocoa SDK. ```bash $ pod install ``` -------------------------------- ### Initialize ARTClientOptions with API Key Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/configuration.md Use this snippet to initialize the ARTClientOptions with a basic API key. This is the most common way to start using the Ably SDK. ```swift let options = ARTClientOptions(key: "ably-api-key") // Configure properties let realtime = ARTRealtime(options: options) ``` ```swift let options = ARTClientOptions(key: "ably-api-key") let realtime = ARTRealtime(options: options) ``` -------------------------------- ### One-Time Setup for Presence Listener on Attach Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/event-emitter.md Conditionally set up a presence listener only once when the channel first attaches. This prevents redundant setup and ensures the listener is active when needed. ```swift // Setup presence listener only on first attach var presenceListenerSetup = false channel.on(.attached) { [weak self] stateChange in if !presenceListenerSetup { presenceListenerSetup = true self?.setupPresenceListener() } } func setupPresenceListener() { channel.presence.subscribe { message in print("Presence: \(message.clientId) -> \(message.action)") } } ``` -------------------------------- ### Get Presence Messages Example Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/rest-presence.md Retrieves presence messages from a channel and iterates through them to print client ID, action, data, and timestamp. ```swift channel.presence.get { messages, error in for message in messages { print("Client: \(message.clientId)") print("Status: \(message.action)") print("Data: \(message.data ?? \"no data\")") print("When: \(message.timestamp ?? Date())") } } ``` -------------------------------- ### Create Simulator Device Source: https://github.com/ably/ably-cocoa/blob/main/CONTRIBUTING.md Example command to create a specific simulator device using `simctl`. This is useful if you don't have a matching simulator for CI test requirements. ```bash xcrun simctl create "iPhone 12 (14.4)" "iPhone 12" "com.apple.CoreSimulator.SimRuntime.iOS-14-4" ``` -------------------------------- ### Initialize ARTClientOptions Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/client-options.md Initializes ARTClientOptions using different authentication methods like API keys, tokens, or token details. The example shows initializing with an API key and setting a client ID. ```objc - (instancetype)init; - (instancetype)initWithKey:(NSString *)key; - (instancetype)initWithToken:(NSString *)token; - (instancetype)initWithTokenDetails:(ARTTokenDetails *)tokenDetails; ``` ```swift let options = ARTClientOptions(key: "your-ably-key") options.clientId = "user123" let realtime = ARTRealtime(options: options) ``` -------------------------------- ### Configure Channel Encryption with Cipher Parameters Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/channel-options.md This example demonstrates configuring channel encryption using advanced cipher parameters such as algorithm, key length, and mode. ```swift let cipherParams = ARTCipherParams() cipherParams.algorithm = "AES" cipherParams.keyLength = 256 cipherParams.mode = "CBC" // or "GCM" cipherParams.key = "BASE64-ENCODED-KEY" cipherParams.iv = "BASE64-ENCODED-IV" // if needed let options = ARTChannelOptions() options.cipherParams = cipherParams ``` -------------------------------- ### Complete Ably Client Configuration Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/configuration.md This snippet demonstrates a comprehensive setup of ARTClientOptions, including identity, connection behavior, timeouts, protocol settings, logging, custom hosts, token defaults, dispatch queues, fallback hosts, and creating an Ably client. It also shows how to configure a secure channel with a cipher key. ```swift import Ably let options = ARTClientOptions(key: "ably-api-key") // Identity options.clientId = "user-123" // Connection behavior options.autoConnect = true options.tls = true options.queueMessages = true options.echoMessages = false // Timeouts (milliseconds) options.httpOpenTimeout = 5.0 options.httpRequestTimeout = 15.0 options.disconnectedRetryTimeout = 10.0 options.suspendedRetryTimeout = 20.0 options.channelRetryTimeout = 15.0 // Protocol options.useBinaryProtocol = true options.idempotentRestPublishing = true options.addRequestIds = true // Logging options.logLevel = .debug let logHandler = ARTLog() logHandler.level = .debug options.logHandler = logHandler // Custom hosts options.environment = "staging" options.restHost = "api.staging.ably.io" options.realtimeHost = "ws.staging.ably.io" // Token defaults let tokenParams = ARTTokenParams() tokenParams.ttl = 3600 tokenParams.capability = "[{{\"channel\":\"orders:*\",\"operations\":[\"publish\",\"subscribe\"]}}]" options.defaultTokenParams = tokenParams // Dispatch options.dispatchQueue = DispatchQueue.main options.internalDispatchQueue = DispatchQueue(label: "com.example.ably.internal", attributes: .serial) // Fallback hosts options.fallbackHosts = ["backup1.ably.io", "backup2.ably.io"] options.httpMaxRetryCount = 3 // Create client let realtime = ARTRealtime(options: options) // Create secure channel let channelOptions = ARTRealtimeChannelOptions() channelOptions.cipherKey = "BASE64-256-BIT-KEY" let channel = realtime.channels.get("secure-data", options: channelOptions) ``` -------------------------------- ### Handle Channel State Changes Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/types.md Example of reacting to channel state changes, specifically when a channel becomes attached. ```swift channel.on { stateChange in if stateChange.current == .attached { print("Channel attached") } } ``` -------------------------------- ### Typical Ably Usage Pattern Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/INDEX.md A comprehensive example demonstrating the typical usage pattern for the Ably Cocoa SDK, including initialization, channel attachment, message subscription, publishing, and presence management. ```swift import Ably // Initialize let options = ARTClientOptions(key: "ably-api-key") options.clientId = "user-123" let realtime = ARTRealtime(options: options) // Wait for connection realtime.connection.once(.connected) { _ in // Get channel let channel = realtime.channels.get("my-channel") // Attach channel.attach { error in if error == nil { // Subscribe channel.subscribe { message in print("Received: \(message.data ?? "")") } // Publish channel.publish("greeting", data: "hello world") // Presence channel.presence.enter(["status": "online"]) { error in channel.presence.subscribe { message in print("Member: \(message.clientId)") } } } } } ``` -------------------------------- ### Subscribe to Presence Messages Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/types.md Example of subscribing to presence updates on a channel and logging member information. ```swift presence.subscribe { message in print("Member: \(message.clientId)") print("Action: \(message.action)") print("Data: \(message.data ?? {})") } ``` -------------------------------- ### Get All Members on Channel Attach Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/realtime-presence.md Fetches and logs all members present on a channel once the channel has successfully attached. ```swift let channel = realtime.channels.get("my-channel") channel.attach { error in channel.presence.get { members, error in guard let members = members else { return } for member in members { print("Found: \(member.clientId)") } } } ``` -------------------------------- ### Publishing ARTMessage with Client ID Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/message.md Example of creating an ARTMessage with a name, dictionary data, and a specific clientId, then publishing it to a channel. ```swift // Create message for publishing let msg = ARTMessage(name: "user-login", data: ["userId": 123]) msg.clientId = "client456" channel.publish(msg) { error in print("Published: \(error?.message ?? \"success\")") } // Or create with dict data let data: [String: Any] = ["action": "update", "value": 42] let msg2 = ARTMessage(name: "event", data: data) ``` -------------------------------- ### Configure Ably Client Options in Swift Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/client-options.md Set up ARTClientOptions to customize your Ably client's behavior, including identity, connection settings, timeouts, logging levels, custom hostnames, and default token parameters. This example demonstrates a comprehensive configuration. ```swift let options = ARTClientOptions(key: "your-api-key") // Identity options.clientId = "user-123" // Connection options.autoConnect = true options.tls = true options.queueMessages = true options.echoMessages = true // Timeouts options.httpOpenTimeout = 5.0 options.httpRequestTimeout = 15.0 options.disconnectedRetryTimeout = 10.0 options.suspendedRetryTimeout = 20.0 // Logging options.logLevel = .debug // Custom hosts options.restHost = "api.example.com" options.realtimeHost = "ws.example.com" // Token defaults let tokenParams = ARTTokenParams() tokenParams.ttl = 3600 tokenParams.capability = "[{{\"channel\":\"*\",\"operations\":[\"publish\"]}}]" options.defaultTokenParams = tokenParams let realtime = ARTRealtime(options: options) ``` -------------------------------- ### Get or Create Realtime Channel Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/channels.md Retrieves an existing channel instance by name or creates a new one if it does not exist. Does not automatically attach to the channel. ```objc - (ARTRealtimeChannel *)get:(NSString *)name; - (ARTRealtimeChannel *)get:(NSString *)name options:(ARTRealtimeChannelOptions *)options; ``` ```swift // Get or create channel let channel = realtime.channels.get("my-channel") // With options let options = ARTRealtimeChannelOptions() options.encrypted = true let secureChannel = realtime.channels.get("secure-channel", options: options) ``` -------------------------------- ### Lint Ably Cocoa SDK with EditorConfig Source: https://github.com/ably/ably-cocoa/blob/main/CLAUDE.md Runs the EditorConfig checker to ensure compliance with project linting rules. Requires `editorconfig-checker` to be installed. ```bash make lint ``` -------------------------------- ### Initialize and Use Ably Realtime Client Source: https://github.com/ably/ably-cocoa/blob/main/README.md Demonstrates how to initialize the Ably Realtime client, subscribe to a channel, and publish messages. Ensure you replace 'your-ably-api-key' with your actual API key. ```swift // Initialize Ably Realtime client let clientOptions = ARTClientOptions(key: "your-ably-api-key") clientOptions.clientId = "me" let realtime = ARTRealtime(options: clientOptions) // Wait for connection to be established realtime.connection.on { stateChange in if stateChange.current == .connected { print("Connected to Ably") // Get a reference to the 'test-channel' channel let channel = realtime.channels.get("test-channel") // Subscribe to all messages published to this channel channel.subscribe { message in print("Received message: \(message.data ?? "")") } // Publish a test message to the channel channel.publish("test-event", data: "hello world!") { error in guard error == nil else { print("Error publishing message: \(error!.message)") return } print("Message successfully published") } } } ``` -------------------------------- ### Get Presence Members Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/realtime-presence.md Get current presence members on the channel. Supports filtering and pagination via `ARTRealtimePresenceQuery`. ```APIDOC ## get:callback: ### Description Get current presence members. ### Method GET ### Endpoint /channels/{channelId}/presence ### Parameters #### Query Parameters - **limit** (integer) - Optional - Maximum number of presence messages to return - **waitForSync** (boolean) - Optional - Whether to wait for initial presence sync to complete - **direction** (string) - Optional - "forwards" or "backwards" for pagination - **paginationToken** (string) - Optional - Token for fetching next page of results ### Response #### Success Response (200) - **messages** (array ofъARTPresenceMessage) - Array of current presence messages. - **next** (function) - Function to fetch the next page of results if available. #### Response Example ```json { "messages": [ { "action": "enter", "clientId": "user-123", "data": { "status": "online" }, "timestamp": 1678886400000 }, { "action": "enter", "clientId": "user-456", "data": { "status": "online" }, "timestamp": 1678886401000 } ], "next": "function() { ... }" } ``` ``` -------------------------------- ### Get Message Versions Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/message.md Retrieve all historical versions of a message identified by its serial. ```swift channel.getMessageVersionsWithSerial("serial-id") { result, error in guard let result = result else { print("Error: \(error?.message ?? "")") return } for version in result.items { print("Action: \(version.action), Data: \(version.data ?? "")") } } ``` -------------------------------- ### Get Message by Serial Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/message.md Retrieve a specific message using its serial identifier. ```swift channel.getMessageWithSerial("serial-id") { message, error in guard let message = message else { print("Error: \(error?.message ?? "")") return } print("Latest version: \(message.data ?? "")") } ``` -------------------------------- ### Token Callback Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/auth.md Configure the library to call a callback function to get tokens on-demand. ```APIDOC ## Token Callback Library calls callback to get tokens on-demand. ```swift let options = ARTAuthOptions() options.authCallback = { tokenParams, completion in // Fetch token from your auth server let token = getTokenFromServer(clientId: self.clientId) completion(token, nil) } let realtime = ARTRealtime(options: options as ARTClientOptions) ``` ### Signature: ```objc typedef void (^ARTAuthCallback)(ARTTokenParams *_Nullable, void (^_Nonnull)(id _Nullable, NSError *_Nullable)); ``` The callback receives: - `tokenParams` — suggested parameters (respects TTL, capabilities) - Completion block — call with token (string, `ARTTokenRequest`, or `ARTTokenDetails`) or error ``` -------------------------------- ### Initialize ARTRest with Custom Options Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/rest-client.md Configure ARTRest with custom options, including client ID and TLS settings. ```swift let options = ARTClientOptions(key: "your-key") options.clientId = "server123" options.tls = true let rest = ARTRest(options: options) ``` -------------------------------- ### Get Message Versions Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/message.md Retrieve all historical versions of a message identified by its serial number. ```APIDOC ## Get Message Versions Retrieve all versions of a message: ```swift channel.getMessageVersionsWithSerial("serial-id") { result, error in guard let result = result else { print("Error: \(error?.message ?? "")") return } for version in result.items { print("Action: \(version.action), Data: \(version.data ?? "")") } } ``` ``` -------------------------------- ### Initialization Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/realtime-client.md Initializes the ARTRealtime client with configuration options, an API key, or a token. The connection is established asynchronously if autoConnect is enabled. ```APIDOC ## Initialization ### Signature ```objc - (instancetype)initWithOptions:(ARTClientOptions *)options; - (instancetype)initWithKey:(NSString *)key; - (instancetype)initWithToken:(NSString *)token; ``` | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | options | `ARTClientOptions` | Yes | — | Configuration object containing auth and connection settings | | key | `NSString` | Yes | — | Ably API key string (shorthand initializer) | | token | `NSString` | Yes | — | Ably token string (shorthand initializer) | ### Return Value Fully initialized `ARTRealtime` instance. The connection is established asynchronously if `ARTClientOptions.autoConnect` is `true` (default). ### Example ```swift // Initialize with API key let options = ARTClientOptions(key: "your-ably-key") options.clientId = "user123" let realtime = ARTRealtime(options: options) // Or with token let realtime = ARTRealtime(token: "token-string") // Handle connection state changes realtime.connection.on { stateChange in switch stateChange.current { case .connected: print("Connected to Ably") case .failed, .closed: print("Connection failed: \(stateChange.reason)") default: break } } ``` ``` -------------------------------- ### Get Message by Serial Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/message.md Retrieve a specific message using its unique serial identifier. ```APIDOC ## Get Message by Serial ```swift channel.getMessageWithSerial("serial-id") { message, error in guard let message = message else { print("Error: \(error?.message ?? "")") return } print("Latest version: \(message.data ?? "")") } ``` ``` -------------------------------- ### Channel Naming Conventions Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/channels.md Illustrates recommended patterns for naming channels, using domain, resource, and hierarchical structures for clarity. ```swift // By domain channels.get("orders:created") channels.get("orders:updated") channels.get("orders:deleted") // By resource channels.get("users:123:events") channels.get("users:123:notifications") // Hierarchical channels.get("chat:lobby") channels.get("chat:private:abc123") channels.get("games:chess:room-456") ``` -------------------------------- ### Handle ARTErrorInfo Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/types.md Example of how to access error details from a failed operation using ARTErrorInfo. ```swift channel.publish("msg", data: "data") { error in if let error = error as? ARTErrorInfo { print("Code: \(error.code)") print("Message: \(error.message)") if let reqId = error.requestId { print("Request ID: \(reqId)") } } } ``` -------------------------------- ### Initialize ARTRealtime Client Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/realtime-client.md Initialize the ARTRealtime client using an API key or a token. You can also set a client ID for identification. Connection state changes can be handled via a callback. ```swift let options = ARTClientOptions(key: "your-ably-key") options.clientId = "user123" let realtime = ARTRealtime(options: options) // Or with token let realtime = ARTRealtime(token: "token-string") // Handle connection state changes realtime.connection.on { stateChange in switch stateChange.current { case .connected: print("Connected to Ably") case .failed, .closed: print("Connection failed: \(stateChange.reason)") default: break } } ``` -------------------------------- ### Initialize with Token Callback Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/INDEX.md Configure the Ably client to obtain a token dynamically using a callback function. This is useful for securely fetching tokens from your server. ```swift let options = ARTAuthOptions() options.authCallback = { params, completion in let token = getTokenFromServer() completion(token, nil) } ``` -------------------------------- ### Initialize with API Key Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/INDEX.md Initialize the Ably client using an API key. This is a common way to authenticate your application. ```swift let options = ARTClientOptions(key: "your-api-key") let realtime = ARTRealtime(options: options) ``` -------------------------------- ### Get Channel Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/INDEX.md Retrieves a channel instance for publishing and subscribing to messages. Supports both Realtime and REST clients. ```APIDOC ## Get Channel ### Description Retrieves a channel instance for publishing and subscribing to messages. Supports both Realtime and REST clients. ### Method ```swift let channel = realtime.channels.get("channel-name") let restChannel = rest.channels.get("channel-name") ``` ### Endpoint N/A (SDK Method) ``` -------------------------------- ### Monitor Connection State Changes Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/types.md Shows how to observe connection state transitions and log reasons for changes. ```swift realtime.connection.on { stateChange in print("State: \(stateChange.previous) -> \(stateChange.current)") if let reason = stateChange.reason { print("Reason: \(reason.message)") } } ``` -------------------------------- ### Get Server Time Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/rest-client.md Retrieve the current server time. The callback receives an NSDate object or an error. ```swift rest.time { date, error in guard let date = date else { print("Error: \(error?.message ?? "unknown")") return } print("Server time: \(date)") } ``` -------------------------------- ### Message with Client Metadata Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/message.md Example of publishing a message that includes client-specific metadata such as `clientId` and custom `extras`. ```APIDOC ## Message with Client Metadata ```swift let msg = ARTMessage(name: "action", data: "payload") msg.clientId = currentUser.id msg.extras = ["source": "mobile-app", "version": "1.0.0"] channel.publish(msg) ``` ``` -------------------------------- ### Initialize with Static Token Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/INDEX.md Initialize the Ably client using a pre-obtained static token string. Ensure the token is valid and has the necessary permissions. ```swift let options = ARTClientOptions() options.token = "token-string" let realtime = ARTRealtime(options: options) ``` -------------------------------- ### Realtime Channel Lifecycle Management Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/channels.md Demonstrates the typical lifecycle of a realtime channel, including creation, attachment, subscription, detachment, and release. ```swift let realtime = ARTRealtime(key: "key") // Create/get channel let channel = realtime.channels.get("my-channel") // Attach and subscribe channel.attach { error in let listener = channel.subscribe { message in print("Message: \(message.data ?? "")") } } // Later, detach channel.detach { error in print("Detached") } // Release completely realtime.channels.release("my-channel") // Or release all realtime.channels.releaseAll() ``` -------------------------------- ### Structured Events Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/message.md Example of publishing structured data as a message, using `Codable` types for event payloads. ```APIDOC ## Structured Events ```swift struct LoginEvent: Codable { let userId: Int let timestamp: TimeInterval } let event = LoginEvent(userId: 123, timestamp: Date().timeIntervalSince1970) let data = try JSONEncoder().encode(event) let msg = ARTMessage(name: "user.login", data: data) channel.publish(msg) ``` ``` -------------------------------- ### Get Realtime Channel Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/INDEX.md Obtain a reference to a realtime channel by its name. This is the first step to interacting with a specific channel. ```swift let channel = realtime.channels.get("channel-name") ``` -------------------------------- ### Configure Logging Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/client-options.md Initialize client options with a custom log handler and set the desired log level for debugging. ```swift let options = ARTClientOptions(key: "key") let logHandler = ARTLog() logHandler.level = .debug options.logHandler = logHandler options.logLevel = .debug ``` -------------------------------- ### Get or Create REST Channel Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/channels.md Retrieves or creates a channel instance for REST operations. This does not manage connection state. ```objc - (ARTRestChannel *)get:(NSString *)name; - (ARTRestChannel *)get:(NSString *)name options:(ARTChannelOptions *)options; ``` ```swift let channel = rest.channels.get("my-channel") // Publish without connection channel.publish("event", data: "data") { error in print("Published via REST: \(error?.message ?? "success")") } ``` -------------------------------- ### Initialize with Token URL Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/INDEX.md Configure the Ably client to obtain a token from a specified URL. The SDK will make a request to this URL to fetch the token. ```swift let options = ARTAuthOptions() options.authUrl = URL(string: "https://auth.example.com/token") ``` -------------------------------- ### Configure Plugins Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/client-options.md Register plugin extensions with the client options, such as the LiveObjects functionality. ```swift let options = ARTClientOptions(key: "key") options.plugins = [ARTPluginNameLiveObjects: AblyLiveObjects.Plugin.self] ``` -------------------------------- ### Configure Plugins Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/configuration.md Add experimental plugin support to the SDK. This allows for extending the SDK's functionality with custom modules. ```swift let options = ARTClientOptions(key: "key") options.plugins = [ ARTPluginNameLiveObjects: AblyLiveObjects.Plugin.self ] ``` -------------------------------- ### Configure Custom Hosts and Ports Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/configuration.md Set custom hostnames and ports for Ably services using ARTClientOptions. This is useful for connecting to non-standard environments. ```swift let options = ARTClientOptions(key: "key") options.environment = "custom" // or "staging", "production" options.restHost = "api.custom.io" options.realtimeHost = "ws.custom.io" options.port = 8080 options.tlsPort = 8443 ``` -------------------------------- ### Get Member Data Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/rest-presence.md Retrieves the presence data associated with a specific client ID. Fetches all members and then finds the first match. ```swift let clientId = "user-456" channel.presence.get { members, error in if let member = members.first(where: { $0.clientId == clientId }) { print("Status: \(member.data ?? {})") } } ``` -------------------------------- ### Configure Protocol and Encoding Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/client-options.md Choose between MsgPack (binary) or JSON (text) encoding for protocol communication. Using binary protocol can improve performance. ```swift let options = ARTClientOptions(key: "key") options.useBinaryProtocol = true // Use MsgPack ``` -------------------------------- ### Count Active Members Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/rest-presence.md Counts the number of currently active members in a channel by fetching all members and getting the count of the resulting array. ```swift channel.presence.get { members, error in print("Active members: \(members.count)") } ``` -------------------------------- ### Run Swift Tests Source: https://github.com/ably/ably-cocoa/blob/main/CONTRIBUTING.md Execute the test suite on your Mac using the `swift test` command. Ensure all tests pass before submitting changes. ```bash swift test ``` -------------------------------- ### Get Current Presence Members Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/realtime-presence.md Use this to retrieve the current presence members on the channel. The callback returns an array of ARPResenceMessage objects. ```swift presence.get { messages, error in guard let messages = messages else { print("Error: \(error?.message ?? "")") return } for member in messages { print("Member: \(member.clientId), Status: \(member.action)") } } ``` -------------------------------- ### Get REST Channel Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/INDEX.md Obtain a reference to a REST channel by its name. This is used for performing REST API operations on a specific channel. ```swift let restChannel = rest.channels.get("channel-name") ``` -------------------------------- ### Configure Basic Connection Settings Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/configuration.md Set basic connection properties for ARTClientOptions, including auto-connect, TLS usage, message queuing, and echo messages. ```swift let options = ARTClientOptions(key: "key") options.autoConnect = true options.tls = true options.queueMessages = true options.echoMessages = true ``` -------------------------------- ### ARTDataQuery Objective-C Interface Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/rest-presence.md Defines the ARTDataQuery interface, extending ARTPresenceQuery to include start and end time properties for time-range filtering. ```objc #interface ARTDataQuery : ARTPresenceQuery @property (nullable, readwrite, nonatomic) NSDate *start; @property (nullable, readwrite, nonatomic) NSDate *end; @end ``` -------------------------------- ### Configure Ably Connection Options Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/connection.md Customize connection behavior using `ARTClientOptions`. This includes setting auto-connect, retry timeouts, and fallback hosts. ```swift let options = ARTClientOptions(key: "key") options.autoConnect = false options.disconnectedRetryTimeout = 5.0 options.suspendedRetryTimeout = 60.0 options.fallbackHosts = ["example.ably.io", "backup.ably.io"] let realtime = ARTRealtime(options: options) ``` -------------------------------- ### Ably Cocoa Client Library SDK Overview Source: https://github.com/ably/ably-cocoa/blob/main/Docs/Main.md Overview of the Ably Cocoa Client Library SDK, its interfaces, and where to find more detailed documentation. ```APIDOC ## Ably Cocoa Client Library SDK Overview ### Description The Ably Cocoa Client Library SDK offers two primary interfaces: a realtime interface for maintaining persistent connections and a REST interface for stateless operations. ### Realtime Interface Enables clients to establish persistent connections with Ably, facilitating the publishing and subscribing to messages on channels, as well as presence management. ### REST Interface This stateless interface is typically used server-side for operations such as retrieving statistics, token authentication, and publishing messages to channels. ### Further Documentation - **Conceptual Information**: [Ably docs](https://ably.com/docs/) - **All Languages API References**: [Ably API references](https://ably.com/docs/api/) - **Realtime SDK API Reference**: [Ably Realtime SDK](https://ably.com/docs/api/realtime-sdk) - **REST SDK API Reference**: [Ably REST SDK](https://ably.com/docs/api/rest-sdk) ``` -------------------------------- ### ARTRest Initialization Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/rest-client.md Initializes an ARTRest client instance. This does not establish a connection; requests are made on-demand. You can initialize using an API key, a token string, or a detailed options object. ```APIDOC ## ARTRest Initialization ### Description Initializes an `ARTRest` instance. No connection is established; requests are made on-demand. ### Signature ```objc - (instancetype)initWithOptions:(ARTClientOptions *)options; - (instancetype)initWithKey:(NSString *)key; - (instancetype)initWithToken:(NSString *)token; ``` ### Parameters #### Initializer Parameters - **options** (`ARTClientOptions`) - Required - Configuration object with auth and host settings. - **key** (`NSString`) - Required - Ably API key (shorthand initializer). - **token** (`NSString`) - Required - Ably token string (shorthand initializer). ### Return Value Initialized `ARTRest` instance. ### Example ```swift // Initialize with API key let rest = ARTRest(key: "your-ably-key") // Or with custom options let options = ARTClientOptions(key: "your-key") options.clientId = "server123" options.tls = true let rest = ARTRest(options: options) ``` ``` -------------------------------- ### Get Current Presence Members Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/rest-presence.md Retrieves the current members present on a channel. This can be used to check if a specific member is present or to count active members. ```APIDOC ## GET /presence ### Description Retrieves the current members present on a channel. ### Method GET ### Endpoint /presence ### Parameters #### Query Parameters - **limit** (NSUInteger) - Optional - Maximum number of results to return. - **direction** (ARTQueryDirection) - Optional - Direction of results ordering (e.g., .forwards, .backwards). ### Response #### Success Response (200) - **items** (ARTPresenceMessage[]) - An array of presence messages representing current members. ### Request Example ```swift channel.presence.get { messages, error in // Process messages } ``` ### Response Example ```json { "clientId": "user-123", "action": ".enter", "data": {}, "encoding": null, "timestamp": 1678886400000, "id": "msg-id-1" } ``` ``` -------------------------------- ### Enable verbose logging in ARTClientOptions Source: https://github.com/ably/ably-cocoa/blob/main/Docs/tools-for-investigating-test-failures.md Pass the `debug: true` parameter to `AblyTests.commonAppSetup` to enable verbose logging within the `ARTClientOptions`. Be aware that increasing the log level may interfere with some tests and potentially introduce new failures. ```swift AblyTests.commonAppSetup(debug: true) ``` -------------------------------- ### Get Historical Presence Changes Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/rest-presence.md Retrieves historical presence changes on a channel with specified query parameters. Handles pagination and potential validation errors. ```swift let query = ARTDataQuery() query.limit = 100 query.direction = .backwards // Most recent first var error: NSError? let success = channel.presence.history(query, callback: { result in guard let messages = result.items as? [ARTPresenceMessage] else { return } for message in messages { switch message.action { case .enter: print("\(message.clientId) entered at \(message.timestamp ?? Date())") case .leave: print("\(message.clientId) left at \(message.timestamp ?? Date())") case .update: print("\(message.clientId) updated: \(message.data ?? "")") default: break } } // Pagination if result.hasNext { result.next? { nextResult in // More history... } } }, error: &error) if !success { print("Query error: \(error?.localizedDescription ?? "unknown")") } ``` -------------------------------- ### Get Current Presence Members with Pagination Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/rest-presence.md Retrieves current presence members with custom pagination and direction. Allows fetching subsequent pages if available. ```swift let query = ARTPresenceQuery() query.limit = 50 query.direction = .backwards channel.presence.get(query) { members, error in guard let members = members else { return } for member in members { print("Member: \(member.clientId)") } // Get next page if available if let nextPageFn = members.next? { nextPageFn { nextPage, error in // Process next batch } } } ``` -------------------------------- ### get:query: Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/realtime-presence.md Retrieve the current members of the presence set with optional query parameters. This method allows fetching presence data with filtering and ordering. ```APIDOC ## get:query: ### Description Retrieve the current members of the presence set with optional query parameters. This method allows fetching presence data with filtering and ordering. ### Method Objective-C Method Signature ### Endpoint N/A (SDK Method) ### Parameters #### Path Parameters None #### Query Parameters * **query** (`ARTRealtimePresenceQuery`) - Optional - Specifies query options like limit, direction, and `waitForSync`. #### Request Body None ### Request Example ```swift let query = ARTRealtimePresenceQuery() query.limit = 25 query.direction = .forwards query.waitForSync = false // Return current snapshot presence.get(query) { members, error in for member in members { print("\(member.clientId) is \(member.action)") } } ``` ### Response #### Success Response (200) * **members** (Array of `ARTMember`) - A list of members currently in the presence set. * **error** (`ARTErrorInfo`) - An error object if the request failed. #### Response Example ```json { "members": [ { "clientId": "user123", "action": ".enter", "data": null, "encoding": null, "timestamp": "2023-10-27T10:00:00Z", "id": "msg-id-1" } ], "error": null } ``` ``` -------------------------------- ### Get Server Time Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/realtime-client.md Retrieve the current time from the Ably service. The callback receives an NSDate object with the server time or an error if the request fails. ```swift realtime.time { date, error in if let error = error { print("Error: \(error.message)") } else if let date = date { print("Server time: \(date)") } } ``` -------------------------------- ### Configure Fallback Hosts and Retry Settings Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/configuration.md Specify custom fallback hosts and configure retry counts and durations for network fallbacks using ARTClientOptions. ```swift let options = ARTClientOptions(key: "key") options.fallbackHosts = ["host1.ably.io", "host2.ably.io", "host3.ably.io"] options.httpMaxRetryCount = 3 options.httpMaxRetryDuration = 15.0 ``` -------------------------------- ### Subscribe to Event Once Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/event-emitter.md Register a callback that will be executed only once for a specific event. The listener is automatically removed after the first invocation. Useful for one-time setup or initialization tasks. ```swift // Wait for first connection realtime.connection.once(.connected) { stateChange in print("First time connected!") // Listener automatically removed } // Wait for channel attach channel.once(.attached) { stateChange in print("Channel ready to use") } ``` -------------------------------- ### Configure Message Handling Options Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/configuration.md Customize message handling behavior, including binary protocol usage and idempotent publishing. Use binary protocol for efficiency. ```swift let options = ARTClientOptions(key: "key") options.useBinaryProtocol = true // MsgPack options.idempotentRestPublishing = true options.addRequestIds = false ``` -------------------------------- ### Set Channel Encryption Option Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/realtime-channel.md Demonstrates how to enable encryption for a channel at runtime. The callback will indicate success or provide an error message. ```swift let options = ARTRealtimeChannelOptions() options.encrypted = true channel.setOptions(options) { error in print("Options set: \(error?.message ?? \"success\")") } ``` -------------------------------- ### Get Presence History Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/rest-presence.md Retrieves historical presence messages for a channel within a specified time range. Supports pagination for fetching large history sets. ```APIDOC ## GET /presence/history ### Description Retrieves historical presence messages for a channel. ### Method GET ### Endpoint /presence/history ### Parameters #### Query Parameters - **limit** (NSUInteger) - Optional - Maximum number of results per page. Defaults to 100. - **direction** (ARTQueryDirection) - Optional - Direction of results ordering. Defaults to .backwards. - **start** (NSDate?) - Optional - Start time (inclusive) for the history query. - **end** (NSDate?) - Optional - End time (inclusive) for the history query. ### Response #### Success Response (200) - **items** (ARTPresenceMessage[]) - An array of historical presence messages. - **hasNext** (bool) - Indicates if there are more pages of results. - **next** (function) - A function to fetch the next page of results. ### Request Example ```swift let query = ARTDataQuery() query.limit = 1000 query.direction = .forwards channel.presence.history(query, callback: { result in // Process historical messages }, error: nil) ``` ### Response Example ```json { "items": [ { "clientId": "user-123", "action": ".enter", "timestamp": 1678886400000 } ], "hasNext": true, "next": "" } ``` ``` -------------------------------- ### Configure Logging Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/configuration.md Set up a custom log handler and define the logging level for debugging and monitoring. Debug level provides the most verbose output. ```swift let options = ARTClientOptions(key: "key") let logHandler = ARTLog() options.logHandler = logHandler options.logLevel = .debug ``` -------------------------------- ### Get Historical Presence Changes with Time Range Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/rest-presence.md Retrieves historical presence changes within a specific time range. Results can be ordered forwards or backwards. ```swift let query = ARTDataQuery() query.start = Date(timeIntervalSinceNow: -3600) // Last hour query.end = Date() query.limit = 50 query.direction = .forwards // Oldest to newest channel.presence.history(query, callback: { result in for msg in result.items { print("Presence history: \(msg.clientId) -> \(msg.action)") } }, error: nil) ``` -------------------------------- ### Detect Connection Problems Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/event-emitter.md Monitor connection state changes to detect and handle network issues. This example logs messages for disconnected, suspended, or failed states. ```swift realtime.connection.on { stateChange in switch stateChange.current { case .disconnected, .suspended: print("Connection problem detected") case .failed: print("Fatal connection error") // Handle fatal error default: break } } ``` -------------------------------- ### Configure Dynamic Token Authentication with Callback Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/configuration.md Set up a callback for dynamic token renewal using ARTAuthOptions. The callback fetches a new token from a server when needed. ```swift let options = ARTAuthOptions() options.authCallback = { tokenParams, completion in // Fetch token from server let token = fetchToken() completion(token, nil) } ``` -------------------------------- ### Configure Dynamic Token Authentication with URL Source: https://github.com/ably/ably-cocoa/blob/main/_autodocs/configuration.md Configure ARTAuthOptions to fetch tokens from a dynamic URL. This allows for custom authentication endpoints and methods. ```swift let options = ARTAuthOptions() options.authUrl = URL(string: "https://auth.example.com/token") options.authMethod = "POST" options.authHeaders = ["Authorization": "Bearer token"] options.authParams = [ URLQueryItem(name: "clientId", value: "user123") ] ```