-
Notifications
You must be signed in to change notification settings - Fork 43
[ECO-5267] Swift pub/sub getting started #2620
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,285 @@ | ||
--- | ||
title: "Getting started: Pub/Sub in Swift" | ||
meta_description: "Get started with Pub/Sub in Swift using Ably. Learn how to publish, subscribe, track presence, fetch message history, and manage realtime connections." | ||
meta_keywords: "Pub/Sub Swift, Swift PubSub, Ably Swift SDK, realtime messaging Swift, publish subscribe Swift, Ably Pub/Sub guide, Swift realtime communication, Ably tutorial Swift, Swift message history, presence API Swift, Ably Pub/Sub example, realtime Pub/Sub Swift, subscribe to channel Swift, publish message Swift, Ably CLI Pub/Sub" | ||
--- | ||
|
||
This guide will get you started with Ably Pub/Sub in Swift. | ||
|
||
It will take you through the following steps: | ||
|
||
* Create a client and establish a realtime connection to Ably. | ||
* Attach to a channel and subscribe to its messages. | ||
* Publish a message to the channel for your client to receive. | ||
* Join and subscribe to the presence set of the channel. | ||
* Retrieve the messages you sent in the guide from history. | ||
* Close a connection to Ably when it is no longer needed. | ||
|
||
h2(#prerequisites). Prerequisites | ||
|
||
* Sign up for an Ably account. | ||
** Create a new app, and create your first API key. | ||
** Your API key will need the @publish@, @subscribe@, @presence@ and @history@ capabilities. | ||
|
||
* Install the Ably CLI: | ||
|
||
```[sh] | ||
npm install -g @ably/cli | ||
``` | ||
|
||
* Run the following to log in to your Ably account and set the default app and API key: | ||
|
||
```[sh] | ||
ably login | ||
|
||
ably apps switch | ||
ably auth keys switch | ||
``` | ||
|
||
* Install "Xcode":https://developer.apple.com/xcode/ | ||
|
||
* Install the Ably SDK in your Swift project using Swift Package Manager: | ||
|
||
```[swift] | ||
dependencies: [ | ||
.package(url: "https://github.com/ably/ably-cocoa", from: "1.2.20") | ||
] | ||
``` | ||
|
||
|
||
<aside data-type='note'> | ||
<p>The code examples in this guide include a demo API key. If you wish to interact with the Ably CLI and view outputs within your Ably account, ensure that you replace them with your own API key.</p> | ||
<p><strong>Important:</strong> API keys are suitable for development and demo purposes only. For production apps, <a href="/docs/authentication/token-authentication">use token authentication</a> to keep your credentials secure.</p> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe separate these :) |
||
</aside> | ||
|
||
h2(#xcode-setup). Running this example in Xcode (SwiftUI) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Make this h3 |
||
|
||
To follow this guide in Xcode, use a new iOS project with the SwiftUI App template. All code can be added directly to your @ContentView.swift@ file, inside the @ContentView@ struct. Use the @.onAppear@ modifier to run the Ably code when the view appears. No additional files or setup are needed. | ||
|
||
*Steps:* | ||
|
||
# Open Xcode and create a new iOS project (App template, Swift, SwiftUI). | ||
# Open @ContentView.swift@. | ||
# Add the code snippets from each step inside the @.onAppear@ block in the @ContentView@ struct. | ||
# Run the app using the Simulator or a real device. | ||
# All @print@ output will appear in Xcode's debug console (View > Debug Area > Activate Console, or press Cmd+Shift+C). | ||
|
||
h2(#step-1). Step 1: Connect to Ably | ||
|
||
Clients establish a connection with Ably when they instantiate an SDK. This enables them to send and receive messages in realtime across channels. | ||
|
||
* Open up the "dev console":https://ably.com/accounts/any/apps/any/console of your first app before instantiating your client so that you can see what happens. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe just a re-jig with the way we are using bullets |
||
|
||
* Add these imports to the top of your Swift file: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Which Swift file, @ContentView.swift@? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add "the following" imports to the top of your Swift file: |
||
|
||
```[swift] | ||
import Ably | ||
``` | ||
|
||
* Create an instance of @ARTRealtime@ with your API key. This is the main entry point for the realtime library. The @ARTRealtime@ client connects to Ably as soon as it's instantiated, using a basic transport such as a raw TCP socket or a WebSocket: | ||
|
||
```[swift] | ||
let realtime = ARTRealtime(key: "{{API_KEY}}") | ||
``` | ||
|
||
* You can monitor the connection state by adding a listener to the connection property: | ||
|
||
```[swift] | ||
realtime.connection.on { stateChange in | ||
print("Connection state changed to: \(stateChange.current)") | ||
|
||
if stateChange.current == .connected { | ||
print("Made my first connection!") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On one hand, I think we shouldn't overcomplicate things; on the other hand, printing to the console in a SwiftUI project feels a bit out of place. Maybe we can create simple in-app console (just render list of lines in a text box)? Or maybe create console desktop swift app instead of swift ui? |
||
} | ||
} | ||
``` | ||
|
||
You can also specify a client ID, which is a caller-defined string that identifies this client: | ||
|
||
```[swift] | ||
let clientOptions = ARTClientOptions(key: "{{API_KEY}}") | ||
clientOptions.clientId = "my-first-client" | ||
let realtime = ARTRealtime(options: clientOptions) | ||
``` | ||
|
||
A client can establish a connection using "token authentication":/docs/authentication/token-authentication rather than "basic authentication":/docs/authentication/basic-authentication. To do so, specify a token instead of a key: | ||
|
||
```[swift] | ||
let realtime = ARTRealtime(token: "{{TOKEN}}") | ||
``` | ||
|
||
*To run:* | ||
- Build and run the app in Xcode (Cmd+R). | ||
- Watch the Xcode debug console for connection state changes and messages. | ||
|
||
h2(#step-2). Step 2: Subscribe to a channel and publish a message | ||
|
||
Messages contain the data that a client is communicating, such as a short 'hello' from a colleague, or a financial update being broadcast to subscribers from a server. Ably uses channels to separate messages into different topics, so that clients only ever receive messages on the channels they are subscribed to. | ||
|
||
* Use the @channels@ property of your realtime client to get a reference to a channel instance: | ||
|
||
```[swift] | ||
let channel = realtime.channels.get("my-first-channel") | ||
``` | ||
|
||
* Subscribe to messages on the channel. When a client publishes a message to the channel, the handler function you passed into @subscribe@ will be called with that message: | ||
|
||
```[swift] | ||
channel.subscribe { message in | ||
print("Received message: \(message.data ?? "no data")") | ||
} | ||
``` | ||
|
||
* Use the Ably CLI to publish a message to your channel. The message will be received by the client you've subscribed to the channel, and be logged to the console: | ||
|
||
```[sh] | ||
ably channels publish my-first-channel 'Hello!' | ||
``` | ||
|
||
* In a new terminal tab, subscribe to the same channel using the CLI: | ||
|
||
```[sh] | ||
ably channels subscribe my-first-channel | ||
``` | ||
|
||
* Now you can publish a message from your Swift code to the channel: | ||
|
||
```[swift] | ||
channel.publish("greeting", data: "Hello from Swift!") { error in | ||
guard error == nil else { | ||
print("Error publishing message: \(error!.message)") | ||
return | ||
} | ||
print("Message successfully published") | ||
} | ||
``` | ||
|
||
When you publish this message, it will be received by both your Swift client and the CLI subscription. | ||
|
||
*To run:* | ||
- Build and run the app again. | ||
- Use the Ably CLI as described to publish/subscribe and see output in the Xcode debug console. | ||
|
||
h2(#step-3). Step 3: Join the presence set | ||
|
||
Presence enables clients to be aware of one another if they are present on the same channel. You can then show clients who else is online, provide a custom status update for each, and notify the channel when someone goes offline. | ||
|
||
* Add the following code to subscribe to presence events, which lets you know when clients enter, update, and leave the presence set for this channel: | ||
|
||
```[swift] | ||
channel.presence.subscribe { presenceMessage in | ||
print("Presence event: \(presenceMessage.action) - Client: \(presenceMessage.clientId ?? "no client id") - \(presenceMessage.data ?? "no data")") | ||
} | ||
``` | ||
|
||
* Enter the presence set for the channel: | ||
|
||
```[swift] | ||
channel.presence.enter("I'm here!") { error in | ||
guard error == nil else { | ||
print("Error entering presence set: \(error!.message)") | ||
return | ||
} | ||
print("Successfully entered presence set") | ||
} | ||
``` | ||
|
||
* In the "dev console":https://ably.com/accounts/any/apps/any/console of your first app, attach to @my-first-channel@. Enter a @clientId@, such as @my-dev-console@, and then join the presence set of the channel. You'll see that @my-first-client@ is already present in the channel. | ||
|
||
* You can have another client join the presence set using the Ably CLI: | ||
|
||
```[sh] | ||
ably channels presence enter my-first-channel --client-id "my-cli" --data '{"status":"learning about Ably!"}' | ||
``` | ||
|
||
*To run:* | ||
- Build and run the app. | ||
- Use the Ably CLI or dev console to join presence and see events in the Xcode debug console. | ||
|
||
h2(#step-4). Step 4: Retrieve message history | ||
|
||
You can retrieve previously sent messages using the history feature. Ably stores all messages for 2 minutes by default in the event a client experiences network connectivity issues. This can be extended for longer if required. | ||
|
||
If more than 2 minutes has passed since you published a regular message (excluding the presence events), then you can publish some more before trying out history. You can use the Ably CLI to do this. | ||
|
||
For example, using the Ably CLI to publish 5 messages: | ||
|
||
```[sh] | ||
ably channels publish --count 5 my-first-channel "Message number {{.Count}}" | ||
``` | ||
|
||
* Add the following code to retrieve any messages that were recently published to the channel: | ||
|
||
```[swift] | ||
let query = ARTRealtimeHistoryQuery() | ||
query.limit = 25 // Maximum number of messages to retrieve | ||
|
||
try channel.history(query) { paginatedResult, error in | ||
guard error == nil else { | ||
print("Error retrieving message history: \(error!.message)") | ||
return | ||
} | ||
|
||
guard let paginatedResult = paginatedResult else { | ||
print("No results received") | ||
return | ||
} | ||
|
||
print("Retrieved \(paginatedResult.items.count) messages from history") | ||
for message in paginatedResult.items { | ||
print("Message: \(message.data ?? "no data")") | ||
} | ||
} | ||
``` | ||
|
||
The output will look similar to the following: | ||
|
||
```[json] | ||
[ | ||
"Message number 5", | ||
"Message number 4", | ||
"Message number 3", | ||
"Message number 2", | ||
"Message number 1" | ||
] | ||
``` | ||
|
||
*To run:* | ||
- Build and run the app. | ||
- Use the Ably CLI to publish messages if needed, then check the Xcode debug console for history output. | ||
|
||
h2(#step-5). Step 5: Close the connection | ||
|
||
Connections are automatically closed approximately 2 minutes after no heartbeat is detected by Ably. Explicitly closing connections when they are no longer needed is good practice to help save costs. It will also remove all listeners that were registered by the client. | ||
|
||
Note that messages are streamed to clients as soon as they attach to a channel, as long as they have the necessary capabilities. Clients are implicitly attached to a channel when they call @subscribe()@. Detaching from a channel using the @detach()@ method will stop the client from being streamed messages by Ably. | ||
|
||
Listeners registered when subscribing to a channel are registered client-side. Unsubscribing by calling @unsubscribe()@ will remove previously registered listeners for that channel. Detaching from a channel has no impact on listeners. As such, if a client reattaches to a channel that they previously registered listeners for, then those listeners will continue to function upon reattachment. | ||
|
||
* Close the connection using the @close@ method: | ||
|
||
```[swift] | ||
// Simulate a delay before closing the connection | ||
DispatchQueue.main.asyncAfter(deadline: .now() + 10.0) { | ||
realtime.close() | ||
print("Connection closed") | ||
} | ||
``` | ||
|
||
*To run:* | ||
- Build and run the app. | ||
- After 10 seconds, the connection will close and a message will appear in the Xcode debug console. | ||
|
||
h2(#next). Next steps | ||
|
||
Continue to explore the documentation with Swift as the selected language: | ||
|
||
Read more about the concepts covered in this guide: | ||
|
||
* Revisit the basics of "Pub/Sub":/docs/pub-sub | ||
* Explore more "advanced":/docs/pub-sub/advanced Pub/Sub concepts | ||
* Understand realtime "connections":/docs/connect to Ably | ||
* Read more about how to use "presence":/docs/presence-occupancy/presence in your apps | ||
* Fetch message "history":/docs/storage-history/history in your apps | ||
|
||
You can also explore the Ably CLI further, or visit the Pub/Sub "API references":/docs/api/realtime-sdk. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add a step to create a new Swift project before installing the Ably SDK?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed