Skip to content

Commit 63cf7cc

Browse files
maratalclaude
andcommitted
fix(push-guides): restructure APNs, FCM, and web push guides to match react-native/flutter layout
- Add Step 5 "Publish a push notification" with CLI-only publish (client-id + channel sub-steps) - Remove send-with-code examples from all three guides - Remove push-admin Aside (info already in prerequisites) - Align Step 3 opening text across all guides - Update "send push notifications" to "publish push notifications" throughout - Restore service worker description sentence in web guide - APNs Step 6 (location pushes) renumbered from Step 7 after removing send-with-code step Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 1cbbd2a commit 63cf7cc

5 files changed

Lines changed: 217 additions & 702 deletions

File tree

src/pages/docs/push/getting-started/apns.mdx

Lines changed: 43 additions & 233 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ meta_keywords: "Push Notifications Swift, Ably Push, APNs, iOS Push, Swift push
66

77
This guide will get you started with Ably Push Notifications in a new SwiftUI application.
88

9-
You'll learn how to set up your `AppDelegate` to manage push notifications, register devices with Ably, send push notifications, subscribe to channel-based push, handle incoming notifications, and implement location-based push notifications.
9+
You'll learn how to set up your `AppDelegate` to manage push notifications, register devices with Ably, publish push notifications, subscribe to channel-based push, handle incoming notifications, and implement location-based push notifications.
1010

1111
<Aside data-type='note'>
1212
Using an AI coding assistant? [Teach it Ably](/docs/platform/ai-llms#agent-skills) with Agent Skills for all popular AI coding agents. Run `claude plugin add ably/agent-skills` or `npx skills add ably/agent-skills` to get started.
@@ -16,16 +16,16 @@ Using an AI coding assistant? [Teach it Ably](/docs/platform/ai-llms#agent-skill
1616

1717
1. [Sign up](https://ably.com/signup) for an Ably account.
1818
2. Create a [new app](https://ably.com/accounts/any/apps/new), and create your first API key in the **API Keys** tab of the dashboard.
19-
3. Your API key will need the `publish` and `subscribe` capabilities. For sending push notifications from your app, you'll also need the `push-admin` capability.
20-
4. For channel-based push, add a rule for the channel with **Push notifications enabled** checked. In the dashboard left sidebar: **Configuration****Rules****Add** or **Edit** a rule,
21-
then enable the Push notifications option. See [rules](/docs/channels#rules) for details.
22-
5. Install [Xcode](https://developer.apple.com/xcode/).
23-
6. You'll need a real iOS device to test push notifications (the simulator doesn't support APNs).
24-
7. Set up Apple Push Notification service (APNs) certificates through the [Apple Developer Portal](https://developer.apple.com/).
19+
* Your API key needs the `publish` and `subscribe` capabilities.
20+
* Also add the `push-admin` capability if you're using the same API key to publish a push notification. In production this would more likely be a server using a different API key.
21+
3. Add a rule to a channel so you can test sending push notifications via a channel. Select [**Rules**](https://ably.com/accounts/any/apps/any/app_namespaces) in the Ably dashboard, add a new rule and enable the **Push notifications** option.
22+
4. Install [Xcode](https://developer.apple.com/xcode/).
23+
5. You'll need a real iOS device to test push notifications (the simulator doesn't support APNs).
24+
6. Set up Apple Push Notification service (APNs) certificates through the [Apple Developer Portal](https://developer.apple.com/).
2525

2626
### (Optional) Install Ably CLI <a id="install-cli"/>
2727

28-
Use the [Ably CLI](https://github.com/ably/cli) as an additional client to quickly test Pub/Sub features and push notifications.
28+
Use the [Ably CLI](/docs/platform/tools/cli) as an additional client to quickly test Pub/Sub features and push notifications.
2929

3030
1. Install the Ably CLI:
3131

@@ -205,7 +205,7 @@ func didDeactivateAblyPush(_ error: ARTErrorInfo?) {
205205

206206
Now you are ready to receive push notifications.
207207

208-
## Step 3: Receive push notifications <a id="step-3"/>
208+
### Handle push notifications <a id="step-2-handle"/>
209209

210210
Use `UNUserNotificationCenterDelegate` methods to receive push notifications.
211211
You've set the notification center delegate in the `application:didFinishLaunchingWithOptions` method.
@@ -239,8 +239,9 @@ func userNotificationCenter(_ center: UNUserNotificationCenter,
239239
```
240240
</Code>
241241

242-
Push notifications can be sent either directly to your `deviceId` (or `clientId`),
243-
or posted to a channel, in which case you first need to subscribe your device to that channel:
242+
## Step 3: Subscribe to channel push notifications <a id="step-3"/>
243+
244+
To subscribe your device to a channel so it can receive channel-based push notifications, add the following methods to your `AppDelegate` class:
244245

245246
<Code>
246247
```swift
@@ -274,23 +275,6 @@ func unsubscribeFromChannel(_ channelName: String) {
274275
```
275276
</Code>
276277

277-
Sending push notifications using `deviceId` or `clientId` requires the `push-admin` capability for your API key. Use this method for testing purposes. In a production environment, you would typically send push notifications from your backend server (by posting messages with `push` `extras` field to a channel).
278-
279-
To test push notifications in your app, you can use [Ably dashboard](https://ably.com/dashboard), [Apple developer dashboard](https://icloud.developer.apple.com/dashboard/) or [Ably CLI](/docs/platform/tools/cli).
280-
281-
To publish to your client ID using the [Ably CLI](/docs/platform/tools/cli) paste the following command into your terminal:
282-
283-
<Code>
284-
```shell
285-
ably push publish --client-id push-tutorial-client \
286-
--title "Test push" \
287-
--body "Hello from CLI!" \
288-
--data '{"foo":"bar","baz":"qux"}'
289-
```
290-
</Code>
291-
292-
For sending pushes via a channel, we need some actual UI to be able to subscribe to this channel. So, let's build one.
293-
294278
## Step 4: Build the UI <a id="step-4"/>
295279

296280
First, in your `PushTutorialApp.swift`, add `@UIApplicationDelegateAdaptor` wrapped `appDelegate` property
@@ -324,7 +308,7 @@ struct ContentView: View {
324308
let appDelegate: AppDelegate
325309

326310
@State private var statusMessage = "Ready to start"
327-
@State private var selectedChannel = "exampleChannel1"
311+
@State private var selectedChannel = "my-first-push-channel"
328312

329313
var body: some View {
330314
NavigationStack {
@@ -468,8 +452,8 @@ struct SetupPushSection: View {
468452
// Helper to get a user-friendly title for a channel
469453
func titleForChannel(_ name: String) -> String {
470454
let titles = [
471-
"exampleChannel1": "Channel 1",
472-
"exampleChannel2": "Channel 2"
455+
"my-first-push-channel": "Channel 1",
456+
"my-first-push-channel-2": "Channel 2"
473457
]
474458
return titles[name] ?? name
475459
}
@@ -487,11 +471,11 @@ struct ChannelSection: View {
487471
VStack(spacing: 10) {
488472
HStack(spacing: 8) {
489473
Menu {
490-
Button(titleForChannel("exampleChannel1")) {
491-
selectedChannel = "exampleChannel1"
474+
Button(titleForChannel("my-first-push-channel")) {
475+
selectedChannel = "my-first-push-channel"
492476
}
493-
Button(titleForChannel("exampleChannel2")) {
494-
selectedChannel = "exampleChannel2"
477+
Button(titleForChannel("my-first-push-channel-2")) {
478+
selectedChannel = "my-first-push-channel-2"
495479
}
496480
} label: {
497481
HStack {
@@ -546,217 +530,43 @@ struct ChannelSection: View {
546530
</Code>
547531

548532
Build and run your app in Xcode on a real device. You will see the UI with sections to activate
549-
push notifications and subscribe to channels. Tap the "Activate Push" button and wait until the status message
550-
displays the received device token. Try sending push using client ID or device ID as shown earlier.
551-
You can get your device ID from the device details button (don't confuse it with the device token):
552-
553-
![Screenshot of the Swift push tutorial application](../../../../images/content/screenshots/getting-started/apns-swift-getting-started-guide.png)
533+
push notifications and subscribe to channels.
554534

555-
### Send push via channel <a id="step-4-send-channel"/>
556-
557-
To test pushes via channel, subscribe to "Channel 1" in the UI and publish a push notification to the channel using the [Ably CLI](/docs/platform/tools/cli):
558-
559-
<Code>
560-
```shell
561-
ably push publish --channel exampleChannel1 \
562-
--title "Hello" \
563-
--body "World!" \
564-
--message '{"name":"greeting","data":"Hello World!"}'
565-
```
566-
</Code>
567-
568-
If you unsubscribe from this channel in the app's UI, you will no longer receive push notifications for that channel.
569-
Send the same command again and verify that no notification is received.
570-
571-
You can also send push notifications right from your app. The next step will show you how.
572-
573-
## Step 5: Send push with code <a id="step-5"/>
574-
575-
Just as you can send push notifications through the Ably CLI or dashboard, you can also send them directly from your app
576-
using `deviceId` (or `clientId`), or channel publishing methods. For channel publishing, you don't need the admin capabilities
577-
for your API key.
578-
579-
Add the following methods to your `AppDelegate` class:
580-
581-
<Code>
582-
```swift
583-
// MARK: - Send Push Notifications
535+
## Step 5: Publish a push notification <a id="step-5"/>
584536

585-
/// Send push notification to a specific device ID
586-
func sendPushToDevice() {
587-
let recipient = [
588-
"deviceId": realtime.device.id
589-
]
590-
let data = [
591-
"notification": [
592-
"title": "Push Tutorial",
593-
"body": "Hello from device ID!"
594-
],
595-
"data": [
596-
"foo": "bar",
597-
"baz": "qux"
598-
]
599-
]
600-
realtime.push.admin.publish(recipient, data: data) { error in
601-
print("Publish result: \(error?.localizedDescription ?? "Success")")
602-
}
603-
}
537+
Tap **Activate Push** and wait until the status message displays the received device token. You can get your device ID from the **Get Device Details** button (don't confuse it with the device token).
604538

605-
/// Send push notification to a specific client ID
606-
func sendPushToClient() {
607-
let recipient = [
608-
"clientId": realtime.auth.clientId ?? "push-tutorial-client"
609-
]
610-
let data = [
611-
"notification": [
612-
"title": "Push Tutorial",
613-
"body": "Hello from client ID!"
614-
],
615-
"data": [
616-
"foo": "bar",
617-
"baz": "qux"
618-
]
619-
]
620-
realtime.push.admin.publish(recipient, data: data) { error in
621-
print("Publish result: \(error?.localizedDescription ?? "Success")")
622-
}
623-
}
624-
```
625-
</Code>
539+
### Publish directly to your device <a id="step-5-direct"/>
626540

627-
Sending to a channel is just publishing a message on a channel with a `push` `extras` field:
541+
Publish a push notification directly to your client ID (or device ID using `--device-id` instead of `--client-id`) via the [Ably CLI](/docs/platform/tools/cli):
628542

629-
<Code>
630-
```swift
631-
/// Send push notification to a specific channel by publishing a message with a push extras field
632-
func sendPushToChannel(_ channelName: String) {
633-
let message = ARTMessage(name: "example", data: "Hello from channel!")
634-
message.extras = [
635-
"push": [
636-
"notification": [
637-
"title": "Channel Push",
638-
"body": "Sent push to \(channelName)"
639-
],
640-
"data": [
641-
"foo": "bar",
642-
"baz": "qux"
643-
]
644-
]
645-
] as any ARTJsonCompatible
646-
647-
realtime.channels.get(channelName).publish([message]) { error in
648-
if let error {
649-
print("Error sending push to \(channelName) with error: \(error.localizedDescription)")
650-
} else {
651-
print("Sent push to \(channelName)")
652-
}
653-
}
654-
}
543+
<Code fixed="true">
544+
```shell
545+
ably push publish --client-id push-tutorial-client \
546+
--title "Test push" \
547+
--body "Hello from CLI!" \
548+
--data '{"foo":"bar","baz":"qux"}'
655549
```
656550
</Code>
657551

658-
Now add buttons for these methods in the new `SendPushSection` view struct:
659-
660-
<Code>
661-
```swift
662-
// MARK: - Send Push Section
663-
664-
struct SendPushSection: View {
665-
let appDelegate: AppDelegate
666-
@Binding var statusMessage: String
667-
@Binding var selectedChannel: String
668-
669-
var body: some View {
670-
VStack(alignment: .leading, spacing: 12) {
671-
Text("Send Push Notifications")
672-
.font(.headline)
673-
674-
VStack(spacing: 10) {
675-
Button(action: {
676-
appDelegate.sendPushToDevice()
677-
statusMessage = "Sending push to device ID..."
678-
}) {
679-
HStack {
680-
Image(systemName: "phone.badge.checkmark")
681-
Text("Send Push to Device ID")
682-
}
683-
.frame(maxWidth: .infinity)
684-
.padding()
685-
.background(Color.purple)
686-
.foregroundStyle(.white)
687-
.cornerRadius(8)
688-
}
689-
690-
Button(action: {
691-
appDelegate.sendPushToClient()
692-
statusMessage = "Sending push to client ID..."
693-
}) {
694-
HStack {
695-
Image(systemName: "person.crop.circle.badge.checkmark")
696-
Text("Send Push to Client ID")
697-
}
698-
.frame(maxWidth: .infinity)
699-
.padding()
700-
.background(Color.orange)
701-
.foregroundStyle(.white)
702-
.cornerRadius(8)
703-
}
552+
### Publish via a channel <a id="step-5-channel"/>
704553

705-
HStack(spacing: 8) {
706-
Menu {
707-
Button(titleForChannel("exampleChannel1")) {
708-
selectedChannel = "exampleChannel1"
709-
}
710-
Button(titleForChannel("exampleChannel2")) {
711-
selectedChannel = "exampleChannel2"
712-
}
713-
} label: {
714-
HStack {
715-
Image(systemName: "line.3.horizontal.decrease.circle")
716-
Text(titleForChannel(selectedChannel))
717-
}
718-
.frame(maxWidth: .infinity)
719-
.padding()
720-
.background(Color.gray.opacity(0.2))
721-
.cornerRadius(8)
722-
}
554+
Subscribe to "Channel 1" in the UI, then publish a push notification to the channel using the [Ably CLI](/docs/platform/tools/cli):
723555

724-
Button(action: {
725-
appDelegate.sendPushToChannel(selectedChannel)
726-
statusMessage = "Sending push to channel: \(selectedChannel)..."
727-
}) {
728-
HStack {
729-
Image(systemName: "checkmark.circle.fill")
730-
Text("Send")
731-
}
732-
.frame(maxWidth: .infinity)
733-
.padding()
734-
.background(Color.cyan)
735-
.foregroundStyle(.white)
736-
.cornerRadius(8)
737-
}
738-
}
739-
}
740-
}
741-
.padding()
742-
.background(Color.white)
743-
.cornerRadius(12)
744-
.shadow(radius: 2)
745-
}
746-
}
556+
<Code fixed="true">
557+
```shell
558+
ably push publish --channel my-first-push-channel \
559+
--title "Hello" \
560+
--body "World!" \
561+
--message '{"name":"greeting","data":"Hello World!"}'
747562
```
748563
</Code>
749564

750-
Update your `ContentView` body to include this section (add it just after the `ChannelSection`):
565+
![Screenshot of the Swift push tutorial application](../../../../images/content/screenshots/getting-started/apns-swift-getting-started-guide.png)
751566

752-
<Code>
753-
```swift
754-
// Send Push Section
755-
SendPushSection(appDelegate: appDelegate, statusMessage: $statusMessage, selectedChannel: $selectedChannel)
756-
```
757-
</Code>
567+
If you unsubscribe from this channel in the app's UI, you will no longer receive push notifications for that channel. Run the same command again and verify that no notification is received.
758568

759-
Build and run your app again. Use the added section to send push notifications.
569+
To see the full list of options for publishing push notifications with the Ably CLI, run `ably push publish --help` or see the [Ably CLI push documentation](/docs/cli/push). To publish push notifications from your own server code instead of the CLI, see [Push notification publishing](https://ably.com/docs/push/publish).
760570

761571
## Step 6: Location pushes <a id="step-6"/>
762572

@@ -769,7 +579,7 @@ Add `Location (when in use)`, `Location (Always)`, `Location Push Service Extens
769579
Add `Location Push Service Extension` target as described at the [Apple Developer Portal](https://developer.apple.com/documentation/CoreLocation/creating-a-location-push-service-extension).
770580
For simplicity, use **Automatically manage signing**, so all needed identifiers are created for you by
771581
Xcode (with XC prefix in their display name). Your Location Push Service Extension should have a bundle
772-
identifier of your app with a suffix of extension's product name (e.g., `the.company.TheApp.TheExtension`).
582+
identifier of your app with a suffix of extension's product name (for example, `the.company.TheApp.TheExtension`).
773583

774584
Add these methods to your `AppDelegate` class:
775585

@@ -861,7 +671,7 @@ func didUpdateAblyPush(_ error: ARTErrorInfo?) {
861671
```
862672
</Code>
863673

864-
### Receiving location pushes <a id="step-5-receiving"/>
674+
### Receive location pushes <a id="step-6-receiving"/>
865675

866676
Once you've added the location push extension to your project, Xcode gives you a default implementation of the
867677
`LocationPushService.swift` file in your extension target.

0 commit comments

Comments
 (0)