---
source_url: https://www.pubnub.com/docs/general/push/ios
title: iOS Mobile Push Notifications
updated_at: 2026-06-04T11:10:25.878Z
---

> Documentation Index
> For a curated overview of PubNub documentation, see: https://www.pubnub.com/docs/llms.txt
> For the full list of all documentation pages, see: https://www.pubnub.com/docs/llms-full.txt


# iOS Mobile Push Notifications

:::note HTTP/2-based APNs
This APNs tutorial uses the HTTP/2-based Apple Push Notification service (APNs), not the legacy APNs binary interface, to send notifications.
:::

PubNub Mobile Push Notifications bridges native message publishing with third-party push services, including Apple Push Notification service (APNs) and Firebase Cloud Messaging (FCM). This tutorial shows how to register for remote notifications, receive the device token, and add the device token to a PubNub channel.

Push notifications are channel‑specific. A user receives pushes for channels where push is enabled. In‑app messages still require a channel subscription.

## Step 1: Configure account settings

Follow these steps to configure APNs Mobile Push Notifications for your app.

### Step 1a: Create an APNs authentication token

Log in to your [Apple Developer account](https://developer.apple.com/account/resources/authkeys/list).

![Apple Developer account](https://www.pubnub.com/assets/images/apple_dev_main_nav-349d4ca329731c12df012eae2d435ead.png)

Go to **Certificates, IDs & Profiles**, and select **Keys**.

![Certificates, IDs &amp; Profiles](https://www.pubnub.com/assets/images/apple_dev_cert_nav-bba19238896a4022046cf9a63cf6e21e.png)

Create and obtain a valid APNs Authentication Token (`.p8` file extension).

![Register a New Key](https://www.pubnub.com/assets/images/apple_dev_register_key-28ea48dee1377177d87378f176c131d8.png)

After downloading, the Auth Key filename will look like this *AuthKeyABCD1234.p8*, the *ABCD1234* is the Key ID for this key, we will need this Key ID later. You can also find the Auth Key ID by selecting your push token from your list of available [Apple Developer Account Keys](https://developer.apple.com/account/resources/authkeys/list).

![View Key Details](https://www.pubnub.com/assets/images/apple_dev_key_details-0cabdbd57c580e23853bbf679c2aa389.png)

### Step 1b: Configure mobile push notifications in the Admin Portal

In the [Admin Portal](https://admin.pubnub.com), open your app’s keyset.

![Upload token](https://www.pubnub.com/assets/images/admin_portal_upload_token1-744079fa10822e6bacc52c56dd989de1.png)

Enable **Mobile Push Notifications** and provide values for the [Team ID](https://developer.apple.com/help/account/manage-your-team/locate-your-team-id/) and **Auth Key ID** (Apple's [key identifier](https://developer.apple.com/help/account/manage-keys/get-a-key-identifier/)) fields.

Then, upload your APNs Authentication Token through the **Token File** option.

## Step 2: Request device token

Enable the [Mobile Push Notifications](https://help.apple.com/xcode/mac/current/#/devdfd3d04a1) capability in your Xcode project.

![Upload token](https://www.pubnub.com/assets/images/xcode_project_capabilities_after-f3d489dcdefc5bb31a837382c7eb8587.png)

For this example, place the code in the [AppDelegate](https://developer.apple.com/documentation/uikit/uiapplicationdelegate). Any globally accessible object works for non‑system logic.

Import PubNub into your project:

### Swift

```swift
import UserNotifications
import PubNubSDK
```

### Objective-C

```objectivec
#import <UserNotifications/UserNotifications.h>
#import <PubNub/PubNub.h>
```

When the app launches, or any time it makes sense, use `UNUserNotificationCenter` to request [notification permissions](https://developer.apple.com/documentation/usernotifications/asking_permission_to_use_notifications).

Inside the completion block, request the device token for your app.

#### Swift

For more information regarding requesting tokens, go to [Apple Docs](https://developer.apple.com/documentation/usernotifications/unusernotificationcenter).

```swift
func application(
  _ application: UIApplication,
  didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil
) -> Bool {

  UNUserNotificationCenter.current().delegate = self

  UNUserNotificationCenter.current().requestAuthorization(options: [.badge, .alert, .sound]) { (granted, err) in
    DispatchQueue.main.async() {
      UIApplication.shared.registerForRemoteNotifications()
    }
  }

  return true
}
```

#### Objective-C

For more information regarding requesting tokens, go to [Apple Docs](https://developer.apple.com/documentation/usernotifications/unusernotificationcenter?language=objc).

```objectivec
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

  [self registerCustomDispatchQueues];

  UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];

  center.delegate = self;

  [center requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge)
                        completionHandler:^(BOOL granted, NSError * _Nullable error) {
    dispatch_async(dispatch_get_main_queue(), ^{
      [[UIApplication sharedApplication] registerForRemoteNotifications];
    });
  }];

  return YES;
}
```

Refer to the [Apple Developer documentation](https://developer.apple.com/documentation/usernotifications/registering_your_app_with_apns) for more information on how to register your app and obtain an APNs Authentication Token.

## Step 3: Receive & monitor device token

Calling [registerForRemoteNotifications()](https://developer.apple.com/documentation/uikit/uiapplication/1623078-registerforremotenotifications) initiates registration with Apple Push Notification service (APNs).

The system provides a token via `UIApplicationDelegate` by calling the following method. After initial registration, APNs may deliver new (sometimes duplicate) tokens. Update your PubNub channel registrations when the token changes.

### Swift

For more information on receiving token, go to [Apple Docs](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622958-application).

```swift
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
  let oldDeviceToken = self.cachedToken
  guard deviceToken != oldDeviceToken else { return }
  self.cachedToken = deviceToken

  updateAPNSDevicesOnChannels(
    pushChannels.allObjects, newDevice: deviceToken, oldDevice: oldDeviceToken,
    on: "com.mycompany.mybundleid",  environment: .production
  ) { result in
    switch result {
    case .success: print("Successfully updated channels with new token")
    case let .failure(error): print("Failed to update device token due to: \(error)")
    }
  }
}
```

### Objective-C

For more information on receiving token, go to [Apple Docs](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622958-application?language=objc).

```objectivec
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
  NSData *oldDevice = self.cachedToken;
  if ([deviceToken isEqualToData:oldDevice]) { return; }
  self.cachedToken = deviceToken;

  [self updateAPNSDevicesOnChannels:[self.pushChannels allObjects]
                withDevicePushToken:deviceToken
           replacingDevicePushToken:oldDevice
                           pushType:PNAPNS2Push
                        environment:PNAPNSProduction
                              topic:@"com.mycompany.mybundleid"
                      andCompletion:^(PNAcknowledgmentStatus * _Nonnull status) {
    if (!status.isError) {
      NSLog(@"Successfully updated channels with new token");
    } else {
      NSLog(@"Failed to update device token due to: %@", status);
    }
  }];
}
```

### Step 3a: Cache device token & registered channels

To ensure that an application can properly handle adding, updating, and removing registered push channels there are two pieces of information that should be cached to avoid race conditions: the Device Token and the list of registered channels. Not only will properly caching allow for easy access from anywhere inside the application, but it will also prevent race conditions when multiple registration operations are queued at the same time.

`UserDefaults` provides basic persistent storage; you can replace it with more advanced storage as needed. The following code makes access to cached information thread‑safe.

The system can provide a new device token at any time. Store the token whenever you receive it.

#### Swift

```swift
let tokenDispatch = DispatchQueue(label: "com.pubnub.deviceToken", attributes: .concurrent)
var cachedToken: Data? {
  get {
    var token: Data?
    tokenDispatch.sync {
      token = UserDefaults.standard.data(forKey: "com.pubnub.deviceToken")
    }
    return token
  }
  set {
    tokenDispatch.async(flags: .barrier) {
      UserDefaults.standard.set(newValue, forKey: "com.pubnub.deviceToken")
    }
  }
}
```

#### Objective-C

```objectivec
static dispatch_queue_t deviceTokenDispatch;
static dispatch_queue_t pushChannelsDispatch;

static dispatch_once_t registerCustomDispatchOnceToken;
- (void) registerCustomDispatchQueues {
  dispatch_once(&registerCustomDispatchOnceToken, ^{
    deviceTokenDispatch = dispatch_queue_create("com.pubnub.deviceToken", DISPATCH_QUEUE_CONCURRENT);
    pushChannelsDispatch = dispatch_queue_create("com.pubnub.pushChannels", DISPATCH_QUEUE_CONCURRENT);
  });
}

- (nullable NSData *) cachedToken {
  __block NSData* token;
  dispatch_sync(tokenDispatch, ^{
    token = [[NSUserDefaults standardUserDefaults] dataForKey: @"com.pubnub.deviceToken"];
  });
  return token;
}
- (void) setCachedToken:(nullable NSData *) newValue {
  dispatch_barrier_async(tokenDispatch, ^{
    [[NSUserDefaults standardUserDefaults] setValue:newValue forKey:@"com.pubnub.deviceToken"];
  });
}
```

Cache the list of registered channels the same way as the device token. Update it whenever you add or remove channels. Using a [Set](https://developer.apple.com/documentation/swift/set) helps prevent duplicates.

##### Swift

```swift
let pushChannelDispatch = DispatchQueue(label: "com.pubnub.pushChannels", attributes: .concurrent)
var pushChannels: Set<String> {
  get {
    var channels: Set<String>?
    pushChannelDispatch.sync {
      channels = UserDefaults.standard.object(forKey: "com.pubnub.pushChannels") as? Set<String>
    }
    return channels ?? []
  }
  set {
    pushChannelDispatch.async(flags: .barrier) {
      UserDefaults.standard.set(newValue, forKey: "com.pubnub.pushChannels")
    }
  }
}
```

##### Objective-C

```objectivec
- (nullable NSSet<NSString*> *) pushChannels {
  __block NSSet<NSString*>* channels;
  dispatch_sync(pushChannelsDispatch, ^{
    channels = [[NSUserDefaults standardUserDefaults] objectForKey: @"com.pubnub.pushChannels"];
  });
  return channels;
}
- (void) setPushChannels:(nullable NSSet<NSString*> *) newValue {
  dispatch_barrier_async(pushChannelsDispatch, ^{
    [[NSUserDefaults standardUserDefaults] setValue:newValue forKey:@"com.pubnub.pushChannels"];
  });
}
```

### Step 3b: Update existing registrations

A simple helper method can be created to consolidate the remove-then-add functionality when updating your existing registered channels.

#### Swift

```swift
func updateAPNSDevicesOnChannels(_ channels: [String], newDevice: Data, oldDevice: Data?,
  on topic: String, environment: PubNub.PushEnvironment, completion: @escaping ((Result<[String], Error>) -> Void)
) {
  if let oldDevice = oldDevice {
    pubnub.removeAllAPNSPushDevice(for: oldDevice, on: topic, environment: environment) { result in
      switch result {
      case .success: print("Successfully removed device token")
      case let .failure(error): print("Failed to remove device token due to: \(error)")
      }
    }
  }
  pubnub.addAPNSDevicesOnChannels(
    channels, device: newDevice, on: topic, environment: environment, completion: completion
  )
}
```

#### Objective-C

```objectivec
- (void) updateAPNSDevicesOnChannels:(NSArray<NSString *> *)channels
                 withDevicePushToken:(nonnull NSData *)newDevice
            replacingDevicePushToken:(nullable NSData *)oldDevice
                            pushType:(PNPushType)pushType
                         environment:(PNAPNSEnvironment)environment
                               topic:(NSString *)topic
                       andCompletion:(PNPushNotificationsStateModificationCompletionBlock)completion {
    if (oldDevice == nil) {
      [self.client removeAllPushNotificationsFromDeviceWithPushToken:oldDevice
                                                            pushType:PNAPNS2Push
                                                         environment:PNAPNSProduction
                                                               topic:@"com.mycompany.mybundleid"
                                                       andCompletion:^(PNAcknowledgmentStatus *status) {
        if (!status.isError) {
          NSLog(@"Successfully removed device token");
        } else {
          NSLog(@"Failed to remove device token due to: %@", status);
        }
      }];
    }

  [self.client addPushNotificationsOnChannels:channels
                          withDevicePushToken:newDevice
                                     pushType:pushType
                                  environment:environment
                                        topic:topic
                                andCompletion:completion];
}
```

## Step 4: Manage device registrations

Once a Device Token is obtained, it can be registered with a list of channels to allow Mobile Push Notifications to be sent to the device. Channels can be dynamically added and removed based on the use cases of the application, and the current registrations for a Device Token can also be viewed.

### Step 4a: Register new channels

When you add channels, read the device token and registered channels from the [cache](#step-3a-cache-device-token--registered-channels). After registration, add the channels to the cached list.

#### Swift

```swift
if let deviceToken = (UIApplication.shared.delegate as? AppDelegate)?.cachedToken {
  pubnub.addAPNSDevicesOnChannels(
    ["ch1", "ch2"],
    device: deviceToken,
    on: "com.mycompany.mybundleid",
    environment: .production
  ) { result in
    switch result {
    case let .success(channelsAdded):
      channelsAdded.forEach { (UIApplication.shared.delegate as? AppDelegate)?.pushChannels.update(with: $0) }
    case let .failure(error): print("Failed to add Push due to: \(error.localizedDescription)")
    }
  }
}
```

#### Objective-C

```objectivec
NSData *deviceToken = [(AppDelegate *)[[UIApplication sharedApplication] delegate] cachedToken];
if (deviceToken == nil) { return; }

[self.client addPushNotificationsOnChannels:@[@"ch1",@"ch2"]
                        withDevicePushToken:deviceToken
                                   pushType:PNAPNS2Push
                                environment:PNAPNSProduction
                                      topic:@"com.mycompany.mybundleid"
                              andCompletion:^(PNAcknowledgmentStatus *status) {
  if (!status.isError) {
    NSSet* cachedChannels = [(AppDelegate *)[[UIApplication sharedApplication] delegate] pushChannels];
    [(AppDelegate *)[[UIApplication sharedApplication] delegate] setPushChannels:[cachedChannels setByAddingObjectsFromArray:@[@"ch1",@"ch2"]]];
  } else {  NSLog(@"Failed to add Push due to: %@", status); }
}];
```

### Step 4b: List registered channels

After you add registrations, confirm APNs registrations by listing all channels for the device. The server list is the source of truth. Update the [cached list](#step-3a-cache-device-token--registered-channels) to match the server.

#### Swift

```swift
guard let deviceToken = (UIApplication.shared.delegate as? AppDelegate)?.cachedToken else { return }

pubnub.listAPNSPushChannelRegistrations(
  for: deviceToken,
  on: "com.mycompany.mybundleid",
  environment: .production
) { result in
  switch result {
  case let .success(channelsRegistered):
    (UIApplication.shared.delegate as? AppDelegate)?.pushChannels = Set(channelsRegistered)
  case let .failure(error): print("Failed to add Push due to: \(error.localizedDescription)")
  }
}
```

#### Objective-C

```objectivec
NSData *deviceToken = [(AppDelegate *)[[UIApplication sharedApplication] delegate] cachedToken];
if (deviceToken == nil) { return; }

[self.client pushNotificationEnabledChannelsForDeviceWithPushToken:deviceToken
                         pushType:PNAPNS2Push
                      environment:PNAPNSDevelopment
                            topic:@"com.mycompany.mybundleid"
                    andCompletion:^(PNAPNSEnabledChannelsResult *result, PNErrorStatus *status) {
  if (!status.isError) {
    NSSet* registeredChannels = [NSSet setWithArray:result.data.channels];
    [(AppDelegate *)[[UIApplication sharedApplication] delegate] setPushChannels:registeredChannels];
  } else {
    NSLog(@"Failed to add Push due to: %@", status);
  }
}];
```

### Step 4c: Remove existing registrations

When you remove channels, read the device token and registered channels from the [cache](#step-3a-cache-device-token--registered-channels). After removal, also remove those channels from the cache.

#### Swift

```swift
if let deviceToken = (UIApplication.shared.delegate as? AppDelegate)?.cachedToken {
  pubnub.removeAPNSDevicesOnChannels(
    ["ch1", "ch2"],
    device: deviceToken,
    on: "com.mycompany.mybundleid",
    environment: .production
  ) { result in
    switch result {
    case let .success(channelsRemoved):
      channelsRemoved.forEach { (UIApplication.shared.delegate as? AppDelegate)?.pushChannels.remove($0) }
    case let .failure(error): print("Failed to add Push due to: \(error.localizedDescription)")
    }
  }
}
```

#### Objective-C

```objectivec
NSData *deviceToken = [(AppDelegate *)[[UIApplication sharedApplication] delegate] cachedToken];
if (deviceToken == nil) { return; }

[self.client removePushNotificationsFromChannels:@[@"ch1",@"ch2"]
                        withDevicePushToken:deviceToken
                                   pushType:PNAPNS2Push
                                environment:PNAPNSProduction
                                      topic:@"com.mycompany.mybundleid"
                              andCompletion:^(PNAcknowledgmentStatus *status) {
  if (!status.isError) {
    NSMutableSet* cachedChannels = [[(AppDelegate *)[[UIApplication sharedApplication] delegate] pushChannels] mutableCopy];
    for (NSString *channel in @[@"ch1",@"ch2"]) { [cachedChannels removeObject:channel]; }
    [(AppDelegate *)[[UIApplication sharedApplication] delegate] setPushChannels:cachedChannels];
  } else { NSLog(@"Failed to remove devices due to: %@", status); }
}];
```

## Step 5: Construct the push payload

On iOS, APNs is the push provider PubNub uses to relay Mobile Push Notifications to your app. To send a push, include the APNs payload when you publish. PubNub parses the message and forwards it to Apple.

The `pn_apns` payload is required for all APNs notifications. It tells PubNub that the payload should be forwarded to Apple.

`pn_apns` consists of:

* Two objects: [aps](#aps) and [pn_push](#pn_push)
* Two additional parameters: [pn_debug](#additional-parameters) and [pn_ttl](#additional-parameters)

```json
{
  "pn_apns": {
    "aps": {
        // necessary items
    },
    "pn_push": {
       // necessary items
    },
  "pn_debug": true,
  "pn_ttl": 60
  }
}
```

#### aps

The `aps` payload is entirely managed by Apple. It's a dictionary that contains the keys used by Apple to deliver the notification to the user's device. The keys specify the type of interactions that you want the system to use when alerting the user. Depending on your use case, providing content for this payload may be required. For example, if you decide to instruct the system to handle the notification in the background, you must add the `content-available` key, set it to `1`, and not include any visual or audio keys. Refer to the **Payload Key Reference** section in the [Apple Developer documentation](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification) for this and other examples.

#### pn_push

The `pn_push` object contains the configuration of the push message. PubNub uses this payload to set such values as request headers in APNs notifications sent to Apple. This payload is required for all APNs notifications.

| Key | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `push_type` | String | No | `alert` | A type of notification sent to Apple. Available values: `alert`, `background`, `voip`, `complication`, `fileprovider`, or `mdm`. The value you set for this key should always align with the payload values you set inside your `aps` payload. Refer to the `apns_push_type` header field in the [Apple Developer documentation](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns) for more information. |
| `auth_method` | String | No | `token` | Available values: `token`, `cert`, or `certificate` |
| `targets:environment` | String | No | `development` | An Apple environment for the certificate associated with the PubNub key-set in use. Available values: `development` or `production`. |
| `targets:topic` | String | Yes |  | A Bundle ID of your target application |
| `targets:excluded_devices` | [String] | No |  | A list of device tokens that should be excluded from receiving the notification. Typically, you can add your own device so you don't get a notification you publish. |
| `version` | String | Yes |  | Set to `v2`. |
| `pn_collapse_id` | String | No |  | An identifier to join multiple notifications into a single notification. |

#### Additional parameters

| Key | Type | Required | Description |
| --- | --- | --- | --- |
| `pn_debug` | boolean | No | A flag that enables publishing push debugging info to the `pndebug` channel. For more information, refer to [Mobile Push Troubleshooting](https://www.pubnub.com/docs/general/push/mobile-push-troubleshooting#debug-messages). |
| `pn_ttl` | int | No | A PubNub push property. It represents the number of seconds the notification is valid for from the time the notification is published to PubNub until the push server processes the publish. This flag only determines if PubNub forwards the notification to APNS, there is no consideration of a user device state. The default value for this parameter is 3600 seconds (1 hour). You don't have to set it if you provide [expirationDate](https://www.pubnub.com/docs/sdks/javascript/api-reference/mobile-push#push-notification-format-configuration) (used in an APNS POST request as the `apns-expiration` header value) in the push notification configuration. |

In the code sample below, the message includes a `pn_apns` payload to trigger APNs notifications on iOS devices:

##### JSON

For more information on generating notification, go to [Apple Docs](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification).

```json
{
   "text": "John invited you to chat",
   "pn_apns": {
      "aps": {
         "alert": {
            "title": "Chat Invitation",
            "body": "John invited you to chat"
         }
      },
      "pn_push":[
         {
            "push_type": "alert",
            "auth_method": "token",
            "targets":[
               {
                  "environment":"production",
                  "topic":"com.mycompany.mybundleid",
                  "excluded_devices": ["device-token1", "device-token2"]
               }
            ],
            "version":"v2"
         }
      ]
   }
}
```

##### Swift

```swift
let message = ["text": "John invited you to chat"]

let pushPayload = PubNubPushMessage(
  apns: PubNubAPNSPayload(
    aps: APSPayload(alert: .object(.init(title: "Chat Invitation", body: "John invited you to chat"))),
    pubnub: [.init(targets: [.init(topic: "com.mycompany.mybundleid", environment: .production)])],
  ),
  additional: message
)
```

##### Objective-C

```objectivec
NSDictionary *message = @{
  @"text": @"John invited you to chat"
};

PNNotificationsPayload *pushData = [PNNotificationsPayload
                                payloadsWithNotificationTitle:@"Chat Invitation"
                                body:@"John invited you to chat"];

// create the APNs target with topic and environment
PNAPNSNotificationTarget *target = [PNAPNSNotificationTarget
                                    targetForTopic:@"com.mycompany.mybundleid"
                                    inEnvironment:PNAPNSProduction
                                    withExcludedDevices:nil];

// create the APNs config object and add the target
PNAPNSNotificationConfiguration *apnsConfig =
          [PNAPNSNotificationConfiguration configurationWithTargets:@[target]];

// add the APNs config to the main pushData object
pushData.apns.configurations = @[apnsConfig];

// generate the final pushPayload object
NSDictionary *pushPayload = [pushData dictionaryRepresentationFor:PNAPNS2Push|PNFCMPush];
```

#### Metadata in message payloads

You can provide custom information to the app when it receives the notification by adding metadata to the message payload. For Apple Push Notification Service (APNs), include metadata as key-value pairs outside the `aps` dictionary in custom fields.

```json
{
  "aps": {
    "alert": {
      "title": "New Message",
      "body": "You have received a new message."
    }
  },
  "customData": {
    "chatId": "78910",
    "notificationType": "messageReceived"
  }
}
```

#### Prevent self-notifications

Exclude the sender’s device token so they don’t receive a push for their own message. Add the token(s) to `targets.excluded_devices` in the `pn_push` entry:

```json
{
  "pn_apns": {
    "aps": {
      "alert": {
        "title": "Chat Invitation",
        "body": "John invited you to chat"
      }
    },
    "pn_push": [
      {
        "push_type": "alert",
        "auth_method": "token",
        "targets": [
          {
            "environment": "production",
            "topic": "com.mycompany.mybundleid",
            "excluded_devices": [
              "<sender_device_token>",
              "<optional_other_device_token>"
            ]
          }
        ],
        "version": "v2"
      }
    ]
  }
}
```

## Step 6: Publish the push notification

Once the push payload is ready, use the `publish` method to publish the message on a channel. When PubNub finds the `pn_apns` and/or `pn_fcm` payloads, it will retrieve all device tokens that are associated with the push payload on the target channel and forward a push notification request to the appropriate push service for those associated devices.

### Swift

```swift
pubnub.publish(channel: "ch1", message: pushPayload) { result in
  switch result {
  case let .success(timetoken):
    print("Successfully published message at: \(timetoken)")
  case let .failure(error):
    print("Failed to publish due to: \(error)")
  }
}
```

### Objective-C

```objectivec
[self.pubnub publish:message toChannel:@"ch1" mobilePushPayload:pushPayload
      withCompletion:^(PNPublishStatus *status) {
  if (!status.isError) {
    NSLog(@"Successfully published message");
  } else {
    NSLog(@"Failed to publish due to: %@", status);
  }
}];
```

### JavaScript

```javascript
//publish on channel
pubnub.publish(
  {
    channel: "ch1"
    message: pushPayload
  },
  function (status, response) {
    console.log(status);
    console.log(response);
  }
);
```

For more information about push troubleshooting, refer to [Mobile Push Troubleshooting](https://www.pubnub.com/docs/general/push/mobile-push-troubleshooting).