Android F.A.Q.

What does Android push token and HWID look like?

Android device push tokens differ in length (less than 255 characters) and start with APA91b, e.g.: APA91bFoi3lMMre9G3XzR1LrF4ZT82_15MsMdEICogXSLB8-MrdkRuRQFwNI5u8Dh0cI90ABD3BOKnxkEla8cGdisbDHl5cVIkZah5QUhSAxzx4Roa7b4xy9tvx9iNSYw-eXBYYd8k1XKf8Q_Qq1X9-x-U-Y79vdPq

Please also note that tokens often contain a colon-separated prefix before APA91b, e.g. eQnyCE6ULAQ:APA91bGrh4ya3b_owo9tshZNVAGhZdGMGb3sA5HbM...

Pushwoosh uses UUID as HWIDs, i.e. randomly generated strings of 32 alphanumerical characters: 123e4567-e89b-12d3-a456-426655440000

How can I obtain my Android device push token?

You can obtain your Android device push token in the console log. Use the logcat tool in Android Studio.

Open monitor.bat in %USERPROFILE%\AppData\Local\Android\sdk\tools\monitor.bat, connect your device to PC and allow USB debugging in Android settings. Run your application on the device. Locate /registerDevice, find the push token for your device to use in Test Devices later on.

What permissions are necessary and what are optional?

When installed on an Android device, the application will ask for the following permissions in connection with Pushwoosh SDK:

<!-- FCM connects to Firebase Services. -->
<uses-permission android:name="android.permission.INTERNET"/>
<!-- Keeps the processor from sleeping when a message is received. -->
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<!-- This permission is used to determine whether the device can access the network. -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!-- This app has permission to register and receive data message. -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

Our SDK doesn’t ask for permission to access images, device contacts, etc.

How accurate is the total number of Android subscribers?

Pushwoosh clears unsubscribed Android devices from the database upon receiving the “NotRegistered” response from FCM, which can be returned after the second attempt to reach a specific device. It means that you have to send 2 pushes to an unsubscribed device to have it removed from our database. Here’s the most common scenario described in the FCM documentation:

  1. Your subscriber uninstalls the app.

  2. Pushwoosh sends a message to FCM server.

  3. The FCM server sends the message to your user’s device.

  4. The FCM client on the device receives the message and detects that your application has been uninstalled; the detection details depend on the platform on which the app is running.

  5. The FCM client on the device informs the FCM server that the app was uninstalled.

  6. The FCM server marks the registration ID for deletion.

  7. Pushwoosh sends another message to FCM.

  8. The FCM returns a NotRegistered message.

  9. Pushwoosh removes the push token from your userbase.

It might take a while for registration ID to be completely removed from FCM. Thus it is possible a message sent in step 7 above gets a valid message ID as response, even though the message will not be delivered to the client app.

Can I use HTML tags in pushes sent to Android?

Yes, in Android you may use the following HTML tags in order to modify the appearance of a push:

<span style="color: green;"><b><i><span style="text-decoration: underline;">Hello world!
Hello hi hey</span></i></b></span>

Place these HTML tags in the Message input field, and use them in the API request as well. Note that some Android devices may fail to process these HTML tags properly, but most of the devices we have used for tests displayed formatting properly.

How to set a notification icon in Android Lollipop (and later versions)?

In Android Lollipop icons were changed to be white only. Therefore, if you select targetSdkVersion >= 21 in your AndroidManifest.xml file, Android will only use alpha-channel of the icon. See more on the behavior in Android documentation.

The system ignores all non-alpha channels in action icons and in the main notification icon. Assume these icons will be alpha-only. The system draws notification icons in white and action icons in dark gray. This is beyond Pushwoosh SDK control.

1. Create the notification icon according to the Android guidelines. As per documentation, the system will ignore all the colors. 1.1. Name the icon as pw_notification.png and put it in res/drawable folder. Pushwoosh SDK will use this icon as default for notifications. 1.2. Alternatively, you can use Remote API and set the "android_icon" parameter value to the icon image (without file extension).

Using Pushwoosh SDK with other FCM services

You can use Pushwoosh alongside with other SDKs that use FCM for push messaging. To do that you should create a router service to distribute events between the services:

FirebaseMessagingRouterService.kt
FirebaseMessagingRouterService.java
class FirebaseMessagingRouterService : FirebaseMessagingService() {
override fun onMessageReceived(remoteMessage: RemoteMessage) {
if (PushwooshFcmHelper.isPushwooshMessage(remoteMessage)) {
//this is a Pushwoosh push, SDK will handle it automatically
PushwooshFcmHelper.onMessageReceived(this, remoteMessage)
} else {
//this is not a Pushwoosh push, you should handle it by yourself
dispatchNonPushwooshMessage(remoteMessage);
}
}
private fun dispatchNonPushwooshMessage(remoteMessage: RemoteMessage) {
// Implement your push handling logics here
}
}

Take care of listening to push token changes:

FirebaseInstanceIdRouterService.kt
FirebaseInstanceIdRouterService.java
class FirebaseInstanceIdRouterService : FirebaseInstanceIdService() {
override fun onTokenRefresh() {
// Get updated InstanceID token.
val refreshedToken = FirebaseInstanceId.getInstance().token
// Send a new token to Pushwoosh
PushwooshFcmHelper.onTokenRefresh(this, refreshedToken)
sendTokenToAnotherService(token);
}
private fun sendTokenToAnotherService(token: String) {
// Implement your token handling logics here
}
}

Register the routers in your AndroidManifest.xml:

AndroidManifest.xml
<service
android:name=".FirebaseInstanceIdRouterService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
<service
android:name=".FirebaseMessagingRouterService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>

Using Pushwoosh with LeakCanary or AppMetrica libraries

When you integrate analytics tools such as LeakCanary, AppMetrica or others, these libraries start a new process, creating new instance of the app. Since you can't listen for the push notifications in another process, this results in java.lang.NullPointerException being thrown.

If you call registerForPushNotifications inside Application.onCreate(), you should check if you are in the application's main process. Use the following code to perform this check:

List<ActivityManager.RunningAppProcessInfo> runningAppProcesses = ((ActivityManager) getSystemService(Context.ACTIVITY_SERVICE)).getRunningAppProcesses();
if (runningAppProcesses != null && runningAppProcesses.size() != 0) {
for (ActivityManager.RunningAppProcessInfo runningAppProcessInfo : runningAppProcesses) {
boolean isCurrentProcess = runningAppProcessInfo.pid == android.os.Process.myPid();
boolean isMainProcessName = getPackageName().equals(runningAppProcessInfo.processName);
if (isCurrentProcess && isMainProcessName) {
Pushwoosh.getInstance().registerForPushNotifications(...);
break;
}
}
}

Deleting particular received notifications from a device

If you want to remove a non-relevant push when performing a specific action inside your application, you can use the following approach:

MainActivity.java
public class MainActivity extends AppCompatActivity {
List<NotificationCreatedEvent> savedPushes = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Pushwoosh.getInstance().registerForPushNotifications();
PushwooshNotificationSettings.setMultiNotificationMode(true);
findViewById(R.id.clear_button).setOnClickListener( v -> {
cancelPushes();
});
EventBus.subscribe(NotificationCreatedEvent.class, event -> {
try {
if (event.getMessage().getCustomData() == null)
return;
//cancel pushes only with a specific flag
if (new JSONObject(event.getMessage().getCustomData()).getBoolean("cancel")) {
savedPushes.add(event);
}
} catch (JSONException e) {
}
});
}
private void cancelPushes() {
NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
if (manager == null) {
return;
}
for (NotificationCreatedEvent event : savedPushes) {
manager.cancel(event.getMessageTag(), event.getMessageId());
}
}
}