Push Notifications
Receiving Incoming Calls via Push Notifications
To receive incoming calls via Push Notifications, the application instance has to be registered on the Sinch backend using UserController.registerUser(). Push Notifications allow reception of an incoming call even if the phone is locked, or the application is in the background or closed.
Sinch SDK supports both currently available major Push Notification platforms on Android - Google's Firebase Cloud Messages (later FCM) and Huawei Mobile Services Push Notifications (Huawei Push or HMS Push).
Note:
application instance must register itself on the Sinch backend to receive Push Notifications using either FCM or HMS.
Registering towards the Sinch backend to receive incoming call push notifications via FCM or HMS Push is quite similar and consists of several topics, which are covered below.
FCM vs HMS Push Registration Steps Comparison
| Step | FCM Specific | Notes | 
|---|---|---|
| 1. Enable support of the Managed Push in Sinch Client | Steps are identical | |
| 2. Provision your application with FCM support code | Use gooogle-services.json | Acquire files online in FCM Consoles | 
| 3. Acquire a unique device token from FCM | Automatic | |
| 4. Register the device token on the Sinch backend | Automatic | |
| 5. Implement listening service | 
 | Minor differences in the RemoteMessageAPI | 
| Step | HMS Specific | Notes | 
|---|---|---|
| 1. Enable support of the Managed Push in Sinch Client | Steps are identical | |
| 2. Provision your application with HMS support code | Use agconnect-services.json | Acquire files online in HMS Consoles | 
| 3. Acquire a unique device token from HMS | ||
| 4. Register the device token on the Sinch backend | Automatic | |
| 5. Implement listening service | 
 | Minor differences in RemoteMessageAPI | 
Google FCM Push Notifications
The following sections take you through the process of registering Google FCM push notifications:
FCM Step 1. Enable support for Managed Push
This step is the same for both FCM and HMS. To enable push notifications, set the following capability before starting the Sinch client:
SinchClient sinchClient = Sinch.getSinchClientBuilder().context(context)
                              ...
                              .build();
...
sinchClient.setSupportManagedPush(true);
sinchClient.start();️Note:
️MissingFCMException will raise if you distribute your app to devices without Google Play Services and using Firebase Cloud Messages
Note:
setSupportManagedPush(true) will register a token with the Firebase Cloud Messaging using a sender ID owned by Sinch. It won't unregister FCM tokens associated with your own sender ID. This means you can use FCM for your own purpose, filtering them in onMessageReceived(RemoteMessage remoteMessage) method of your FCM Listening Service using Sinch helper API SinchHelpers.isSinchPushPayload.
Note:
Make sure Google Play Services is installed on the device. If you distribute your application through other channels than Google Play, push notifications won't be available on devices that don't have Google Play Services.
FCM Step 2. Provision application with support code
Provisioning your application with the support code to receive the FCM Push Notifications is easy. You'll need to acquire a configuration file google-services.json from the FCM console, and add it to your project.
You can add Firebase to your app either semi-automatically using Android Studio, or manually following this step-by-step official guide. In brief, to perform manual setup, you first need to register your application in the firebase console. If your project already uses FCM, the console will prompt you to import it as a new Firebase Cloud Messaging project. Register your application using the console, and download relevant google-services.json into your project’s main folder.
Sample SDK projects sinch-rtc-sample-push and sinch-rtc-sample-video-push will require you to supply your own google-services.json in order to be built. In the absence of this file, gradle will show a relevant error with explanation and relevant links and stop the build. That google-services.json file is the main mean of automatization of support of Firebase services to your app. Android Studio’s plugin com.google.gms.google-services parses and adds relevant resources and permissions to your applications manifest automatically.
FCM Step 3. Acquire FCM device token
This step is performed automatically when you call UserController.registerUser() on the next step.
FCM Step 4. Register FCM device token on Sinch backend
Create an instance of the UserController using the UserControllerBuilder and call UserController.registerUser() to acquire and register the FCM token on the Sinch Backend, and wait for the callbacks that reports whether registration succeeded. Please see dedicated UserContoller documentation here.
UserController userController = Sinch.getUserControllerBuilder()
                .context(getApplicationContext())
                .applicationKey("<application key>")
                .userId("<user id>")
                .environmentHost("ocra.api.sinch.com")
                .build();
// parameters are `UserRegistrationCallback` 
// and `PushTokenRegistrationCallback`
userController.registerUser(this, this); FCM Step 5. Implement Listening Service
Implement your FcmListerningService by extending the FirebaseMessagingService:
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
...
public class FcmListenerService extends FirebaseMessagingService {
@Override
public void onMessageReceived(RemoteMessage remoteMessage){
    if (SinchHelpers.isSinchPushPayload(remoteMessage.getData())) {
        NotificationResult result = sinchClient.relayRemotePushNotificationPayload(
                                  remoteMessage.getData());
        ...
    } else {
        // it's NOT Sinch message - process yourself
    }
  }}Huawei HMS Notifications
The following sections take you through the process of registering Huawei HMS push notifications:
Prerequisites
To use Huawei Push notifications you must also implement the Huawei OAuth 2.0 Flow.
HMS Step 1. Enable support for Managed Push
This step is the same for both FCM and HMS. To enable push notifications, set the following capability before starting the Sinch client:
SinchClient sinchClient = Sinch.getSinchClientBuilder().context(context)
                              ...
                              .build();
...
sinchClient.setSupportManagedPush(true);
sinchClient.start();Note:
Using the HMS Push platform requires that the Huawei Mobile Services is installed on the device. The UI prompt to install the HMS will appear automatically the very first time a unique HMS device token is being acquired.
HMS Step 2. Provision application with support code
Follow the Huawei Push Kit Devlopment Process to acquire agconnect-services.json. Refer to How to Integrate HMS Core SDK for the necessary changes in the gradle build files.
HMS Step 3. Acquire HMS device token
Unlike FCM, Sinch SDK expects the application to acquire the HMS device token before creating UserController. A good example of how to acquire an HMS device token asynchronously is provided in the RegisterToHmsTask class of the sinch-rtc-sample-hms-push sample application.
The task extends AsyncTask and returns both known beforehand mHmsApplicationId and unique mHmsDeviceToken, which Huawei recommends to re-acquire on each application start. To read the HMS Application ID and acquire the HMS Device token, use following methods:
String hmsApplicationId = AGConnectServicesConfig.fromContext(context)
                                                 .getString("client/app_id");
String hmsDeviceToken = HmsInstanceId.getInstance(context)
                                     .getToken(appId, "HCM");️Note:
For this operation to succeed, your application must be signed and its signature fingerprint registered in the Huawei AGConnect console. To learn more, please follow this link.
Checklist for Obtaining the HMS Device Token
- Application is registered on Huawei AGConnect Console (IMPORTANT: package name should match).
- The AGConnect Console's application project has PushKit enabled.
- The application is signed .
- Fingerprint of the signature is registered in the AGConnect Console .
- HMS is installed on the device (User will get UI Prompt automatically).
- Device is connected to the internet.
HMS Step 4. Register HMS device token on Sinch backend
Create an instance of the UserController using the UserControllerBuilder and sub-builder HmsPushBuilder, accessible via UserControllerBuilder.hms() method. Then call UserController.registerUser() to acquire and register the HMS token on the Sinch backend, and wait for the callbacks that reports whether registration succeeded. Please see dedicated UserContoller documentation here.
UserController userController = Sinch.getUserControllerBuilder()
                    .context(getApplicationContext())
                    .applicationKey("<application key>")
                    .userId("<user id>")
                    .environmentHost("ocra.api.sinch.com")
                    .hms()
                        .deviceToken(hmsDeviceToken)
                        .applicationId(hmsApplicationId)
                        .done()
                    .build();
// parameters are `UserRegistrationCallback` 
// and `PushTokenRegistrationCallback`
userController.registerUser(this, this); HMS Step 5. Implement Listening Service
Implement your HmsListerningService by extending the HmsMessageService:
import com.huawei.hms.push.HmsMessageService;
import com.huawei.hms.push.RemoteMessage;
...
public class HmsListenerService extends HmsMessageService {
@Override
public void onMessageReceived(RemoteMessage remoteMessage){
    if (SinchHelpers.isSinchPushPayload(remoteMessage.getDataOfMap())) {
        NotificationResult result = sinchClient.relayRemotePushNotificationPayload(
                                  remoteMessage.getDataOfMap());
        ...
    } else {
        // it's NOT Sinch message - process yourself
    }
  }}Sample Applications
As a developer, you will be responsible for implementing the code that receives the push message.
- 
For FCM example, please see the sample apps 
sinch-rtc-sample-pushandsinch-rtc-sample-video-push.
- 
For HMS example, please see the sample app 
sinch-rtc-sample-hms-push.
The following sections cover how to support receiving calls and messages via push notifications.
Receive and Forward Push Notifications to a Sinch Client
Once you have received the RemoteMessage in your listening service, and forwarded it to the Sinch client using the method SinchClient.relayRemotePushNotificationPayload, you'll get a NotificationResult, which can be inspected to further confirm that the push is valid and associated with an incoming call using NotificationResult.isCall().
If the payload that was forwarded to the Sinch client is a valid Sinch call, the onIncomingCall callback will automatically be triggered as for any other call. Notification result can be further examined using NotificationResult.getCallResult() object provides details about participants, whether the call timed out and whether the call offers video.
Send and Receive Custom Headers via Sinch Managed Push
The Sinch SDK supports adding custom headers in push notification messages when initiating a call, so developers don't need to implement their own push mechanism if they only need to deliver small pieces of information along the Sinch managed push between their app instances. The Sinch SDK allows up to 1024 bytes of custom headers.
Setting custom headers on the sender side when initiating a call:
// setting up custom headers
Map<String,String> headers = new HashMap<>();
headers.put("The first value is ", "@123");
headers.put("Custom value ", "two!");
Call call = callClient.callUser(userId, headers);If custom headers were supplied by call initiator, they can be retrieved from notification result using getHeaders() API:
// make sure you have created a SinchClient
if (SinchHelpers.isSinchPushPayload(remoteMessage.getData())) {
  NotificationResult result = sinchClient.relayRemotePushNotificationPayload(remoteMessage.getData());
  // For HMS use remoteMessage.getDataOfMap() API instead:
  // NotificationResult result = sinchClient.relayRemotePushNotificationPayload(remoteMessage.getDataOfMap());
  if (result.isCall()) {
    CallNotificationResult callResult = result.getCallResult();
    Map<String, String> customHeaders = callResult.getHeaders());
  }
}Note:
It's possible to retrieve custom headers from the push message using SinchHelpers.queryPushNotificationPayload without starting the client.
// SinchClient is not needed to be created at all!
if (SinchHelpers.isSinchPushPayload(remoteMessage.getData())) {
  NotificationResult result = SinchHelpers.queryPushNotificationPayload(applicationContext, remoteMessage.getData());
  // For HMS use remoteMessage.getDataOfMap() API instead:
  // NotificationResult result = sinchClient.relayRemotePushNotificationPayload(remoteMessage.getDataOfMap());
  if (result.isCall()) {
    CallNotificationResult callResult = result.getCallResult();
    Map<String, String> customHeaders = callResult.getHeaders());
    // analyse headers, decide whether to process message/call and start Sinch client or ignore
    ...
  }
}Unregister a Device
If the user of the application logs out or performs a similar action, which implies that this device shouldn't receive incoming calls push notifications any longer, the push notification device token can be unregistered via UserController.unregisterPushToken().
️Note:
If your application assumes frequent change of users (logging in and out), it's imperative to unregister the device by using UserController.unregisterPushToken() on each log out to guarantee that a new user won't receive incoming calls intended to the previous one.
GCM to FCM Migration
Sinch SDK moved from deprecated Google Cloud Messaging (GCM) to its most up-to-date and Google-recommended version Firebase Cloud Messaging (FCM), which requires client app to be modified in accordance with the Google’s official GCM to FCM migration guide
Permissions Required
You don't need to manually add any permission to the application manifest - all required changes will be added automatically by the gradle depending on the configuration file you provide (google-service.json or agconnect-services.json).
Huawei OAuth 2.0 Flow
Sinch supports Huawei push messages via Huawei Push Kit (HPK) which is part of Huawei Mobile Services (HMS). The Sinch SDKs and platform can take care of sending push notification messages via Huawei Push Kit on your behalf as part our Sinch Managed Push Notifications functionality. To enable Huawei push messages for Android devices you will need to do two things:
- Make use of the Huawei ( HMS ) APIs in the Sinch Android SDK as described above .
- Implement an OAuth 2.0 Authorization Server endpoint that can provide Sinch with OAuth 2.0 access_tokens required to send messages via HPK on your behalf.
Sinch will send push notification messages via the Huawei Push Kit API. Huawei Push Kit supports (and requires) an OAuth 2.0 Client Credentials flow to authenticate against the Huawei Push Kit server endpoint(s). Your Huawei app in Huawei AppGallery Connect will have an App ID and an App secret. These are to be used as OAuth client credentials: client_id and client_secret respectively.
Sinch supports Huawei OAuth flow by delegation. You will keep your client_secret on your backend, and Sinch will request an HMS OAuth access_token via an server-side HTTP API endpoint that you implement. Sinch supports two different alternatives for how to provide Sinch with an HMS access token:
- A) A HMS token endpoint protected by a standard OAuth 2.0 Client Credentials flow. This is a good fit if you have an existing OAuth 2.0 Authorization Server that's used to protect and grant access access to your server-side endpoints.
- B) A HMS token endpoint protected using your existing Sinch credentials (Sinch Application Key and Application Secret ). This is a good fit if you don't have an OAuth 2.0 Authorization Server to grant access to your server-side endpoints.
Alt A) Huawei OAuth Flow Using Your OAuth 2.0 Domain
This flow assumes you have an OAuth 2.0 conforming Authorization Server that supports the Client Credentials grant type.
The flow is implemented in terms of two key steps:
- You create a set of OAuth 2.0 Client Credentials that are valid within your OAuth domain, and configure those for your Sinch Application .
- 
You implement a HMS token endpoint that provides a HMS access token (labeled 
$push_token_endpointin diagram below).
In the Sinch Dashboard you should configuring the following:
- OAuth 2.0 access token endpoint (URL)
- 
Client Credentials
 (
client_idandclient_secret)
- 
An OAuth 
scope
 (optional to specify, will default to 
https://push-api.cloud.huawei.com)
- HMS token endpoint (URL)
The overall flow is depicted below:

Key takeaways:
- The component labeled Your Resource Server in the diagram is your Resource Server in the terminology of OAuth and the resource here being an HMS access token .
- 
When Sinch needs a (new) HMS 
access_tokenrequired to send a push message to Huawei Push Kit server, it will first make a request to your Authorization Server to obtain anaccess_tokenvalid for your security domain (labeled asaccess_token_ROin the diagram, RO as in Resource Owner ).
- 
Having obtained 
access_token_RO, Sinch will make a subsequent request to your HMS access token endpoint (labeled$push_token_endpointin the diagram), providingaccess_token_ROas a Bearer token.
- 
Your 
Resource Server
 should obtain a HMS 
access_tokenusing the Huawei HMS OAuth Authorization Server endpoint and your Huawei App ID and App secret asclient_idandclient_secret.
- 
Your 
Resource Server
 should pass the HMS 
access_token(as received from HMS) in the response back to Sinch.
Sinch will only make requests to your Authorization Server access token endpoint and your HMS token endpoint as needed, not for every push message sent. Sinch will cache the HMS access token in accordance to the value of expires_in.
Note:
You can think of the step where you configure OAuth Client Credentials for your Sinch Application as a way of enabling Sinch and your Sinch Application in particular to make requests to your HMS token endpoint (Resource Server).
Implementing the HMS Token Endpoint
As described in the overview, Sinch will make a request to your Resource Server HMS token endpoint, requesting a HMS access_token. The request will be on the following form:
    POST /<your HMS token endpoint>
    Authorization: Bearer <Access token obtained from your Authorization Server>
    Content-Type: application/x-www-form-urlencoded
    grant_type=client_credentials&
    hms_application_id=<Your HMS App Id>Your implementation of this resource endpoint should obtain an HMS access_token using the Huawei HMS OAuth endpoint, using your Huawei App ID and App secret as client_id and client_secret. The access token received from Huawei should then be included in the response back to Sinch. See Huawei documentation for how to implement requesting an OAuth access token using Huawei HMS.
Example response to Sinch:
    HTTP/1.1 200 OK
    Content-Type: application/json;charset=utf-8
    {
      "access_token": "<access token acquired from Huawei>",
      "expires_in": 3600,
      "token_type": "Bearer"
    }Sinch will then be able to use this access_token to send push messages to your end-user devices until the token expires, upon which Sinch will issue a new token request to your Authorization Server and Resource Server.
Attention!
You will receive your HMS App ID as a request parameter (hms_application_id) and you can use that for a given request to map it to your corresponding HMS App.
Note: ️
Alt B) Huawei OAuth Flow Using Sinch Application Credentials
The overall flow is depicted below:

Key takeaways:
- 
When Sinch needs an 
access_tokenrequired to send a push message to Huawei Push Kit server, it will make an OAuth request using a Client Credentials grant type to your Authorization Server . This request will be specifying anclient_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-beareras the value forclient_assertionprovides a JWT that's symmetrically signed with your Sinch Application Secret .
- 
Your 
Authorization Server
 should validate the JWT provided as 
client_assertionby Sinch and that the signed JWT is signed with your Sinch Application Secret .
- 
Your 
Authorization Server
 should obtain a HMS 
access_tokenusing the Huawei HMS OAuth Authorization Server endpoint and your Huawei App ID and App secret asclient_idandclient_secret.
- 
Your 
Authorization Server
 should pass the HMS 
access_token(as received from HMS) in the response back to Sinch.
Sinch will only make requests to your Authorization Server access token endpoint and your HMS token endpoint as needed and not for every push message sent. Sinch will cache the HMS access token in accordance to the value of expires_in.
Details on how to validate the JWT provided by Sinch as client_assertion are available in the following sections.
(The use of client_assertion and client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer is based on RFC 7523 and RFC 7521 and part of the OpenID Connect Core 1.0 standard.)
Validating the client_assertion JWT provided by Sinch
As described in the overview, Sinch will make a request to your OAuth Authorization Server endpoint, requesting a HMS access_token. The request will be on the following form:
    POST /sinch/rtc/push/oauth2/v1/huawei-hms/token HTTP 1.1
    Host: as.your-domain.com
    Content-Type: application/x-www-form-urlencoded
    grant_type=client_credentials&
    scope=https%3A%2F%2Fpush-api.cloud.huawei.com&
    client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer
    client_assertion=<JWT>Note:
The value of scope and client_assertion_type in the example above are URL-encoded
The JWT will be making use of the standard JWT header parameters alg and kid, and the standard claims iss, sub, iat, exp, nonce and aud. Before we jump to the details of how to validate this token, here is an example:
    // JWT Header (example)
    {
      "alg": "HS256",
      "kid": "hkdfv1-20200901",
      "sinch:rtc:application_key": "a32e5a8d-f7d8-411c-9645-9038e8dd051d"
    }
    // JWT Payload (example)
    {
      "iss": "//rtc.sinch.com/applications/a32e5a8d-f7d8-411c-9645-9038e8dd051d",
      "sub": "123456789",
      "aud": "https://as.your-domain.com/sinch/rtc/push/oauth2/v1/huawei-hms/token",
      "scope": "https://push-api.cloud.huawei.com",
      "sinch:rtc:application_key": "a32e5a8d-f7d8-411c-9645-9038e8dd051d",
      "iat": 1600780504,
      "exp": 1600784104,
      "nonce": "6b438bda-2d5c-4e8c-92b0-39f20a94b34e"
    }- 
Claim 
issis on the form//rtc.sinch.com/applications/<your Sinch Application Key>(canonical form)
- 
Claim 
subis your HMS App ID (as specified viaHmsPushBuilder.applicationId(String)on the Android client).
- 
Claim 
audwill be set to the Authorization Server token endpoint you have configured with Sinch. examplehttps://as.your-domain.com/sinch/rtc/push/oauth2/v1/huawei-hms/token
- 
Claim 
scopewill behttps://push-api.cloud.huawei.com(representing the Huawei Push Kit server domain)
- 
Claim 
sinch:rtc:application_keywill contain your Sinch Application Key ` .
- 
Claims 
iat,exp,nonceare standard JWT claims (see JWT RFC 7519 )
Note:
Your Sinch Application Key is present both in the JWT header and the JWT payload (as header parameter and claim sinch:rtc:application_key). The reason, is that it allows you to implement validating the JWT signature without accessing the payload, and once you have validated the JWT signature, you can strip away the header and all the data you need for further processing is self contained in the payload.
kid and Deriving a Signing Key from Sinch Application Secret
The kid parameter in the JWT header is on the form hkdfv1-{DATE} where {DATE} is date of signing in UTC on format YYYYMMDD.
When validating the JWT, use a signing key that's derived from your Sinch Application Secret as follows. Given:
- 
A function 
HMAC256(key, message).
- 
A date-formatting function 
FormatDate(date, format).
- 
The date of signing as variable 
signedAt. This is to be extracted from the JWT header parameterkid.
- 
Sinch Application Secret
 as variable 
applicationSecret, holding the secret as a base64 encoded string.
Derive the signing key as follows:
signingKey = HMAC256(BASE64-DECODE(applicationSecret), UTF8-ENCODE(FormatDate(signedAt, "YYYYMMDD")))Note:
This is the same key derivation scheme as used for Token-based User registration
Validating the JWT
Your Authorization Server should validate the JWT in accordance with section RFC 7523 - Section 3. JWT Format and Processing Requirements. Here is a rough outline of the steps necessary:
- 
Use JWT header parameter 
sinch:rtc:application_keyto lookup your corresponding Application Key and Application Secret (at this point the token is still unvalidated)
- Derive the signing key (as detailed in the previous section)
- Validate that the JWT has a valid signature given the signing that you have derived.
- 
Validate the JWT payload in terms of 
iat,exp,nonceetc.
- 
Validate that the claim 
scopeishttps://push-api.cloud.huawei.com
Examples of JWT creation
Visit https://github.com/sinch/sinch-rtc-api-auth-examples for example implementations of JWT generation.
Acquiring an access_token from Huawei HMS
After validating the JWT client assertion, your Authorization Server should in turn request an access_token from the Huawei HMS OAuth endpoint, using your Huawei App ID and App secret as client_id and client_secret. The access token received from Huawei should then be included in the response back to Sinch. See Huawei documentation for how to implement requesting an OAuth access token using Huawei HMS.
Example response to Sinch:
    HTTP/1.1 200 OK
    Content-Type: application/json;charset=utf-8
    {
      "access_token": "<access token acquired from Huawei>",
      "expires_in": 3600,
      "token_type": "Bearer"
    }Sinch will then be able to use this access_token to send push messages to your end-user devices until the token expires, upon which Sinch will issue a new token request to your Authorization Server.
Note:
You will receive your HMS App ID in JWT claim sub and you can use that to for a given request map it to your corresponding HMS App. You will also be able to access your Sinch Application Key as the JWT claim sinch:rtc:application_key if you need that as input at this stage.
Rejecting the access_token grant request
If your Authorization Server rejects the access token request from Sinch, it should respond with a HTTP response that's compliant with the OAuth 2.0 standard. Example:
    HTTP/1.1 400 Bad Request
    Content-Type: application/json;charset=utf-8
    {
      "error": "unauthorized_client",
      "error_description": "Your helpful error description"
    }Please see https://www.oauth.com/oauth2-servers/access-tokens/access-token-response/ for details on how to formulate conformant OAuth error responses.
More Resources on Huawei Push and OAuth
- Examples how to validate a client assertion JWT at https://github.com/sinch/sinch-rtc-api-auth-examples .
- Huawei HMS OAuth Client Credentials Flow
- OAuth 2.0 Client Credentials
- 
OAuth client_secret_jwt
- RFC 7523 - JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants
- RFC 7521 - Assertion Framework for OAuth 2.0 Client Authentication and Authorization Grants
Active Connection
If push notifications are not desired, the alternative is to use active connection. Invoke SinchClient.startListeningOnActiveConnection().
️Note:
Listening on the active connection in a background service is not guaranteed started from Android 9. Android OS can stop background services at any moment. Use managed push functionality to receive incoming calls from the background or when the application is stopped (but not force stopped).