Push Notifications - Device activation and subscription

Every device that will receive push notifications must activate itself with the local operating system or framework, and hook into the push notification services that the underlying platform provides. This functionality is platform-specific and can also vary considerably across not just platforms, but also across the push services that operate on those platforms such as GCM and FCM, both of which are available on the Android platform.

The Ably client libraries aim to abstract away this complexity and platform-specific behaviour by providing a consistent API for device activation, maintenance of the device registration, and for subscription to Ably channels for receiving push notifications.


Push Notifications process using Ably

The client libraries also provide a set of admin functionality that is typically used server-side (in a trusted environment) to manage all devices and push notification delivery and subscriptions. You can find out more in the push admin documentation.

In this section, we will run you through all of the features that a push notification device has available to it.

Prerequisites

Before you can configure your devices to receive push notifications, you must first enable push in your Ably app by adding the third party push service credentials and/or certificates to your app push dashboard. These credentials are then used by Ably to authenticate with the respective third party push service (such as APNs) and delivery all queued notifications.

If you have not already done so, you can sign up for a free account with Apple’s Push Notification service and Google’s Firebase Cloud Messaging service.

Platform installation

Whilst platform installation is platform-specific, all subsequent Ably API calls are generally portable. Be sure to choose a language above that you wish to see the documentation and code examples in.

Before you can activate your push device or receive push notifications, you must first plug in Ably to the underlying OS or platform. Once Ably is plugged in, all subsequent API interactions you have will be with the Ably Realtime library API which is as consistent as possible across all platforms. By providing a consistent API interface across all platforms, we aim to ensure implementation is simpler and more predictable regardless of the platform you are integrating Ably with.

Installation, however, is platform-specific and as such, instructions for each platform and service are provided below:

Install Ably for Google Firebase Cloud Messaging on Android

As with any Firebase-enabled app, you need to include one or more services within your app to handle interactions with Firebase. You need to have a service that extends FirebaseMessagingService (and overrides onMessageReceived()) in order to handle incoming push messages; the code that handles incoming push messages does not need to interact with Ably in any way.

The second requirement is that your app integrates with Firebase to handle registration token notifications, and these notifications do need to be passed to Ably; the registration token is used by Ably’s servers to be able to push messages to each specific device. You can be notified of token updates either be by overriding onNewToken() in your derived FirebaseMessagingService, or by overriding onTokenRefresh() in a service that derives from FirebaseInstanceIdService. A convenient way to do the latter is to extend AblyFirebaseInstanceIdService; in this case your service’s parent class handles the token update, so you do not need to do anything other than ensure the service is activated.

If you are handling token indications in your own code, registration tokens must be notified to the Ably library by calling AblyFirebaseInstanceIdService.onNewRegistrationToken(). If deriving from FirebaseInstanceIdService directly, for example, your class should end up looking more or less like this:

public class MyRegistrationTokenService extends FirebaseInstanceIdService {
    @Override
    public void onTokenRefresh() {
        // Get updated InstanceID token.
        String token = FirebaseInstanceId.getInstance().getToken();
        // Notify Ably
        AblyFirebaseInstanceIdService.onNewRegistrationToken(this, token);
    }
}

Install Ably for Apple Push Notifications on iOS

You should now have a couple of methods: application(_:didRegisterForRemoteNotificationsWithDeviceToken:)application:didRegisterForRemoteNotificationsWithDeviceToken: and application(_:didFailToRegisterForRemoteNotificationsWithError:)application:​did​Fail​To​Register​For​Remote​Notifications​With​Error:​. ARTPush has two corresponding methods that you should call from yours, passing to them also an ARTRealtime instance, configured with the authentication setup and other options you need.

// In your UIApplicationDelegate class:
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    [ARTPush didRegisterForRemoteNotificationsWithDeviceToken:deviceToken realtime:[self getAblyRealtime]];
}

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error;
    [ARTPush didFailToRegisterForRemoteNotificationsWithError:error realtime:[self getAblyRealtime]];
}

- (ARTRealtime *)getAblyRealtime {
    ARTClientOptions *options = [[ARTClientOptions alloc] init];
    // Set up options; API key or auth URL, etc.
    return [[ARTRealtime alloc] initWithOptions: options];
}
// In your UIApplicationDelegate class:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    ARTPush.didRegisterForRemoteNotifications(withDeviceToken: deviceToken, realtime: self.getAblyRealtime())
}

func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
    ARTPush.didFailToRegisterForRemoteNotificationsWithError(error, realtime: self.getAblyRealtime())
}

func getAblyRealtime() -> ARTRealtime {
    var options = ARTClientOptions()
    // Set up options; API key or auth URL, etc.
    return ARTRealtime(options: options)
}

Activating push on your device

Activating a device for push notifications and registering it with Ably is commonly performed entirely from the device. However, it is possible to separate the concerns such that activation with the underlying platform is performed on the device, and registration of that activated device with Ably is performed using your own servers. This latter pattern is more commonly used when you want to minimize the capabilities assigned to an untrusted device. Find out how to register the device from your servers


Push Notifications direct device registration

In the following example, we will both activate the device with the underlying platform and register the device with Ably from the device itself.

Activate the device for push with push.activate

If you want to start receiving push notifications from Ably (e.g. from your main activityyour UIApplicationDelegate), you need to first call AblyRealtime.push.activateARTRealtime.push.activate which will register the device for push by doing the following on your behalf:

  • Ensure the Ably client is authenticated
  • Generate a unique identifier for this device and store this in local storage
  • Activate the device for push notifications with the underlying OS or platform and obtain a unique identifier for the device as a push recipient. For example, in FCM this is described as a registration token, and in APNs this is described as a device token
  • Register the local device with Ably using the device’s unique identifier, platform-specific details such as form factor and OS, and the push recipient details to receive push notifications. This in turn ensures Ably can reach this device and deliver push notifications
  • Store the deviceIdentityToken from the response from Ably in local storage so that subsequent requests to Ably to update push recipient details are authenticated as being from the device in question.

Please note that the effects of calling activate outlives the current process. Once called, the device will stay registered even after the application is closed, and up until deactivate is called. activate is idempotent: calling it again when device is already activated has the sole effect of calling its callback.

AblyRealtime ably = getAblyRealtime();
ably.setAndroidContext(context)
ably.push.activate();
ARTRealtime *ably = [self getAblyRealtime];
[ably.push activate];
let ably = self.getAblyRealtime()
ably.push.activate()

Please bear in mind that in order for the client to register itself automatically with Ably, it needs to be authenticated and have the required push-subscribe capability. If you would prefer to delegate registration of the push device to your own servers and not allow devices to register themselves directly with Ably, then see the section how to register devices from your server. You can also check our recommendations for choosing either registration strategy.

Register for callback from activate

Once activate is called, the aforementioned activation and registration process kicks off in the background. Once completed, a callback will be invoked if registered. We recommend you set up this callback so that you will be notified when push activation has succeeded or failed. Once the device has successfully been activated, you can then start subscribing for push notifications on channels and receiving push notifications via Ably.

When the activation process is completed, Ably will send a broadcast through the application’s LocalBroadcastManager. You should listen for a broadcast with action io.ably.broadcast.PUSH_ACTIVATEcall your (void)didActivateAblyPush:(nullable ARTErrorInfo *)errordidActivateAblyPush(error: ARTErrorInfo?) method from your ARTPushRegistererDelegate implementation as follows:

LocalBroadcastManager.getInstance(context.getApplicationContext()).registerReceiver(new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        ErrorInfo error = IntentUtils.getErrorInfo(intent);
        if (error != null) {
            // Handle error
            return;
        }
        // Subscribe to channels / listen for push etc.
    }
}, new IntentFilter("io.ably.broadcast.PUSH_ACTIVATE"));

ably.push.activate(context);
// Add the activate method from 'ARTPushRegistererDelegate' to your 'UIApplicationDelegate' class:
- (void)didActivateAblyPush:(nullable ARTErrorInfo *)error {
    if (error) {
        // Handle error
        return;
    }
    // Subscribe to channels / listen for push etc.
}

// Call activate, which will call the delegate method when done:
[ably.push activate];
// Add the activate method from 'ARTPushRegistererDelegate' to your 'UIApplicationDelegate' class:
func didActivateAblyPush(_ error: ARTErrorInfo?) {
    if let error = error {
        // Handle error
        return
    }
    // Subscribe to channels / listen for push etc.
}

// Call activate, which will call the delegate method when done:
ably.push.activate()

Subscribe for push notifications

Before you subscribe to a channel for push, make sure its channel namespace is configured to explicitly enable push notifications. By default, push notifications on channels are disabled.

There are two ways a device can be subscribed to a channel: directly by its device ID, or indirectly by its associated client ID.

Subscribing by device ID

A device ID uniquely identifies a device within Ably’s services and is assigned automatically at the time the device is activated.

If your client has the push-subscribe capabilities, you can do the following:

[[realtime.channels get:@"pushenabled:foo"].push subscribeDevice:^(ARTErrorInfo *error) {
    // Check error.
}];
realtime.channels.get("pushenabled:foo").push.subscribeDevice { error
    // Check error.
}
realtime.channels.get("pushenabled:foo").push.subscribeDevice(context);

// or

realtime.channels.get("pushenabled:foo").push.subscribeDeviceAsync(context, new CompletionListener() {
    @Override
    public void onSuccess() {}

    @Override
    public void onError(ErrorInfo errorInfo) {
        // Handle error.
    }
});

If your client doesn’t have the push-subscribe permissions, you should communicate the device ID to your server so that it can subscribe on the device’s behalf. You can find your unique device ID at ARTRealtime.device.idAblyRealtime.device().id. The server must then use the push admin API to subscribe the device.

Subscribing by client ID

When a device is registered, it can be associated with a client ID. AblyRealtime.push.activateARTRealtime.push.activate takes the client ID from the AblyRealtime instance.

You can subscribe all devices associated with a client ID to a channel in a single operation; that is, create a subscription by client ID. New device registrations associated to that client ID will also be subscribed to the channel, and if a device registration is no longer associated with that client ID, it will also stop being subscribed to the channel (unless it’s also subscribed directly by device ID).

To subscribe your AblyRealtime instance’s client ID to a channel:

[[realtime.channels get:@"pushenabled:foo"].push subscribeClient:^(ARTErrorInfo *error) {
    // Check error.
}];
realtime.channels.get("pushenabled:foo").push.subscribeClient { error
    // Check error.
}
realtime.channels.get("pushenabled:foo").push.subscribeClient();

// or

realtime.channels.get("pushenabled:foo").push.subscribeClientAsync(new CompletionListener() {
    @Override
    public void onSuccess() {}

    @Override
    public void onError(ErrorInfo errorInfo) {
        // Handle error.
    }
});

Alternatively, if you want to subscribe a different client ID not currently associated with the currently authenticated realtime instance, you can use the admin API.

Push capabilities

These are the capabilities necessary to perform push operations:

  • push-subscribe: Register and deregister the local device, and subscribe and unsubscribe the local device to channels for push notifications.
  • push-admin: Register, update and deregister any device registration, and subscribe and unsubscribe to channels for push notifications. Publish push notification using the POST /push/publish endpoint (AblyRealtime.push.admin.publish method).

Typically, client devices subscribing for push will either have push-subscribe privileges or delegate operations to a server with push-admin privileges.

Activating devices from your server

The default for AblyRealtime.push.activate is to register the device with Ably directly from the device, but you can instead delegate that to your server. Don’t forget to register the device using the push admin API in your server.


Push Notifications device registration via server

For this, your UIApplicationDelegate must implement these optional methods from ARTPushRegistererDelegate:

- (void)ablyPushCustomRegister:(ARTErrorInfo *)error
                 deviceDetails:(ARTDeviceDetails *)deviceDetails
                      callback:(void (^)(ARTDeviceIdentityTokenDetails * _Nullable, ARTErrorInfo * _Nullable))callback {
    if (error) {
        // Handle error.
        callback(nil, error);
        return;
    }

    [self registerThroughYourServer:deviceDetails callback:callback];
}

- (void)ablyPushCustomDeregister:(ARTErrorInfo *)error d
                         eviceId:(ARTDeviceId *)deviceId
                        callback:(void (^)(ARTErrorInfo * _Nullable))callback {
    if (error) {
        // Handle error.
        callback(nil, error);
        return;
    }

    [self unregisterThroughYourServer:deviceDetails callback:callback];
}
func ablyPushCustomRegister(_ error: ARTErrorInfo?, deviceDetails: ARTDeviceDetails, callback: @escaping (ARTDeviceIdentityTokenDetails?, ARTErrorInfo?) -> Void) {
    if let e = error {
        // Handle error.
        callback(nil, e)
        return
    }

    self.registerThroughYourServer(deviceDetails: deviceDetails, callback: callback)
}

func ablyPushCustomDeregister(_ error: ARTErrorInfo?, deviceId: String, callback: ((ARTErrorInfo?) -> Void)? = nil) {
    if let e = error {
        // Handle error.
        callback(nil, e)
        return
    }

    self.unregisterThroughYourServer(deviceDetails: deviceDetails, callback: callback)
}

For this, you need to communicate back and forth with the Ably library via the application’s LocalBroadcastManager.

First, make sure you pass true as the useCustomRegisterer parameter to activate (and for deactivate).

ably.push.activate(context, true);
ably.push.deactivate(context, true);

The Ably library will then broadcast an io.ably.broadcast.PUSH_REGISTER_DEVICE action when it needs you to register from your server, and io.ably.broadcast.PUSH_DEREGISTER_DEVICE when it needs you to deregister. You must configure a listener to those actions in your application’s AndroidManifest.xml, and from it answer back with a PUSH_DEVICE_REGISTERED or PUSH_DEVICE_DEREGISTERED, like this:

<receiver android:name=".MyAblyBroadcastReceiver" >
  <intent-filter>
     <action android:name="io.ably.broadcast.PUSH_REGISTER_DEVICE" />
     <action android:name="io.ably.broadcast.PUSH_DEREGISTER_DEVICE" />
  </intent-filter>
</receiver>
public class MyAblyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        AblyRealtime ably = getAblyRealtime();
        String action = intent.getAction();

        if (action.equals("io.ably.broadcast.PUSH_REGISTER_DEVICE")) {
            DeviceDetails device = ably.device(context);
            boolean isNew = intent.getBooleanExtra("isNew", false);

            Intent response = new Intent("io.ably.broadcast.PUSH_DEVICE_REGISTERED");

            try {
                String deviceIdentityToken = registerThroughYourServer(device, isNew);
                response.putExtra("deviceIdentityToken", deviceIdentityToken);
            } catch(AblyException e) {
                IntentUtils.addErrorInfo(intent, e.errorInfo);
            }

            LocalBroadcastManager.getInstance(context.getApplicationContext()).sendBroadcast(intent);
        } else if (action.equals("io.ably.broadcast.PUSH_DEREGISTER_DEVICE")) {
            DeviceDetails device = ably.device(context);

            Intent response = new Intent("io.ably.broadcast.PUSH_DEVICE_DEREGISTERED");

            try {
                deregisterThroughYourServer(device.id);
            } catch(AblyException e) {
                IntentUtils.addErrorInfo(intent, e.errorInfo);
            }

            LocalBroadcastManager.getInstance(context.getApplicationContext()).sendBroadcast(intent);
        }
    }
}

Direct registration vs. registration via your server

Two options for registering devices gives you the flexibility to implement push notifications in the best way for each use case.

Direct registration means less server side code as the device registers itself and attaches to a channel. However, this means you need to trust your devices to handle this securely and efficiently. Token authentication solves this.

If you want to control all of your devices server side then registration via server is the way to go. The Ably Push Admin API lets you do this.

Ably can deliver native push notifications to devices using, amongst others, Apple’s Push Notification service and Google’s Firebase Cloud Messaging service. Native push notifications, unlike Ably’s channel based pub/sub messaging, do not require the device to maintain a connection to Ably, as the underlying platform or OS is responsible for maintaining its own battery-efficient transport to receive push notifications. Therefore, native push notifications are commonly used to display visual notifications to users or launch a background process for an app in a battery-efficient manner.

Delivering push notifications


Push Notifications in Ably

As shown above, Ably provides two models for delivering push notifications to devices:

Direct publishing

Ably provides a REST API that allows native push notifications to be delivered directly to:

  • Devices identified by their unique device ID
  • Devices identified by their assigned clientId
  • Devices identified by the recipient details of the native push transport such as their unique registrationToken in the case of FCM, deviceToken in the case of APNS, or targetUrl and encryptionKey in the case of a Web device (experimental). This means is particularly useful when migrating to Ably with existing push notification target devices.

Find out more about direct push notification publishing

Channel-based broadcasting

The model for delivering push notifications to devices over channels is intentionally very similar to how messages are normally delivered using Ably’s pub/sub channel. For example, a normal message published on an Ably channel is broadcast immediately to all realtime subscribers of that channel. When broadcasting push notifications on channels, however, the process is the same with the exception that the subscribers (devices receiving push notifications) are registered in advance using our API and the message itself must contain an extra push notification payload that specifies the optional visual format and optional data payload of the native push notification.

Find out more about channel-based push notification broadcasting

Activating a device and receiving notifications

Every device that will receive push notifications must activate itself with the local operating system or framework, and hook into the push notification services that the underlying platform provides. This functionality is platform-specific and can also vary considerably across not just platforms, but also across the push services that operate on those platforms such as GCM and FCM, both of which are available on the Android platform.

The Ably client libraries aim to abstract away this complexity and platform-specific behaviour by providing a consistent API for device activation, maintenance of the device registration, and for subscription to Ably channels for receiving push notifications.

Find out more about device activations and subscriptions.

Managing devices and subscriptions

Whilst the realtime client libraries provide APIs for a device to activate itself (via client.push) and subscribe for push notifications (via channel.push), those APIs are intentionally limited to actions pertaining to the device it is run on.

A separate and distinct push admin API is additionally provided in our client libraries specifically designed for use by your servers to facilitate managing and delivering push notifications across all of your registered devices. This API, amongst other things, includes features to manage registered devices, channel subscriptions and deliver push notifications directly. Currently the push admin API is available in our JavaScript, Ruby, Java/Android, PHP, Python, and iOS libraries. It is also available in our other libraries through the use of the request method, using the underlying API directly.

Find out more about the push admin API.

Platform support

Ably currently offers support for push notifications on the following platforms:

Apple Push Notifications
supported on all mobile devices running iOS and desktop devices running OS X
Firebase Cloud Messaging
supported on all Android and iOS devices, although we use FCM exclusively for Android message delivery
Experimental W3C Push API
experimental support for modern W3C compliant browsers (this does not include Apple’s Safari browser). Get in touch if you want to use this.

Push Device API reference

Push Device object

This object is accessible through client.push and provides to push-compatible devices:

Methods

activate

void activate()activate(callback: (ARTErrorInfo?, DeviceDetails?) → Void)

Register the device for push. When the activation process is completed, Ably will send a broadcast through the application’s LocalBroadcastManager. Success or failure will be broadcast through io.ably.broadcast.PUSH_ACTIVATEcall the (void)didActivateAblyPush:(nullable ARTErrorInfo *)errordidActivateAblyPush(error: ARTErrorInfo?) method from the ARTPushRegistererDelegate.

deactivate

void deactivate()deactivate(deregisterCallback: (ARTErrorInfo?, deviceId: String?) → Void)

Deregister the device for push. When the deactivation process is completed, Ably will send a broadcast through the application’s LocalBroadcastManager. Success or failure will be broadcast through io.ably.broadcast.PUSH_DEACTIVATEcall the (void)didDeactivateAblyPush:(nullable ARTErrorInfo *)errordidDeactivateAblyPush(error: ARTErrorInfo?) method from the@ARTPushRegistererDelegate@.

DeviceDetailsAbly::Models::DeviceDetailsARTDeviceDetails

A DeviceDetails is a type encapsulating attributes of a device registered for push notifications.

PropertiesMembersAttributes

id
unique identifier for the device generated by the device itself
Type: String
clientIdclient_id
optional trusted client identifier for the device
Type: String
formFactorform_factor
form factor of the push device. Must be one of phone, tablet, desktop, tv, watch, car or embedded
Type: String
metadata
optional metadata object for this device. The metadata for a device may only be set by clients with push-admin privileges and will be used more extensively in the future with smart notifications
Type: ObjectHash
platform
platform of the push device. Must be one of ios or android
Type: String
deviceSecret
Secret value for the device.
Type: String
push.recipient
push recipient details for this device. See the REST API push publish documentation for more details
Type: ObjectHash
push.state
the current state of the push device being either Active, Failing or Failed
Type: String
push.errorReasonpush.error_reason
when the device’s state is failing or failed, this attribute contains the reason for the most recent failure
Type: ErrorInfo

LocalDeviceAbly::Models::LocalDevice

An extension of DeviceDetails. In addition to the propertiesmembersattributes of DeviceDetails, it includes the following:

PropertiesMembersAttributes

deviceIdentityToken
a unique identity token for the device
Type: String

PushChannelAbly::Models::PushChannel

A PushChannel is a property of a RealtimeChannel or RestChannel. It provides push devices the ability to subscribe and unsubscribe to push notifications on channels.

subscribeDevice

subscribeDevice()

Subscribe your device to the channel’s push notifications.

subscribeClient

subscribeClient()

Subscribe all devices associated with your device’s clientId to the channel’s push notifications.

unsubscribeDevice

unsubscribeDevice()

Unsubscribe your device from the channel’s push notifications.

unsubscribeClient

unsubscribeClient()

Unsubscribe all devices associated with your device’s clientId from the channel’s push notifications.

listSubscriptions

PaginatedResult<PushChannelSubscription> listSubscriptions(String deviceId, String clientId, String deviceClientId, String channel)listSubscriptions(deviceId: String?, clientId: String?, deviceClientId: String?, channel: String?, callback: (ARTPaginatedResult<PushChannelSubscription>?, ARTErrorInfo?) → Void)

Unsubscribe all devices associated with your device’s clientId from the channel’s push notifications.

Parameters

deviceId
a deviceId to filter by
Type: String
clientId
a clientId to filter by
Type: String
deviceClientId
a client ID associated with a device to filter by
Type: String
callback
called with a ARTPaginatedResult<PushChannelSubscription> object or an error

Callback result

On success, resultPage contains a PaginatedResult encapsulating an array of PushChannelSubscription objects corresponding to the current page of results. PaginatedResult supports pagination using next() and first() methods.

On failure to retrieve message history, err contains an ErrorInfo object with the failure reason.

Returns

On success, the returned PaginatedResult encapsulates an array of PushChannelSubscription objects corresponding to the current page of results. PaginatedResult supports pagination using next and first methods.

Failure to retrieve the message history will raise an AblyException

PushChannelSubscriptionAbly::Models::PushChannelSubscriptionChannelSubscriptionArtPushChannelSubscription

An PushChannelSubscription is a type encapsulating the subscription of a device or group of devices sharing a client identifier to a channel in order to receive push notifications.

PropertiesMembersAttributes

channel
the channel that this push notification subscription is associated with
Type: String
deviceIddevice_id
the device with this identifier is linked to this channel subscription. When present, clientIdclient_id is never present
Type: String
clientIdclient_id
devices with this client identifier are included in this channel subscription. When present, deviceIddevice_id is never present
Type: String

PushChannelSubscription constructors

PushChannelSubscription.forDevicePushChannelSubscription.for_device

PushChannelSubscription.forDevice(String channel, String deviceId) → PushChannelSubscriptionPushChannelSubscription.for_device(String channel, String device_id) → PushChannelSubscription

A static factory method to create a PushChannelSubscription object for a channel and single device.

Parameters

channel
channel name linked to this push channel subscription
Type: String
deviceIddevice_id
the device with this identifier will be linked with this push channel subscription
Type: String

Returns

A PushChannelSubscription object

PushChannelSubscription.forClientPushChannelSubscription.for_client

PushChannelSubscription.forDevice(String channel, String clientId) → PushChannelSubscriptionPushChannelSubscription.for_device(String channel, String client_id) → PushChannelSubscription

A static factory method to create a PushChannelSubscription object for a channel and group of devices sharing a client identifier.

Parameters

channel
channel name linked to this push channel subscription
Type: String
clientIdclient_id
devices with this client identifier are included in the new push channel subscription
Type: String

Returns

A PushChannelSubscription object

PaginatedResultARTPaginatedResultAbly::Models::PaginatedResultio.ably.lib.types.PaginatedResultIO.Ably.PaginatedResult

A PaginatedResult is a type that represents a page of results for all message and presence history, stats and REST presence requests. The response from a Ably REST API paginated query is accompanied by metadata that indicates the relative queries available to the PaginatedResult object.

PropertiesMembersAttributes

itemsItems
contains the current page of results (for example an Array of Message or PresenceMessage objects for a channel history request)
Type: Array <Message, Presence, Stats>Type: List <Message, Presence, Stats>

Methods

firstFirst

first(callback(ErrorInfo err, PaginatedResult resultPage))PaginatedResult firstPaginatedResult first()PaginatedResult first()Task<PaginatedResult> FirstAsync()PaginatedResult first()first(callback: (ARTPaginatedResult?, ARTErrorInfo?) → Void)First() (PaginatedResult, error)

Returns a new PaginatedResult for the first page of results. When using the Realtime library, the first method returns a Deferrable and yields a PaginatedResult.The method is asynchronous and returns a Task which needs to be awaited to get the PaginatedResult.

hasNextHasNexthas_next?has_next

Boolean hasNext()Boolean has_next?Boolean hasNext()Boolean has_next()Boolean HasNext()Boolean hasNext()Boolean hasNext()HasNext() (bool)

Returns true if there are more pages available by calling nextNext and returns false if this page is the last page available.

isLastIsLastlast?is_last

Boolean isLast()Boolean last?Boolean isLast()Boolean is_last()Boolean IsLast()Boolean isLast()Boolean isLast()IsLast() (bool)

Returns true if this page is the last page and returns false if there are more pages available by calling nextNext available.

nextNext

next(callback(ErrorInfo err, PaginatedResult resultPage))PaginatedResult nextPaginatedResult next()PaginatedResult next()Task<PaginatedResult> NextAsync()PaginatedResult next()next(callback: (ARTPaginatedResult?, ARTErrorInfo?) → Void)Next() (PaginatedResult, error)

Returns a new PaginatedResult loaded with the next page of results. If there are no further pages, then nulla blank PaginatedResult will be returnedNullNonenil is returned. The method is asynchronous and return a Task which needs to be awaited to get the PaginatedResultWhen using the Realtime library, the first method returns a Deferrable and yields a PaginatedResult.

Example

channel.history(function(err, paginatedResult) {
  console.log('Page 0 item 0:' + paginatedResult.items[0].data);
  paginatedResult.next(function(err, nextPage) {
    console.log('Page 1 item 1: ' + nextPage.items[1].data);
    console.log('Last page?: ' + nextPage.isLast());
  });
});
channel.history(function(err, paginatedResult) {
  console.log('Page 0 item 0:' + paginatedResult.items[0].data);
  paginatedResult.next(function(err, nextPage) {
    console.log('Page 1 item 1: ' + nextPage.items[1].data);
    console.log('Last page?: ' + nextPage.isLast());
  });
});
PaginatedResult firstPage = channel.history();
System.out.println("Page 0 item 0:" + firstPage.items[0].data);
if (firstPage.hasNext) {
  PaginatedResult nextPage = firstPage.next();
  System.out.println("Page 1 item 1:" + nextPage.items[1].data);
  System.out.println("More pages?:" + Strong.valueOf(nextPage.hasNext()));
};
PaginatedResult<Message> firstPage = await channel.HistoryAsync(null);
Message firstMessage = firstPage.Items[0];
Console.WriteLine("Page 0 item 0: " + firstMessage.data);
if (firstPage.HasNext)
{
    var nextPage = await firstPage.NextAsync();
    Console.WriteLine("Page 1 item 1:" + nextPage.Items[1].data);
    Console.WriteLine("More pages?: " + nextPage.HasNext());
}
# When using the REST sync library
first_page = channel.history
puts "Page 0 item 0: #{first_page.items[0].data}"
if first_page.has_next?
  next_page = first_page.next
  puts "Page 1 item 1: #{next_page.items[1].data}"
  puts "Last page?: #{next_page.is_last?}"
end

# When using the Realtime EventMachine library
channel.history do |first_page|
  puts "Page 0 item 0: #{first_page.items[0].data}"
  if first_page.has_next?
    first_page.next do |next_page|
      puts "Page 1 item 1: #{next_page.items[1].data}"
      puts "Last page?: #{next_page.is_last?}"
    end
  end
end
result_page = channel.history()
print 'Page 0 item 0: ' + str(result_page.items[0].data)
if result_page.has_next():
  next_page = result_page.next()
  print 'Page 1 item 1: ' + str(next_page.items[1].data)
  print 'Last page?: ' + str(next_page.is_last())
$firstPage = $channel.history();
echo("Page 0 item 0: " . $firstPage->items[0]->data);
if ($firstPage->hasNext()) {
  $nextPage = $firstPage->next();
  echo("Page 1 item 1: " . $nextPage->items[1]->data);
  echo("Last page?: " . $nextPage->isLast());
}
[channel history:^(ARTPaginatedResult<ARTMessage *> *paginatedResult, ARTErrorInfo *error) {
    NSLog(@"Page 0 item 0: %@", paginatedResult.items[0].data);
    [paginatedResult next:^(ARTPaginatedResult<ARTMessage *> *nextPage, ARTErrorInfo *error) {
        NSLog(@"Page 1 item 1: %@", nextPage.items[1].data);
        NSLog(@"Last page?: %d", nextPage.isLast());
    }];
}];
channel.history { paginatedResult, error in
    let paginatedResult = paginatedResult!
    print("Page 0 item 0: \((paginatedResult.items[0] as! ARTMessage).data)")
    paginatedResult.next { nextPage, error in
        let nextPage = nextPage!
        print("Page 1 item 1: \((nextPage.items[1] as! ARTMessage).data)")
        print("Last page? \(nextPage.isLast())")
    }
}
page0, err := channel.History(nil)
fmt.Println("Page. 0 item 0: %s\n", page0.Messages[0].Data)
page1, err := page0.Next()
fmt.Println("Page. 1 item 1: %s\n", page1.Messages[1].Data)
fmt.Println("Last page? %s\n", page1.IsLast())

API reference
Documentation

Ready to get started?

Our free plan includes 3m messages per month, 100 peak connections, 100 peak channels, and loads of features.