# Push Notifications - Device Activation and Subscription ## Push Device object This object is accessible through `client.push` and provides to [push-compatible devices](https://ably.com/docs/push.md) : ### Methods #### activate `activate(registerCallback?(DeviceDetails device, callback(ErrorInfo | null err, DeviceDetails result)), updateFailedCallback?(ErrorInfo | null err)): Promise` `void activate()` `activate(callback: (ARTErrorInfo?, DeviceDetails?) -> Void)` Register the device for push. When the [activation process](https://ably.com/docs/push/configure/device.md#activate-devices) is completed, Ably will send a broadcast through the application's [`LocalBroadcastManager`](https://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager). Success or failure will be broadcast through `io.ably.broadcast.PUSH_ACTIVATE`call the `(void)didActivateAblyPush:(nullable ARTErrorInfo *)error``didActivateAblyPush(error: ARTErrorInfo?)` method from the `ARTPushRegistererDelegate`. [Activates the device](https://ably.com/docs/push/configure/web.md#activate-browsers) for push notifications. Subsequently registers the device with Ably and stores the `deviceIdentityToken` in local storage. ##### Parameters | Parameter | Description | Type | |-----------|-------------|------| | registerCallback | An optional function passed to override the default implementation to register the local device for push activation | `Callable` | | updateFailedCallback | An optional callback to be invoked when the device registration failed to update | `Callable` | ##### Returns Returns a promise. On successful device activation, the promise resolves. On failure, the promise is rejected with an [`ErrorInfo`](#error-info) object that details the reason why it was rejected. #### deactivate `deactivate(deregisterCallback?(DeviceDetails device, callback(ErrorInfo | null err, String result))): Promise` `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`](https://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager). Success or failure will be broadcast through `io.ably.broadcast.PUSH_DEACTIVATE`call the `(void)didDeactivateAblyPush:(nullable ARTErrorInfo *)error``didDeactivateAblyPush(error: ARTErrorInfo?)` method from the `ARTPushRegistererDelegate`. Deactivates the device from receiving push notifications. ##### Parameters | Parameter | Description | Type | |-----------|-------------|------| | `deregisterCallback` | An optional function passed to override the default implementation to deregister the local device for push activation | `Callable` | ##### Returns Returns a promise. On successful device deactivation, the promise resolves. On failure, the promise is rejected with an [`ErrorInfo`](#error-info) object that details the reason why it was rejected. ## Location push notifications Starting with iOS 15, Apple supports a power-efficient way to request location through the location push service extension. The following table explains how to receive location push notifications: | Action | Details | |--------|---------| | Request location token | Call `CLLocationManager.startMonitoringLocationPushes(completion:)` within the `ARTPushRegistererDelegate.didActivateAblyPush(:)` delegate method. This delegate method is the callback for `ARTRealtime.push.activate()`. | | Register with Ably | Call `ARTPush.didRegisterForLocationNotifications(withDeviceToken:realtime:)` when you receive the location push token. Note the "Location" in the method name to distinguish it from regular push tokens. | | Handle result | Use the `ARTPushRegistererDelegate.didUpdateAblyPush:` callback, which indicates whether the token was successfully saved. | ## Related types ### DeviceDetailsARTDeviceDetails A `DeviceDetails` is a type encapsulating attributes of a device registered for push notifications. #### PropertiesMembers | Property | Description | Type | |----------|-------------|------| | id | Unique identifier for the device generated by the device itself | `String` | | clientId | Optional trusted [client identifier](https://ably.com/docs/auth/identified-clients.md) for the device | `String` | | formFactor | Form factor of the push device. Must be one of `phone`, `tablet`, `desktop`, `tv`, `watch`, `car` or `embedded``embedded` or `other` | `String` | | metadata | Optional metadata object for this device. The metadata for a device may only be set by clients with `push-admin` privileges | `Object` | | platform | Platform of the push device. Must be one of `ios` or `android``android` or `browser` | `String` | | deviceSecret | Secret value for the device | `String` | | push.recipient | Push recipient details for this device. See the [REST API push publish documentation](https://ably.com/docs/api/rest-api.md#message-extras-push) for more details | `Object` | | push.state | The current state of the push device being either `Active`, `Failing` or `Failed``ACTIVE`, `FAILING` or `FAILED` | `String` | | push.errorReasonpush.error | When the device's state is failing or failed, this attribute contains the reason for the most recent failure | [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) | ### LocalDevice An extension of [`DeviceDetails`](#device-details). In addition to the membersproperties of [`DeviceDetails`](#device-details), it includes the following: Contains the device identity token and secret of a device. #### PropertiesMembers | Property | Description | Type | |----------|-------------|------| | id | A unique ID generated by the device | `String` | | deviceSecret | A unique device secret generated by the Ably SDK | `String` | | deviceIdentityToken | A unique identity token for the device | `String` | | Property | Description | Type | |----------|-------------|------| | deviceIdentityToken | A unique identity token for the device | `String` | #### Methods ##### listSubscriptions `listSubscriptions(): Promise<PaginatedResult<PushChannelSubscription>>` Retrieves push subscriptions active for the local device. ##### Returns Returns a promise. On success, the promise is fulfilled with a [PaginatedResult](https://ably.com/docs/api/realtime-sdk/types.md#paginated-result) object containing an array of [PushChannelSubscription](https://ably.com/docs/api/realtime-sdk/types.md#push-channel-subscription) objects for each push channel subscription active for the local device. On failure, the promise is rejected with an [`ErrorInfo`](#error-info) object that details the reason why it was rejected. ### PushChannel A `PushChannel` is a property of a [`RealtimeChannel`](https://ably.com/docs/api/realtime-sdk/channels.md#properties) or [`RestChannel`](https://ably.com/docs/api/rest-sdk/channels.md#properties). It provides [push devices](https://ably.com/docs/push.md) the ability to subscribe and unsubscribe to push notifications on channels. #### Methods ##### subscribeDevice `subscribeDevice(): Promise` `subscribeDevice()` Subscribe your device to the channel's push notifications. ##### Returns Returns a promise. On success, the promise resolves. On failure, the promise is rejected with an [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) object that details the reason why it was rejected. #### subscribeClient `subscribeClient(): Promise` `subscribeClient()` [Subscribe all devices associated with your device's clientId](https://ably.com/docs/push/publish.md#sub-channels) to the channel's push notifications. ##### Returns Returns a promise. On success, the promise resolves. On failure, the promise is rejected with an [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) object that details the reason why it was rejected. #### unsubscribeDevice `unsubscribeDevice(): Promise` `unsubscribeDevice()` Unsubscribe your device from the channel's push notifications. ##### Returns Returns a promise. On success, the promise resolves. On failure, the promise is rejected with an [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) object that details the reason why it was rejected. #### unsubscribeClient `unsubscribeClient(): Promise` `unsubscribeClient()` [Unsubscribe all devices associated with your device's clientId](https://ably.com/docs/push/publish.md#sub-channels) from the channel's push notifications. ##### Returns Returns a promise. On success, the promise resolves. On failure, the promise is rejected with an [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) object that details the reason why it was rejected. #### listSubscriptions `listSubscriptions(Record params?): Promise>` `PaginatedResult listSubscriptions(String deviceId, String clientId, String deviceClientId, String channel)` `listSubscriptions(deviceId: String?, clientId: String?, deviceClientId: String?, channel: String?, callback: (ARTPaginatedResult?, ARTErrorInfo?) -> Void)` Lists push subscriptions on a channel specified by its channel name (`channel`). These subscriptions can be either be a list of client (`clientId`) subscriptions, device (`deviceId`) subscriptions, or if @concatFilters@ is set to @true@, a list of both. This method requires clients to have the [Push Admin capability](push#push-admin). For more information, see `GET main.realtime.ably.net/push/channelSubscriptions` [Rest API](https://ably.com/docs/api/rest-api.md). ##### Parameters | Parameter | Description | Type | |-----------|-------------|------| | deviceId | A deviceId to filter by | `String` | | clientId | A clientId to filter by | `String` | | deviceClientId | A client ID associated with a device to filter by | `String` | | params | An optional object containing key-value pairs to filter subscriptions by. Can contain `clientId`, `deviceId` or a combination of both, and a `limit` on the number of subscriptions returned, up to 1,000 | `Record` | | Parameter | Description | Type | |-----------|-------------|------| | deviceId | A deviceId to filter by | `String` | | clientId | A clientId to filter by | `String` | | deviceClientId | A client ID associated with a device to filter by | `String` | | Parameter | Description | Type | |-----------|-------------|------| | deviceId | A deviceId to filter by | `String` | | clientId | A clientId to filter by | `String` | | deviceClientId | A client ID associated with a device to filter by | `String` | | callback | Called with a [`ARTPaginatedResult`](#paginated-result) object containing [`PushChannelSubscription`](https://ably.com/docs/api/realtime-sdk/push-admin.md#push-channel-subscription) objects or an error | Callback | ##### Returns Returns a promise. On success, the promise is fulfilled with [`PaginatedResult`](#paginated-result) which encapsulates an array of "PushChannelSubscription":#push-channel-subscription objects corresponding to the current page of results. [`PaginatedResult`](#paginated-result) supports pagination using [`next`](#paginated-result) and [`first`](#paginated-result) methods. On failure, the promise is rejected with an [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) object that details the reason why it was rejected. ##### Callback result On success, `resultPage` contains a [`PaginatedResult`](#paginated-result) encapsulating an array of [PushChannelSubscription](https://ably.com/docs/api/realtime-sdk/push-admin.md#push-channel-subscription) objects corresponding to the current page of results. [`PaginatedResult`](#paginated-result) supports pagination using [`next()`](#paginated-result) and [`first()`](#paginated-result) methods. On failure to retrieve message history, `err` contains an [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) object with the failure reason. ##### Returns On success, the returned [`PaginatedResult`](#paginated-result) encapsulates an array of [PushChannelSubscription](#push-channel-subscription) objects corresponding to the current page of results. [`PaginatedResult`](#paginated-result) supports pagination using [`next`](#paginated-result) and [`first`](#paginated-result) methods. Failure to retrieve the message history will raise an [`AblyException`](https://ably.com/docs/api/realtime-sdk/types.md#ably-exception) ### PushChannelSubscriptionChannelSubscriptionARTPushChannelSubscription A `PushChannelSubscription` is a type encapsulating the subscription of a device or group of devices sharing a [client identifier](https://ably.com/docs/auth/identified-clients.md) to a channel in order to receive push notifications. #### PropertiesMembers | Property | Description | Type | |----------|-------------|------| | channel | The channel that this push notification subscription is associated with | `String` | | deviceId | The device with this identifier is linked to this channel subscription. When present, `clientId` is never present | `String` | | clientId | Devices with this [client identifier](https://ably.com/docs/auth/identified-clients.md) are included in this channel subscription. When present, `deviceId` is never present | `String` | ### PushChannelSubscription constructors #### PushChannelSubscription.forDevice `PushChannelSubscription.forDevice(String channel, String deviceId) -> PushChannelSubscription` A static factory method to create a `PushChannelSubscription` object for a channel and single device. ##### Parameters | Parameter | Description | Type | |-----------|-------------|------| | channel | Channel name linked to this push channel subscription | `String` | | deviceId | The device with this identifier will be linked with this push channel subscription | `String` | ##### Returns A [`PushChannelSubscription`](https://ably.com/docs/api/realtime-sdk/types.md#push-channel-subscription) object #### PushChannelSubscription.forClient `PushChannelSubscription.forClient(String channel, String clientId) -> PushChannelSubscription` A static factory method to create a `PushChannelSubscription` object for a channel and group of devices sharing a [client identifier](https://ably.com/docs/auth/identified-clients.md). ##### Parameters | Parameter | Description | Type | |-----------|-------------|------| | channel | Channel name linked to this push channel subscription | `String` | | clientId | Devices with this [client identifier](https://ably.com/docs/auth/identified-clients.md) are included in the new push channel subscription | `String` | ##### Returns A `PushChannelSubscription` object ### PaginatedResultARTPaginatedResultio.ably.lib.types.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 an [Ably REST API paginated query](https://ably.com/docs/api/rest-api.md#pagination) is accompanied by metadata that indicates the relative queries available to the `PaginatedResult` object. #### PropertiesMembers | Property | Description | Type | |----------|-------------|------| | items | Contains the current page of results (for example an Array of [`Message`](#message) or [`PresenceMessage`](#presence-message) objects for a channel history request) | `Array ` | #### Methods ##### first `first(): Promise` `PaginatedResult first()` `first(callback: (ARTPaginatedResult?, ARTErrorInfo?) -> Void)` Returns a new `PaginatedResult` for the first page of results. Returns a promise. On success, the promise is fulfilled with a new `PaginatedResult` for the first page of results. On failure, the promise is rejected with an [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) object that details the reason why it was rejected. ##### hasNext `Boolean hasNext()` `Boolean hasNext()` `Boolean hasNext()` Returns `true` if there are more pages available by calling `next` and returns `false` if this page is the last page available. ##### isLast `Boolean isLast()` Returns `true` if this page is the last page and returns `false` if there are more pages available by calling `next`. ##### next `next(): Promise` `PaginatedResult next()` `next(callback: (ARTPaginatedResult?, ARTErrorInfo?) -> Void)` Returns a new `PaginatedResult` loaded with the next page of results. If there are no further pages, then `null``Null``nil` is returned. Returns a promise. On success, the promise is fulfilled with a new `PaginatedResult` loaded with the next page of results. If there are no further pages, then `null` is returned. On failure, the promise is rejected with an [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) object that details the reason why it was rejected. ##### current `current(): Promise` Returns a promise. On success, the promise is fulfilled with a new `PaginatedResult` loaded with the current page of results. On failure, the promise is rejected with an [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) object that details the reason why it was rejected. ##### Example ###### Javascript ``` const paginatedResult = await channel.history(); console.log('Page 0 item 0:' + paginatedResult.items[0].data); const nextPage = await paginatedResult.next(); console.log('Page 1 item 1: ' + nextPage.items[1].data); console.log('Last page?: ' + nextPage.isLast()); ``` ###### Nodejs ``` const paginatedResult = await channel.history(); console.log('Page 0 item 0:' + paginatedResult.items[0].data); const nextPage = await paginatedResult.next(); console.log('Page 1 item 1: ' + nextPage.items[1].data); console.log('Last page?: ' + nextPage.isLast()); ``` ###### Java ``` 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())); }; ``` ###### Objc ``` [channel history:^(ARTPaginatedResult *paginatedResult, ARTErrorInfo *error) { NSLog(@"Page 0 item 0: %@", paginatedResult.items[0].data); [paginatedResult next:^(ARTPaginatedResult *nextPage, ARTErrorInfo *error) { NSLog(@"Page 1 item 1: %@", nextPage.items[1].data); NSLog(@"Last page?: %d", nextPage.isLast()); }]; }]; ``` ###### Swift ``` channel.history { paginatedResult, error in guard let paginatedResult = paginatedResult else { print("No results available") return } print("Page 0 item 0: \((paginatedResult.items[0] as! ARTMessage).data)") paginatedResult.next { nextPage, error in guard let nextPage = nextPage else { print("No next page available") return } print("Page 1 item 1: \((nextPage.items[1] as! ARTMessage).data)") print("Last page? \(nextPage.isLast())") } } ```