Getting the device identifier
Before invoking any Webcom API for subscribing through mobile push notifications, your app must provide the Webcom SDK with the device identifier. Getting this identifier must rely on the API of either the FCM library for Google-compliant Android devices and iOS devices or the HMS library for Huawei non Google-compliant Android devices.
In the FCM and HMS APIs, the device identifier we need is called FCM token or HMS token.
Some configuration steps are required in your Android Studio project prior to using the FCM or HMS library.
At startup in your main Activity:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// ...
// For FCM:
FirebaseMessaging.getInstance().token.addOnSuccessListener { // it: String
Webcom.deviceIdentifier = Webcom.DeviceIdentifier.Firebase(it)
}
// // For HMS:
// val appId = AGConnectServicesConfig.FromContext(this@MainActivity).getString("client/app_id")
// val token = HmsInstanceId.getInstance(this@MainActivity).getToken(appId, DEFAULT_TOKEN_SCOPE)
// if (!token.isNullOrEmpty()) Webcom.deviceIdentifier = Webcom.DeviceIdentifier.Huawei(token)
// ...
Webcom.whenSdkIsInitialized {
// ...
}
}
}
As the FCM or HMS token may change over time, it is also necessary to update the device identifier from the
onNewToken(...)
callback of the Firebase or HMS messaging service:
// For FCM:
class MyMessagingService : FirebaseMessagingService() {
// ...
override fun onNewToken(token: String) {
Webcom.deviceIdentifier = Webcom.DeviceIdentifier.Firebase(token)
}
// ...
}
// For HMS:
class MyMessagingService : HmsMessageService() {
// ...
override fun onNewToken(token: String?, bundle: Bundle?) {
if (!token.isNullOrEmpty()) Webcom.deviceIdentifier = Webcom.DeviceIdentifier.Firebase(token)
}
// ...
}
When the FCM or HMS token is renewed by the messaging service library (i.e. the
onNewToken(...)
callback is called), your application should remove all subscriptions previously added using the previous token and possibly add all relevant ones again using the new token.
import Firebase
// make the AppDelegate conforms to UNUserNotificationCenterDelegate and MessagingDelegate
final class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, MessagingDelegate {
// complete the `application(_:didFinishLaunchingWithOptions:)` method:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
Messaging.messaging().delegate = self
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { _, _ in }
application.registerForRemoteNotifications()
return true
}
// add the following method in the AppDelegate:
func messaging(_ messaging: Messaging, didReceiveRegistrationToken firebaseMessagingToken: String) {
Webcom.deviceToken = firebaseMessagingToken
}
}
When the FCM token is renewed by the messaging service library (i.e. the
messaging(_:didReceiveRegistrationToken:)
delegate method is called), your application should remove all subscriptions previously added using the previous token and possibly add all relevant ones again using the new token. To achieve that, it may use theupdateDeviceTokenInAllSubscriptions(file:line:session:queue:then:)
method.
Adding a subscription
With respect to subscription through realtime notifications, subscriptions through mobile push notifications have some limitations:
- The size of the payload notifications sent through the targeted messaging service (FCM, APNs or HMS) is limited to 4 KBytes. If the size of the data to send is too large, the Webcom back end will "simplify" the notification content before sending it to the messaging service, and the client application, when receiving it, will have to query back the Webcom back end (typically using the standard read functions of the Webcom SDK) to retrieve the relevant data.
- The size of the path of the subscribed data node is limited to 2048 bytes (including all
/
characters). - As this kind of subscription is aimed at remaining active even when the user closes her·his application on the mobile device (because such subscriptions are able to launch or wake up a closed or paused app), it must be limited in time. The default validity period of subscriptions is set up in the Webcom developer console ("notifications" tab) of a subscription. A subscription may also request a specific duration.
- As notifications are relayed through third-party messaging services (FCM, APNs or HMS), their content should be ciphered to prevent from data leakages.
- Subscribing requires a valid ongoing authentication. If no user is authenticated, then any subscription at any data node will fail.
- Only one subscription can be done at a given data node with a given authentication. If another subscription is requested at the same data node with the same authentication, it automatically cancels and overwrites the previous one.
- Although the same event types may be subscribed as with realtime notifications (value change, child addition, child change and child removal), no data subset may be queried.
In Kotlin, subscribing through push mobile notifications is similar to subscribing through realtime notifications:
import com.orange.webcom.sdk.datasync.subscription.SubscribableEvent.*
val app = WebcomApplication.default
val manager = app.datasyncService.createManager()
val node = manager / "contacts"
var subscription: Subscription
node.subscribeThroughPushNotification(Value.Changed::class) { // it: WebcomResult<Subscription>
when (it) {
is WebcomResult.Success -> // the subscription has been accepted by the back end
subscription = it.result
is WebcomResult.Failure ->
println("The subscription on CONTACTS has been rejected! ${it.error.message}")
}
}
The event type to subscribe to is specified by the Kotlin class of one of the
SubscribableEvent
sub-interfaces.
By default, subscriptions will not cipher notifications. To do so, you must specify the cipher
argument of the
subscribeThroughPushNotification
method.
The expirationDate
or duration
parameters make it possible to limit the subscription to a specific validity
period. If not set, the default duration set up in the "notification" tab of the Webcom developer console is used.
Finally, the includesRevocation
parameter allows notifying client applications when the subscription is revoked
(because either it is expired or the client app explicitly unsubscribes).
You need to use a DataNode
instance:
let node = Webcom.defaultApplication.dataService.node(for: "some/webcom/path")
let descriptor = DataSubscriptionDescriptor(eventType: .valueChange)
node.subscribeThroughNotifications(descriptor: descriptor) { result in
switch result {
case .success:
print("subscription succeeded")
case let .failure(error):
print("subscription error:", error)
}
}
Subscribing is implemented in REST using a POST request:
WEBCOM_APP="<your-app>"
AUTH_TOKEN="<Webcom-authentication-token>" # subscriptions require a valid authentication context
UID="<UID-of-the-user-authenticated-by-the-AUTH-TOKEN>"
KIND="mobile" // for google/fcm
KIND="huawei" // for HMS push kit
DEVICE_ID="<FCM-or-HMS-token>"
curl -X POST "https://io.datasync.orange.com/datasync/v2/$WEBCOM_APP/subscriptions/$UID?allowsUpdate=true" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AUTH_TOKEN" \
-d '{"notifFormatVersion": "v2", "kind":"'$KIND'", "mode":"value", "path":"/", "context":"'$DEVICE_ID'"}'
The JSON document passed in the request body may contain the following additional properties:
- The
mode
andchildEventFilter
properties specify the subscribed event type (note that the latter property may combine several child events):
mode |
childEventFilter |
Subscribed event type |
---|---|---|
"value" |
Value Change | |
"noData" |
Value Change, except that the data of the subscribed node is never included within the sent notifications | |
"chidEvent" |
{"added":true} |
Child Addition |
"chidEvent" |
{"changed":true} |
Child Change |
"chidEvent" |
{"removed":true} |
Child Addition |
- The
encryption
property requests the back end to cipher the sent notifications. Possible values are:{"alg":"none"}
(default, i.e. no encryption),{"alg":"A128CBC-HS256"}
,{"alg":"A192CBC-HS384"}
,{"alg":"A256CBC-HS512"}
,{"alg":"none"}
. - The
receivesRevocations
boolean property controls whether client applications are notified when the subscription is revoked (because either it is expired or the client app explicitly unsubscribes).
If not set, revocations will be notified. - The
expirationTimestampSeconds
numeric property assigns a specific duration to the subscription.
If not set, the default duration set up in the "notification" tab of the Webcom developer console is used.
When successful, the REST request returns a JSON document containing a referential description of the just created
subscription. In particular, the id
property gives the identifier of the subscription, to use further with other
REST requests to update or delete the subscription.
The received JSON document may be further retrieved using a GET request:
SUBSCRIPTION_ID="<the-id-received-at-subscription>"
curl -X GET "https://io.datasync.orange.com/datasync/v2/$WEBCOM_APP/subscriptions/$UID/$SUBSCRIPTION_ID" \
-H "Authorization: Bearer $AUTH_TOKEN"
Refreshing a subscription
If you need to extend a subscription beyond its expiration date, you have to refresh it before this date. As the Webcom back end manages at most one subscription per data node, authentication state and device, refreshing a subscription simply consists in adding a new one (therefore using the same API as shown in the previous section) to the same data node with the same authentication state.
For the REST API, refreshing a subscription is possible only if the allowsUpdate=true
query parameter has been passed
to the first adding request. Refreshing may also be done using a PUT request (see the REST
API).
Removing a subscription
Removing a subscription may be done like this (replace “<your-app>” with your actual application identifier):
In Kotlin, there are two ways of removing subscriptions through mobile push notifications:
- Either you still hold the
Subscription
object previously returned by thesubscribeThroughPushNotification(...)
method. In this case, simply call itscancel()
method:
subscription.cancel()
- Or you don't hold the
Subscription
object. In this case, you can remove any existing subscription at a given data node:
val app = WebcomApplication.default
val manager = app.datasyncService.createManager()
val node = manager / "contacts"
node.cancelSubscriptionsThroughPushNotification { // it: WebcomResult<Subscription>
when (it) {
is WebcomResult.Success -> println("The subscriptions on CONTACTS have been canceled")
is WebcomResult.Failure -> println("The cancelation of subscriptions on CONTACTS has failed! ${it.error.message}")
}
}
In Swift, there are two ways of removing subscriptions through mobile push notifications:
- Either you still hold the
DataSubscription
object. In this case, simply call itscancel()
method:
let node = ...
let descriptor = ...
let subscription = node.subscribeThroughNotifications(descriptor: descriptor) ...
subscription.cancel() { result in
switch result {
case .success:
print("unsubcription succeeded")
case let .failure(error):
print("unsubcription error:", error)
}
}
- Or you don't hold the
DataSubscription
object. In this case, you can remove any existing subscription at a givenDataNode
:
let node = Webcom.defaultApplication.dataService.node(for: "some/webcom/path")
node.dataNode.unsubscribeFromNotifications { result in
switch result {
case .success:
print("unsubcription succeeded")
case let .failure(error):
print("unsubcription error:", error)
}
}
In REST, there are two ways of removing subscriptions through mobile push notifications:
- Either you still hold the subscription identifier returned by the request that previously added the subscription. In this case simply use a DELETE request. Note that the provided authentication token must refer to the same user UID as the one used to add the subscription:
WEBCOM_APP="<your-app>"
AUTH_TOKEN="<Webcom-authentication-token>" # an authentication context with the user identifier of the user that has added the subscription to remove
SUBSCRIPTION_ID="<the-subscription-ID-returned-when-added-the-subscription>"
curl -X DELETE "https://io.datasync.orange.com/datasync/v2/$WEBCOM_APP/subscriptions/$UID/$SUBSCRIPTION_ID" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AUTH_TOKEN"
- Or you don't hold the subscription identifier.
In this case, the request is the same as the one to add a subscription, with the
expirationTimestampSeconds
property of the passed JSON body set to0
. Note also that the provided authentication token must refer to the same user UID as the one used to add the subscription:
UID="<UID-of-the-user-authenticated-by-the-AUTH-TOKEN>"
KIND="mobile" // for google/fcm
KIND="huawei" // for HMS push kit
DEVICE_ID="<FCM-or-HMS-token>"
curl -X POST "https://io.datasync.orange.com/datasync/v2/$WEBCOM_APP/subscriptions/$UID?allowsUpdate=true" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AUTH_TOKEN" \
-d '{"kind":"'$KIND'", "mode":"value", "path":"/", "context":"'$DEVICE_ID'", expirationTimestampSeconds:0}'