How to Push Messages to Devices of Different Manufacturers
Tags: java, programming, tutorial
Published: 2022-06-21 09:24:36

Push messaging, with the proliferation of mobile Internet, has become a very effective way for mobile apps to achieve business success because it improves user engagement and stickiness by allowing developers to send messages to a wide range of users in a wide range of scenarios: taking the subway or bus, having a meal in a restaurant, having a chat... you name it. No matter what the scenario is, a push message is always a great helper for you to directly "talk" to your users, and for your users to know something informative.

Such great benefits brought by push messages, however, can be dampened by a challenge: the variety of mobile phone manufacturers. This is because usually each manufacturer has their own push messaging channels, which increases the difficulty for uniformly sending your app's push messages to mobile phones of different manufacturers. Of course there is an easy solution for this: sending your push messages to mobile phones of only one manufacturer, but this can limit your user base and prevent you from obtaining your desired messaging effects.

Then this well explains why we developers usually need to find a solution for our apps to be able to push their messages to devices of different brands.

I don't know about you, but the solution I found for my app is [HMS Core Push Kit](https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/service-introduction-0000001050040060?ha_source=hms1). Going on, I will demonstrate how I have integrated this kit and used its ability to aggregate third-party push messaging channels to implement push messaging on mobile phones made by different manufacturers, expecting greater user engagement and stickiness. Let's move on to the implementation.

## Preparations
Before integrating the SDK, make the following preparations:
1) Sign in to the push messaging platform of a specific manufacturer, create a project and app on the platform, and save the JSON key file of the project. (The requirements may vary depending on the manufacturer, so refer to the specific manufacturer's documentation to learn about their requirements.)
2) [Create an app](https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/android-config-agc-0000001050170137?ha_source=hms1) on a platform, but use the following build dependency instead when configuring the build dependencies:

```
dependencies {
    implementation 'com.huawei.hms:push-fcm:6.3.0.304'
}
```
3) On the platform mentioned in the previous step, click **My projects**, find the app in the project, and go to **Grow** > **Push Kit** > **Settings**. On the page displayed, click **Enable** next to **Configure other Android-based push**, and then copy the key in the saved JSON key file and paste it in the **Authentication parameters** text box.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xmhpg0rk7cps4re6q7dh.png)

## Development Procedure
Now, let's go through the development procedure.
1) Disable the automatic initialization of the SDK.
To do so, open the **AndroidManifest.xml** file, and add the **<meta-data>** element to the **<application>** element. Note that in the element, the **name** parameter has a fixed value of **push_kit_auto_init_enabled**. As for the **value** parameter, you can set it to **false**, indicating that the automatic initialization is disabled.

```
<manifest ...>
    ...
    <application ...>      
        <meta-data
            android:name="push_kit_auto_init_enabled"
            android:value="false"/>
        ...
    </application>
    ...
</manifest>
```
2) Initialize the push capability in either of the following ways:

- Set **value** corresponding to **push_kit_proxy_init_enabled** in the **<meta-data>** element to **true**.

```
    <application>
        <meta-data
            android:name="push_kit_proxy_init_enabled"
            android:value="true" />
    </application>
```

- Explicitly call **FcmPushProxy.init** in the **onCreate** method of the **Application** class.

3) Call the **getToken** method to apply for a token.

```
private void getToken() {
    // Create a thread.
    new Thread() {
        @Override
        public void run() {
            try {
                // Obtain the app ID from the agconnect-services.json file.
                String appId = "your APP_ID";

                // Set tokenScope to HCM.
                String tokenScope = "HCM";
                String token = HmsInstanceId.getInstance(MainActivity.this).getToken(appId, tokenScope);
                Log.i(TAG, "get token: " + token);
                
                // Check whether the token is empty.
                if(!TextUtils.isEmpty(token)) {
                    sendRegTokenToServer(token);
                }
            } catch (ApiException e) {
                Log.e(TAG, "get token failed, " + e);
            }
        }
    }.start();
}
private void sendRegTokenToServer(String token) {
    Log.i(TAG, "sending token to server. token:" + token);
}
```
4) Override the **onNewToken** method.
After the SDK is integrated and initialized, the **getToken** method will not return a token. Instead, you'll need to obtain a token by using the **onNewToken** method.

```
@Override
public void onNewToken(String token, Bundle bundle) {
    Log.i(TAG, "onSubjectToken called, token:" + token );
}
```
5) Override the **onTokenError** method.
This method will be called if the token fails to be obtained.

```
@Override
public void onTokenError(Exception e, Bundle bundle) {
    int errCode = ((BaseException) e).getErrorCode();
    String errInfo = e.getMessage();
    Log.i(TAG, "onTokenError called, errCode:" + errCode + ",errInfo=" + errInfo );
}
```
6) Override the **onMessageReceived** method to receive data messages.

```
@Override
public void onMessageReceived(RemoteMessage message) {
    Log.i(TAG, "onMessageReceived is called");

    // Check whether the message is empty.
    if (message == null) {
        Log.e(TAG, "Received message entity is null!");
        return;
    }

    // Obtain the message content.
    Log.i(TAG, "get Data: " + message.getData()
            + "\n getFrom: " + message.getFrom()
            + "\n getTo: " + message.getTo()
            + "\n getMessageId: " + message.getMessageId()
            + "\n getSentTime: " + message.getSentTime()
            + "\n getDataMap: " + message.getDataOfMap()
            + "\n getMessageType: " + message.getMessageType()
            + "\n getTtl: " + message.getTtl()
            + "\n getToken: " + message.getToken());

    Boolean judgeWhetherIn10s = false;
    // Create a job to process a message if the message is not processed within 10 seconds.
    if (judgeWhetherIn10s) {
        startWorkManagerJob(message);
    } else {
        // Process the message within 10 seconds.
        processWithin10s(message);
    }
}
private void startWorkManagerJob(RemoteMessage message) {
    Log.d(TAG, "Start new job processing.");
}
private void processWithin10s(RemoteMessage message) {
    Log.d(TAG, "Processing now.");
}
```
7) Send downlink messages.
Currently, you can only use REST APIs on the server to send [downlink messages](https://developer.huawei.com/consumer/en/doc/development/HMSCore-References/https-send-api-0000001050986197#section8686112674319?ha_source=hms1) through a third-party manufacturer's push messaging channel. 
The following is the URL for calling the API using HTTPS POST:

```
POST https://push-api.cloud.huawei.com/v1/[appId]/messages:send
```
The request header looks like the following:

```
Content-Type: application/json; charset=UTF-8
Authorization: Bearer CF3Xl2XV6jMKZgqYSZFws9IPlgDvxqOfFSmrlmtkTRupbU2VklvhX9kC9JCnKVSDX2VrDgAPuzvNm3WccUIaDg==
```
An example of the notification message body is as follows:

```
{
    "validate_only": false,
    "message": {
        "android": {
            "notification": {
                "title": "test title",
                "body": "test body",
                "click_action": {
                    "type": 3
                }
            }
        },
        "token": ["pushtoken1"]
    }
}
```
And just like that, my app has got the ability to send its push messages to mobile phones of different manufacturers — without any other configurations. Easy-peasy, right?

## Conclusion
Today's highly developed mobile Internet has made push messaging an important and effective way for mobile apps to improve user engagement and stickiness. A great obstacle for push messaging to effectively play its role is the highly diversified mobile phone market that is inundated with various manufacturers.

In this article, I demonstrated my solution to aggregate the push channels of different manufacturers, which allowed my app to push messages in a unified way to devices made by those manufacturers. As proven, the whole implementation process is both straightforward and cost-effective, delivering a better messaging effect of push messages by ensuring that they can reach a bigger user base supported by various manufacturers.