Android Library/SDK


Index

QuickStart

Firebase Cloud Messaging pre-requisites

Catapush Android SDK needs Firebase to work.

  1. Create a new Project in Firebase Console and obtain your Server Key and your Sender ID
  2. Save your google-services.json file in your app/ folder
  3. Go to your Catapush App configuration dashboard and select your app by clicking "View Panel"
  4. In Platforms section add your Server API Key to your Android configuration

Gradle configuration

The Google Services plugin for Gradle parses configuration information from the google-services.json file. Add the plugin to your project by updating your app build.gradle file as follows:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.5.1'
        classpath 'com.google.gms:google-services:4.3.2' 
    }
}

At the bottom of build.gradle, add the following line:

apply plugin: 'com.google.gms.google-services'

In the dependencies section, add the following line:

implementation 'com.google.firebase:firebase-core:16.0.9'
implementation 'com.google.firebase:firebase-messaging:18.0.0'

Catapush SDK

Add a new repository to the repositories section:

repositories {
    maven { url "https://jitpack.io" }
}

Add a new implementation:

implementation ('com.catapush:catapush-android-sdk:7.4.24') {
    exclude group: 'org.jetbrains', module: 'annotations'
}

Catapush follows Semantic Versioning rules, so you can safely replace the static version dependency with a dynamic 7.+ one.

Android Manifest configuration

To properly run Catapush, you need to add a few setup lines to your AndroidManifest.xml file.

Permissions

Catapush requires the following permission usages to be declared in your app's AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

App key

Declare this meta-data inside the application node of your AndroidManifest.xml

<meta-data
   android:name="com.catapush.library.APP_KEY"
   android:value="YOUR_APP_KEY" />

YOUR_APP_KEY is the AppKey of your Catapush App (go to your Catapush App configuration dashboard, select your App by clicking "View Panel" and then click on App details section)

Receivers and Service

In the <application> block, just before the closing tag, add these lines:

<service
    android:name="com.catapush.library.firebase.CatapushFirebaseMessagingService">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
</service>

<service android:name="com.catapush.library.MessagingService" android:label="YOUR_MESSAGE_CENTER_LABEL" />

<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version"/>

<receiver
  android:name=".MyReceiver"
  android:permission="${applicationId}.C2D_MESSAGE" >
  <intent-filter>
    <action android:name="com.catapush.library.action.MESSAGE_RECEIVED"/>
<action android:name="com.catapush.library.action.MESSAGE_OPENED"/>
<action android:name="com.catapush.library.action.MESSAGE_SENT"/>
<action android:name="com.catapush.library.action.MESSAGE_SENT_CONFIRMED"/>
<action android:name="com.catapush.library.action.NOTIFICATION_CLICKED"/>
<action android:name="com.catapush.library.action.RELOGIN_NOTIFICATION_CLICKED"/>
<action android:name="com.catapush.library.action.INVALID_LIBRARY"/>
<action android:name="com.catapush.library.action.CONNECTING"/>
<action android:name="com.catapush.library.action.CONNECTED"/>
<action android:name=“com.catapush.library.action.NETWORK_ERROR” />
<action android:name="com.catapush.library.action.DISCONNECTED"/> <category android:name="${applicationId}"/> </intent-filter> </receiver>

Create a receiver

To communicate with Catapush, you can extend CatapushReceiver and implement the needed methods. You can copy/paste the following class:

import com.catapush.library.CatapushTwoWayReceiver;
    import com.catapush.library.exceptions.CatapushAuthenticationError;
    import com.catapush.library.messages.CatapushMessage;

    import android.content.Context;
    import android.content.Intent;
    import android.support.annotation.NonNull;
    import android.util.Log;

    public class MyReceiver extends CatapushTwoWayReceiver {

    @Override
    public void onConnecting(Context context) {
        Log.d("MyApp", "Connecting...");
    }

    @Override
    public void onConnected(Context context) {
        Log.d("MyApp", "Connected");
    }

    @Override
    public void onMessageReceived(@NonNull CatapushMessage catapushMessage, Context context) {
        Log.d("MyApp", "Received Message: " + catapushMessage);
    }

    @Override
    public void onMessageOpened(@NonNull CatapushMessage catapushMessage, Context context) {
        Log.d("MyApp", "Opened Message: " + catapushMessage);
    }

    @Override
    public void onMessageSent(@NonNull CatapushMessage catapushMessage, Context context) {
        Log.d("MyApp", "Message marked as sent");
    }

    @Override
    public void onMessageSentConfirmed(@NonNull CatapushMessage catapushMessage, Context context) {
        Log.d("MyApp", "Message sent and delivered");
    }

    @Override
    public void onNotificationClicked(@NonNull CatapushMessage catapushMessage, Context context) {
        Log.d("MyApp", "Notification clicked: " + catapushMessage);
    }

    @Override
    public void onReloginNotificationClicked(Context context) {
        Log.d("MyApp", "Authentication lost. Need to relogin");
    }

    @Override
    public void onRegistrationFailed(@NonNull CatapushAuthenticationError error, Context context) {
        Log.e("MyApp", "Error Message: " + error.getReason());
    }

    @Override
    public void onDisconnected(int errorCode, Context context) {
        Log.d("MyApp", "Disconnected: " + errorCode);
    }
}

Initialization

You can initialize Catapush in your class that extends Application. Your onCreate() method should contains the following lines:

public class App extends MultiDexApplication {

    private static final String NOTIFICATION_CHANNEL_ID = "your.app.package.channel_id";

    @Override
    public void onCreate() {
        super.onCreate();

        Catapush.getInstance().init(this, NOTIFICATION_CHANNEL_ID, getString(R.string.notifications_default_channel_name),
                new Callback<Boolean>() {
                    @Override
                    public void success(Boolean response) {
                        Log.d("APP", "Catapush has been successfully initialized");
                    }

                    @Override
                    public void failure(Throwable t) {

                    }
                });
    }

}

From version 6.6.0 the method Catapush.getInstance().init() has been updated with two additional parameters to better comply with the new Android Oreo requirements regarding notification channels:

  • channelId: The id of the notification channel. Must be unique per package. The value may be truncated if it is too long.
  • channelName: The user visible name of the channel. You can rename this channel when the system locale changes by listening for the Intent.ACTION_LOCALE_CHANGED broadcast. The recommended maximum length is 40 characters; the value may be truncated if it is too long.

If you are creating the class App that extends Application for the first time, remember to add it to your AndroidManifest.xml:

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:name=".App"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">

Start

Catapush setup is complete. Whenever you want to start using Catapush, you just need to call the start() method. For instance, in your main Activity, after your user has logged in, you can use the following code to customize a Notification and start Catapush:

Uri sound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);

    Notification notification = Notification.builder()
        .swipeToDismissEnabled(false)
        .title(YOUR NOTIFICATION TITLE)
        .vibrationEnabled(true)
        .vibrationPattern(new long[]{100, 200, 100, 300})
        .soundEnabled(true)
        .soundResourceUri(sound)
        .circleColor(NOTIFICATION ICON BACKGROUND COLOR) // Check out the Customization section below
        .ledEnabled(true)
        .ledColor(Color.BLUE)
        .ledOnMS(2000)
        .ledOffMS(1000)
        .build();

    Catapush.getInstance()
        .setPush(notification)
        .setUser(CATAPUSH_USER, CATAPUSH_PASSWORD)
        .start();

  • CATAPUSH_USER is the user Identifier present in Users section of the Catapush App dashboard
  • CATAPUSH_PASSWORD is the user Password present in Users section of the Catapush App dashboard

Catapush 9.x

Catapush SDK for Android 9.x is the latest and most feature-rich release
We've migrated our codebase to AndroidX thus reducing the number of third-party dependencies and we improved Android 9.0 Pie support.
We've also added the ability to add a custom payload to your messages

Due to these improvements we've updated our SDK interface accordingly, so you'll need to make some changes on your side:

  1. Migrate your project to AndroidX, see the official documentation. On most cases this will be effortless since Android Studio takes care of everything for you.
  2. Update the Catapush version:
    implementation ('com.catapush:catapush-android-sdk:9.0.3')
  3. Update your Catapush initialization: the SDK won't create a notification channel on your behalf, so it won’t ask for the channel name anymore, you just need to provide a notification channel ID instead.

    Follow this template:
    
    public class App extends MultiDexApplication {
    
        private static final String NOTIFICATION_CHANNEL_ID = "your.app.package.channel_id";
    
        @Override
        public void onCreate() {
            super.onCreate();
    
            NotificationManager nm = ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE));
            channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "User visible channel name", NotificationManager.IMPORTANCE_HIGH);
            nm.createNotificationChannel(channel);
    
            Catapush.getInstance().init(this, NOTIFICATION_CHANNEL_ID,
                    new Callback() {
                        @Override
                        public void success(Boolean response) {
                            Log.d("APP", "Catapush has been successfully initialized");
                        }
                        @Override
                        public void failure(Throwable t) {
                            Log.e("APP", "Catapush not initialized! Reason: " + t.getMessage());
                        }
                    });
       }	
    }
    
    Please note: the notification channel ID you pass to the SDK as initialization parameter must refer to an already created channel on the NotificationManager. See the official documentation
  4. Update your Catapush start with the new Callback that also receives warnings from the SDK. This callback will deliver non-fatal exceptions that will guide you fixing the device configuration to optimize the delivery performances, particularly when in background.

    Follow this template:
    
    Catapush.getInstance()
    .setPush(notification)
    .setUser(CATAPUSH_USER, CATAPUSH_PASSWORD)
    .start(new RecoverableErrorCallback() {
    	@Override
    	public void success(Boolean boolean) {
    		Log.d("APP", "Catapush started!");
    	}
    	
    	@Override
    	public void warning(@NotNull Throwable t) {
    		Log.w("APP", "Catapush device configuration warning: " + t.getMessage());
    	}
    	
    	@Override
    	public void failure(@NotNull Throwable throwable) {
    		Log.e("APP", "Can’t start Catapush! Reason: " + t.getMessage());
    	}
      }
    );		
    

Advanced

Notification management

By default Push Notifications visualization is managed by the Catapush library, which builds Notifications and displays them in the notification bar with your UI settings.

Disable Push Notification Visualization

You can choose to disable Push Notifications visualization permanently using:

Catapush.getInstance().disableNotifications();

And re-enable them using:

Catapush.getInstance().enableNotifications();

This state will be persisted and preserved across app restarts and Catapush starts/stops.

Note: disabling Push Notifications does not stop receiving messages, but you have to handle Open Notification feedback by your own.

Pause Push Notification Visualization

You can choose to disable Push Notifications visualization temporarily using:

Catapush.getInstance().pauseNotifications();

And re-enable them using:

Catapush.getInstance().resumeNotifications();

This state will not be persisted. If you restart your app or stop/start Catapush the push notifications visualization will be resumed.

Note: pausing Push Notifications does not stop receiving messages, but you have to handle Open Notification feedback by your own.

Hide Notifications when User is in your Messages List

It is also useful to pause/resume Push Notifications visualization when your Message list is active and visible.

You can disable and enable them as in the following example, taking advantage of your Activity lifecycle methods:

@Override public void onResume() {
    super.onResume();
    // Our app is open and we don't want status bar notification in this scenario
    Catapush.getInstance().pauseNotifications();
}

Enable Push visualization when the user close your Message Thread list, e.g. ListActivity:

@Override public void onPause() {
    super.onPause();
    // Our app is not visible and we want status bar notification in this scenario
    Catapush.getInstance().resumeNotifications();
}

Notification Visualization

When you decide to use Android system Notification provided by Catapush, you can detect the click on the notification with your MyReceiver class. In the following example, when the user clicks the notification, an onNotificationClicked event is triggered and the appropriate CatapushMessage is passed as argument. The example shows how to start an Activity on this click event:

@Override
public void onNotificationClicked(CatapushMessage catapushMessage, Context context) {
    Log.d("MyApp", "Opened Message: " + catapushMessage);

    Intent intent = new Intent(context, MainActivity.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
    context.startActivity(intent);
}        

Sending Read Notification Receipt Manually

If you decide to disable default Push Notification management, you have to manually report every message opening:

Catapush.getInstance().notifyMessageOpened(catapushMessage.id());

Enabling optimal QoS for Silent Push notifications by ignoring Dozemode

With version 6.0, Android has introduced a new feature called Doze that, under certain circumstances, might limit your app execution or network access while running in the background thus reducing reliability of sending Silent Push to execute the app; this capability is important to guarantee high priority push and the ability to start the application when it is closed / inactive.

Dozemode restrictions have been improved and strengthened in each subsequent Android release, ending with the introduction of App Standby Buckets in Android 9.0. These features, when your app hasn't been used for a period of time, might hinder your ability to execute Capatush SDK / your application and thus the ability of Catapush of consistently delivering messages to it.

To check if your app is being considered inactive you can use this method:
https://developer.android.com/reference/android/app/usage/UsageStatsManager.html#isAppInactive(java.lang.String)
Its javadoc gives a brief description on how the system decides which app is inactive: Returns whether the specified app is currently considered inactive. This will be true if the app hasn't been used directly or indirectly for a period of time defined by the system. This could be of the order of several hours or days.

To check if your app has been classified in a low priority Standby Bucket you can use this method:
https://developer.android.com/reference/android/app/usage/UsageStatsManager.html#getAppStandbyBucket()
From its javadoc: Returns the current standby bucket of the calling app. The system determines the standby state of the app based on app usage patterns. Standby buckets determine how much an app will be restricted from running background tasks such as jobs and alarms. Restrictions increase progressively from STANDBY_BUCKET_ACTIVE to STANDBY_BUCKET_RARE, with STANDBY_BUCKET_ACTIVE being the least restrictive. The battery level of the device might also affect the restrictions. Apps in buckets ≤ STANDBY_BUCKET_ACTIVE have no standby restrictions imposed. Apps in buckets > STANDBY_BUCKET_FREQUENT may have network access restricted when running in the background. The standby state of an app can change at any time either due to a user interaction or a system interaction or some algorithm determining that the app can be restricted for a period of time before the user has a need for it.

If you app is considered inactive or has been put in a Standby Bucket > STANDBY_BUCKET_FREQUENT you should ask your user to disable the battery optimizations for your app, especially if reliable delivery is critical for your business.

You can check if the user has already disabled the battery optimizations for you app using this method:
https://developer.android.com/reference/android/os/PowerManager.html#isIgnoringBatteryOptimizations(java.lang.String)

Then, if it's not yet ignoring the optimizations, you can open the device settings on the correct page broadcasting an Intent with the following action:

https://developer.android.com/reference/android/provider/Settings.html#ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS

This list will be displayed:



The user will have to find and tap your app, then choose "Don't optimize".