Send mobile push notifications
PubNub connects to Android Firebase Cloud Messaging (FCM) and iOS Apple Push Notification service (APNs) for push notifications.
Create provider keys and add them in the Admin Portal.
FCM also supports iOS. Use one provider or both.
Before you begin, make sure you have:
- Access to the Admin Portal
- Platform credentials (APNs key for iOS, Firebase key for Android)
- A mobile app that requests push notification permissions
A device push token is a unique ID from APNs or FCM that targets a specific app install.
Request a device push token
Register each device with its push provider to get a device push token. Refer to the Android, iOS, and Firebase for iOS documentation for setup.
Register and cache the device push token
After you obtain a device push token, ensure your app always uses the current token. Collect, replace, and cache the device push token. For caching, use UserDefaults
on iOS and SharedPreferences
on Android.
To create the cache:
- Swift
- Objective-C
- Java
- Kotlin
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")
}
}
}
static dispatch_queue_t deviceTokenDispatch;
static dispatch_queue_t pushChannelsDispatch;
static dispatch_once_t registerCustomDispatchOnceToken;
- (void) registerCustomDispatchQueues {
dispatch_once(®isterCustomDispatchOnceToken, ^{
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(deviceTokenDispatch, ^{
token = [[NSUserDefaults standardUserDefaults] dataForKey: @"com.pubnub.deviceToken"];
show all 23 linespublic class SharedPreferencesManager {
private static SharedPreferences sharedPref;
private SharedPreferencesManager() { }
public static void init(Context context) {
if(sharedPref == null)
sharedPref = context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
}
public static final String FCM_DEVICE_TOKEN = "PUBNUB_FCM_DEVICE_TOKEN";
public static @Nullable String readDeviceToken() {
return sharedPref.getString(FCM_DEVICE_TOKEN, null)
}
public static void writeDeviceToken(String value) {
SharedPreferences.Editor prefsEditor = sharedPref.edit();
show all 29 linesclass SharedPreferencesManager private constructor() {
companion object {
private val sharePref = SharedPreferencesManager()
private lateinit var sharedPreferences: SharedPreferences
private val PLACE_OBJ = "place_obj"
private val FCM_DEVICE_TOKEN = "PUBNUB_FCM_DEVICE_TOKEN"
private val FCM_CHANNEL_LIST = "PUBNUB_FCM_CHANNEL_LIST"
fun getInstance(context: Context): SharedPreferencesManager {
if (!::sharedPreferences.isInitialized) {
synchronized(SharedPreferencesManager::class.java) {
if (!::sharedPreferences.isInitialized) {
sharedPreferences = context.getSharedPreferences(context.packageName, Context.MODE_PRIVATE)
show all 28 linesNext, update the cached device push token when it changes.
- Swift
- Objective-C
- Java
- Kotlin
For more information regarding registering token, go to Apple Docs.
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)")
}
}
}
For more information regarding registering token, go to Apple Docs.
- (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 {
show all 19 linespublic class MyFirebaseMessagingService extends FirebaseMessagingService {
@Override public void onNewToken(String token) {
String oldToken = SharedPreferencesManager.readDeviceToken();
if (token.equals(oldToken)) { return; }
SharedPreferencesManager.write(token);
updatePushNotificationsOnChannels(SharedPreferencesManager.readChannelList(), token, oldToken);
}
}
override fun onNewToken(token: String) {
val oldToken = SharedPreferencesManager.getInstance(applicationContext).readDeviceToken()
if (token == oldToken) { return }
SharedPreferencesManager.getInstance(applicationContext).writeDeviceToken(token)
updatePushNotificationsOnChannels(
SharedPreferencesManager.getInstance(applicationContext).readChannelList(),
token,
oldToken
)
}
Connect the device to a channel
Initialize your PubNub client with your subscribe and publish keys. Mark specific channels as push channels. In the examples below, ch1
and ch2
are added as push channels.
- Swift
- Objective-C
- Java
- Kotlin
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)")
}
}
}
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); }
}];
String cachedToken = SharedPreferencesManager.readDeviceToken();
pubnub.addPushNotificationsOnChannels()
.pushType(PNPushType.FCM)
.deviceId(cachedToken)
.channels(Arrays.asList("ch1", "ch2", "ch3"))
.async(result -> { /* check result */ });
SharedPreferencesManager.getInstance(applicationContext).readDeviceToken()?.also { deviceToken ->
pubnub.addPushNotificationsOnChannels(
pushType = PNPushType.FCM,
deviceId = deviceToken,
channels = listOf("ch1", "ch2", "ch3")
).async { result, status ->
// Handle Response
}
}
Build the push notification message
Specify APNs (pn_apns
) or FCM (pn_fcm
) in the payload. For APNs, set the environment (development
or production
) and the app bundle ID (topic
).
For Apple Push Notification Service:
- JSON
- Swift
- Objective-C
{
"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":[
{
show all 25 lineslet 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
)
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
show all 23 linesFor Firebase:
- Swift
- Objective-C
- JSON(Firebase)
- Java
- Kotlin
let message = ["text": "John invited you to chat"]
let pushPayload = PubNubPushMessage(
fcm: PubNubFCMPayload(
payload: nil,
target: .topic("invitations"),
apns: FCMApnsConfig(
headers: [
"apns-push-type": "alert", "apns-topic": "com.mycompany.mybundleid", "apns-priority": "10"
],
payload: APSPayload(alert: .object(.init(title: "Chat Invitation", body: "John invited you to chat")))
)
),
additional: message
)
NSDictionary *message = @{
@"text": @"John invited you to chat"
};
NSDictionary *pushPayload = @{
@"text": @"John invited you to chat",
@"pn_fcm": @{
@"notification": @{
@"title": @"Chat Invitation",
@"body": @"John invited you to chat"
},
@"apns": @{
@"payload": @{
@"aps": @{
@"alert": @{
show all 29 lines{
"text": "John invited you to chat",
"pn_fcm": {
"android": {
"notification": {
"title": "Chat Invitation",
"body": "John invited you to chat"
}
},
"pn_exceptions" : ["device-token1", "device-token2"]
}
}
PushPayloadHelper pushPayloadHelper = new PushPayloadHelper();
PushPayloadHelper.FCMPayload fcmPayload = new PushPayloadHelper.FCMPayload();
PushPayloadHelper.FCMPayload.Notification fcmNotification =
new PushPayloadHelper.FCMPayload.Notification()
.setTitle("Chat Invitation")
.setBody("John invited you to chat");
fcmPayload.setNotification(fcmNotification);
pushPayloadHelper.setFcmPayload(fcmPayload);
Map<String, Object> commonPayload = new HashMap<>();
commonPayload.put("text", "John invited you to chat");
pushPayloadHelper.setCommonPayload(commonPayload);
Map<String, Object> pushPayload = pushPayloadHelper.build();
val pushPayloadHelper = PushPayloadHelper()
val fcmPayload = FCMPayload().apply {
notification = FCMPayload.Notification().apply {
title = "Chat Invitation"
body = "John invited you to chat"
}
custom = mapOf(
"topic" to "invitations",
"pn_exceptions" to arrayOf("device-token1", "device-token2")
)
}
pushPayloadHelper.fcmPayload = fcmPayload
pushPayloadHelper.commonPayload = mapOf(
show all 19 linesSend the push notification
Use publish
to send the push. Publish on the same channels you registered for mobile push.
- Java
- Kotlin
- JavaScript
- Swift
- Objective-C
pubnub.publish()
.channel("ch1")
.message(pushPayload)
.async(result -> { /* check result */ });
pubnub.publish(
channel = "ch1",
message = pushPayload
).async { result ->
// Handle Response
}
//publish on channel
pubnub.publish(
{
channel: "ch1"
message: pushPayload
},
function (status, response) {
// Handle Response
}
);
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)")
}
}
[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);
}
}];