# Configuring push notifications (Android)

## Prerequisites
---
Google Firebase Cloud Messaging is necessary to handle [Mobile Campaigns](/docs/campaign/Mobile) sent from Synerise.

1. Follow the instructions in [this article](https://firebase.google.com/docs/storage/android/start).
2. Integrate the Firebase project with Synerise. See [this article](/docs/settings/tool/firebase).

Documentation on how to prepare your first push notification is available in our [user guide](/docs/campaign/Mobile).

## Set up Firebase Cloud Messaging for Synerise SDK
---

1. Register your service in the AndroidManifest:
   
   <pre><code class="language-XML">&lt;application
              android:name=".App"
              android:allowBackup="true"
              android:icon="@mipmap/ic_launcher"
              android:label="@string/app_name"
              android:roundIcon="@mipmap/ic_launcher_round"
              android:supportsRtl="true"
              android:theme="@style/AppTheme"&gt;
              ...
              &lt;service android:name=".service.MyFirebaseMessagingService"&gt;
                  &lt;intent-filter&gt;
                      &lt;action android:name="com.google.firebase.MESSAGING_EVENT" /&gt;
                  &lt;/intent-filter&gt;
              &lt;/service&gt;
          &lt;/application&gt;</code></pre>

2. In your application, implement registration for Firebase notifications:
   
   <div class="content-tabs code-tabs" data-tab-group="tabgrp-521">
   <div class="tab-buttons"><button class="tab-button" data-tab-id="tabgrp-521-0" data-tab-group="tabgrp-521" data-tab-active="true">java</button><button class="tab-button" data-tab-id="tabgrp-521-1" data-tab-group="tabgrp-521">kotlin</button></div>

   <div class="tab-panel" data-tab-id="tabgrp-521-0" data-tab-group="tabgrp-521" data-tab-active="true">

   ```java
   public class App extends MultiDexApplication implements OnRegisterForPushListener {

          private static final String TAG = App.class.getSimpleName();

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

               Synerise.Builder.with(this, syneriseClientApiKey, appId)
                                      .notificationIcon(R.drawable.ic_notification_icon)
                                      .pushRegistrationRequired(this)
                                      ...
                                      .build();
          }

          @Override
          public void onRegisterForPushRequired() {
              FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(instanceIdResult -> {
                  String refreshedToken = instanceIdResult.getToken();
                  Log.d(TAG, "Refreshed token: " + refreshedToken);

                  IApiCall call = Client.registerForPush(refreshedToken, true);
                  call.execute(() -> Log.d(TAG, "Register for Push succeed: " + refreshedToken),
                               apiError -> Log.w(TAG, "Register for push failed: " + refreshedToken));
              });
          }
      }
   ```

   </div>

   <div class="tab-panel" data-tab-id="tabgrp-521-1" data-tab-group="tabgrp-521">

   ```kotlin
   class App:MultiDexApplication(), OnRegisterForPushListener {
        fun onCreate() {
          super.onCreate()
          Synerise.Builder.with(this, syneriseClientApiKey, appId)
          .notificationIcon(R.drawable.ic_notification_icon)
          .pushRegistrationRequired(this)
          build()
        }
        fun onRegisterForPushRequired() {
          FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener({ instanceIdResult->
            val refreshedToken = instanceIdResult.getToken()
            Log.d(TAG, "Refreshed token: " + refreshedToken)
            val call = Client.registerForPush(refreshedToken, true)
            call.execute({ Log.d(TAG, "Register for Push succeed: " + refreshedToken) },
              { apiError-> Log.w(TAG, "Register for push failed: " + refreshedToken) }) })
        }
        companion object {
          private val TAG = App::class.java!!.getSimpleName()
        }
      }
   ```

   </div>
   </div>


   
   <div class="admonition admonition-important"><div class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg></div><div class="admonition-body"><div class="admonition-content">

   The second parameter of the registration method is the agreement for mobile push campaigns. In the Profile's card in Synerise, you can find it in the **Subscriptions** section (if you have the required access permission). Learn more about the [Client.registerForPush(token, mobilePushAgreement) method in the method reference](/developers/mobile-sdk/method-reference/android/campaigns#register-for-push-notifications).

   </div></div></div>


3. Add registerForPush method inside onNewToken callback. This should be done in your class which extends FirebaseMessagingService
   
   <div class="content-tabs code-tabs" data-tab-group="tabgrp-522">
   <div class="tab-buttons"><button class="tab-button" data-tab-id="tabgrp-522-0" data-tab-group="tabgrp-522" data-tab-active="true">java</button><button class="tab-button" data-tab-id="tabgrp-522-1" data-tab-group="tabgrp-522">kotlin</button></div>

   <div class="tab-panel" data-tab-id="tabgrp-522-0" data-tab-group="tabgrp-522" data-tab-active="true">

   ```java
   @Override
          public void onNewToken(String refreshedToken) {
              super.onNewToken(refreshedToken);

              Log.d(TAG, "Refreshed token: " + refreshedToken);

              if (refreshedToken != null) {
                  IApiCall call = Client.registerForPush(refreshedToken, true);
                  call.execute(() -> Log.d(TAG, "Register for Push succeed: " + refreshedToken),
                               apiError -> Log.w(TAG, "Register for push failed: " + refreshedToken));
              }
          }
   ```

   </div>

   <div class="tab-panel" data-tab-id="tabgrp-522-1" data-tab-group="tabgrp-522">

   ```kotlin
   fun onNewToken(refreshedToken:String) {
        super.onNewToken(refreshedToken)
        Log.d(TAG, "Refreshed token: " + refreshedToken)
        if (refreshedToken != null)
        {
          val call = Client.registerForPush(refreshedToken, true)
          call.execute({ Log.d(TAG, "Register for Push succeed: " + refreshedToken) },
                       { apiError-> Log.w(TAG, "Register for push failed: " + refreshedToken) })
        }
      }
   ```

   </div>
   </div>

4. Pass the incoming push notification payload to the `Injector` in your `FirebaseMessagingService` implementation:
   
   <div class="content-tabs code-tabs" data-tab-group="tabgrp-523">
   <div class="tab-buttons"><button class="tab-button" data-tab-id="tabgrp-523-0" data-tab-group="tabgrp-523" data-tab-active="true">java</button><button class="tab-button" data-tab-id="tabgrp-523-1" data-tab-group="tabgrp-523">kotlin</button></div>

   <div class="tab-panel" data-tab-id="tabgrp-523-0" data-tab-group="tabgrp-523" data-tab-active="true">

   ```java
   public class MyFirebaseMessagingService extends FirebaseMessagingService {

          @Override
          public void onMessageReceived(RemoteMessage remoteMessage) {
              super.onMessageReceived(remoteMessage);

              boolean isSynerisePush = Injector.handlePushPayload(remoteMessage.getData());
          }
      }
   ```

   </div>

   <div class="tab-panel" data-tab-id="tabgrp-523-1" data-tab-group="tabgrp-523">

   ```kotlin
   class MyFirebaseMessagingService:FirebaseMessagingService() {
        fun onMessageReceived(remoteMessage:RemoteMessage) {
          super.onMessageReceived(remoteMessage)
          val isSynerisePush = Injector.handlePushPayload(remoteMessage.getData())
        }
      }
   ```

   </div>
   </div>

      Overriding `onMessageReceived(RemoteMessage)` stops simple notifications from being displayed while the app is the active screen.
      
5. In order to configure a notification icon and notification icon color, you need to set the following two parameters in `AndroidManifest.xml`, in the `application` section:
  
   <pre><code class="language-XML">&lt;meta-data
               android:name="com.synerise.sdk.messaging.notification_icon"
               android:resource="@drawable/ic_notification_icon" /&gt;
      &lt;meta-data
               android:name="com.synerise.sdk.messaging.notification_icon_color"
               android:resource="@color/amaranth" /&gt;</code></pre>
  
   The default values are: `android icon` and `white color`.  

   
   <div class="admonition admonition-note"><div class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg></div><div class="admonition-body"><div class="admonition-content">

   Check [the repository of our sample app](https://github.com/Synerise/android-sdk) for an example usage of building your non-Synerise notification.

   </div></div></div>


## Keep Firebase token always up-to-date
---
You must always keep the Firebase token updated. 

- Whenever the user changes the notification consent in the system or the application, you should call the `registerForPush` method ([Android](/developers/mobile-sdk/method-reference/android/campaigns#register-for-push-notifications); [iOS](/developers/mobile-sdk/method-reference/ios/campaigns#register-for-push-notifications), [Flutter](/developers/mobile-sdk/method-reference/flutter/campaigns), [React Native](/developers/mobile-sdk/method-reference/react-native/campaigns)).
- In many cases in the application lifecycle, such as authorization, destroyed sessions, user context change, periodic jobs ([Work Manager](/developers/mobile-sdk/installation-and-configuration/android#work-manager)), and so on, the SDK invokes the [snr_registerForPushNotificationsIsNeeded(origin)](/developers/mobile-sdk/listeners-and-delegates/android-listeners#on-register-for-push-listener-on-register-for-push-required-with-origin) method or [snr_registerForPushNotificationsIsNeeded()](/developers/mobile-sdk/listeners-and-delegates/android-listeners#on-register-for-push-listener-on-register-for-push-required) method.


  <div class="admonition admonition-note"><div class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg></div><div class="admonition-body"><div class="admonition-content">

  [Work Manager](/developers/mobile-sdk/installation-and-configuration/android#work-manager) allows you to keep the Firebase token updated even if the host application is not launched for a long time. It launches your app in the background approximately every 20 days and refreshes the token so it stays up to date.

  </div></div></div>


### Assign notifications to channels
Starting with Android 8.0 (API level 26), all notifications must be assigned to a channel. Otherwise, they are not displayed.

You can implement notifications in one of the following ways:

- If you already have a channel defined in your application, use the `notificationDefaultChannelId(String)` and `NotificationHighPriorityChannelId(String)` methods of Builder during SDK initialization.
- You cannot configure more than two notification channels.
- If you want the SDK to set the channel names to default (same as the application name), initialize the SDK without the methods mentioned above.

## Callback methods
---


<div class="admonition admonition-note"><div class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg></div><div class="admonition-body"><div class="admonition-content">

[NotificationListener](/developers/mobile-sdk/listeners-and-delegates/android-listeners#on-notification-listener) is available from SDK 4.9.0 version.

</div></div></div>


If you want to receive callbacks to inform the application about notification's state, implement `OnNotificationListener` using the `Injector.setOnNotificationListener` method.

For details, see [this article](/developers/mobile-sdk/listeners-and-delegates/android-listeners#on-notification-listener).

See sample code from the application below:

<div class="content-tabs code-tabs" data-tab-group="tabgrp-524">
<div class="tab-buttons"><button class="tab-button" data-tab-id="tabgrp-524-0" data-tab-group="tabgrp-524" data-tab-active="true">java</button><button class="tab-button" data-tab-id="tabgrp-524-1" data-tab-group="tabgrp-524">kotlin</button></div>

<div class="tab-panel" data-tab-id="tabgrp-524-0" data-tab-group="tabgrp-524" data-tab-active="true">

```java
Injector.setOnNotificationListener(new OnNotificationListener() {
            @Override
            public void onNotificationReceived(NotificationInfo notificationInfo) {
            }

            @Override
            public void onNotificationClicked(NotificationInfo notificationInfo) {
            }

            @Override
            public void onNotificationDismissed(NotificationInfo notificationInfo) {
            }

            @Override
            public void onActionButtonClicked(NotificationInfo notificationInfo, String actionButton) {
            }
        });
```

</div>

<div class="tab-panel" data-tab-id="tabgrp-524-1" data-tab-group="tabgrp-524">

```kotlin
Injector.setOnNotificationListener(
    object callback: OnNotificationListener() {
        override fun onNotificationReceived(notificationInfo: NotificationInfo) {
        }

        override fun onNotificationClicked(notificationInfo: NotificationInfo) { 
        }

        override fun onNotificationDismissed(notificationInfo: NotificationInfo) {  
        }

        override fun onActionButtonClicked(
            notificationInfo: NotificationInfo,
            actionButton: String) {
        }
    })
```

</div>
</div>


## Configure notification encryption
---

To enable encrypted push notifications, you must change the configuration of your workspace in the Synerise Platform. For details, read [Google Firebase](/docs/settings/tool/firebase).

In the mobile application, you must set `encryption` to `true` in the notification settings. 


<div class="content-tabs code-tabs" data-tab-group="tabgrp-525">
<div class="tab-buttons"><button class="tab-button" data-tab-id="tabgrp-525-0" data-tab-group="tabgrp-525" data-tab-active="true">java</button><button class="tab-button" data-tab-id="tabgrp-525-1" data-tab-group="tabgrp-525">kotlin</button></div>

<div class="tab-panel" data-tab-id="tabgrp-525-0" data-tab-group="tabgrp-525" data-tab-active="true">

```java
Synerise.settings.notifications.setEncryption(true);
```

</div>

<div class="tab-panel" data-tab-id="tabgrp-525-1" data-tab-group="tabgrp-525">

```kotlin
Synerise.settings.notifications.setEncryption(true)
```

</div>
</div>


The SDK performs the encryption as a part of the `Synerise.Notifications.handleNotification` method.

If you use only the `"Synerise"` issuer in push notifications, no more actions are required.

If you need custom integration of encrypted push notifications, implement the following solution:


<div class="content-tabs code-tabs" data-tab-group="tabgrp-526">
<div class="tab-buttons"><button class="tab-button" data-tab-id="tabgrp-526-0" data-tab-group="tabgrp-526" data-tab-active="true">java</button><button class="tab-button" data-tab-id="tabgrp-526-1" data-tab-group="tabgrp-526">kotlin</button></div>

<div class="tab-panel" data-tab-id="tabgrp-526-0" data-tab-group="tabgrp-526" data-tab-active="true">

```java
Map<String, String> data = remoteMessage.getData();
    if (Injector.isPushEncrypted(data)) {
        data = Injector.decryptPushPayload(data);
    }
// your operations on push notification
```

</div>

<div class="tab-panel" data-tab-id="tabgrp-526-1" data-tab-group="tabgrp-526">

```kotlin
val data = remoteMessage.getData()
    if (Injector.isPushEncrypted(data)) {
        data = Injector.decryptPushPayload(data)
    }
// your operations on push notification
```

</div>
</div>



<div class="admonition admonition-note"><div class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg></div><div class="admonition-body"><div class="admonition-content">

The `decryptPushPayload` method returns raw data when the payload is not encrypted. If the crypter fails, the method returns null.<br/>

For more information, read [the description of the decryption method](/developers/mobile-sdk/method-reference/android/campaigns#decrypt-push-notification).

</div></div></div>


## Handling actions from push notifications
---
- [Read more about types of actions in campaigns](/developers/mobile-sdk/campaigns/action-handling#types-of-actions-in-campaigns)  
- [Read more about handling actions from push notifications](/developers/mobile-sdk/campaigns/action-handling)  
