# 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())")
}
}
```