|
| 1 | +--- |
| 2 | +title: Enable push notifications in your Android chat app |
| 3 | +titleSuffix: An Azure Communication Services tutorial |
| 4 | +description: Learn how to enable push notification in Android App by using Azure Communication Chat SDK |
| 5 | +author: jiminwen |
| 6 | +services: azure-communication-services |
| 7 | +ms.author: jiminwen |
| 8 | +ms.date: 08/16/2022 |
| 9 | +ms.topic: tutorial |
| 10 | +ms.service: azure-communication-services |
| 11 | +--- |
| 12 | + |
| 13 | + |
| 14 | +# Enable push notifications |
| 15 | +Push notifications let clients be notified for incoming messages and other operations occurring in a chat thread in situations where the mobile app isn't running in the foreground. Azure Communication Services supports a [list of events that you can subscribe to](../concepts/chat/concepts.md#push-notifications). |
| 16 | +> [!NOTE] |
| 17 | +> Chat push notifications are supported for Android SDK in versions starting from 1.1.0-beta.4 and 1.1.0. It is recommended that you use version 1.2.0 or newer, as older versions have a known issue with the registration renewal. Steps from 8 to 12 are only needed for versions equal to or greater than 1.2.0. |
| 18 | +
|
| 19 | +1. Set up Firebase Cloud Messaging for the ChatQuickstart project. Complete steps `Create a Firebase project`, `Register your app with Firebase`, `Add a Firebase configuration file`, `Add Firebase SDKs to your app`, and `Edit your app manifest` in [Firebase Documentation](https://firebase.google.com/docs/cloud-messaging/android/client). |
| 20 | + |
| 21 | +2. Create a Notification Hub within the same subscription as your Communication Services resource, configure your Firebase Cloud Messaging settings for the hub, and link the Notification Hub to your Communication Services resource. See [Notification Hub provisioning](../concepts/notifications.md#notification-hub-provisioning). |
| 22 | +3. Create a new file called `MyFirebaseMessagingService.java` in the same directory where `MainActivity.java` resides. Copy the following code into `MyFirebaseMessagingService.java`. You will need to replace `<your_package_name>` with the package name used in `MainActivity.java`. You can use your own value for `<your_intent_name>`. This value will be used in step 6 below. |
| 23 | + |
| 24 | + ```java |
| 25 | + package <your_package_name>; |
| 26 | + |
| 27 | + import android.content.Intent; |
| 28 | + import android.util.Log; |
| 29 | + |
| 30 | + import androidx.localbroadcastmanager.content.LocalBroadcastManager; |
| 31 | + |
| 32 | + import com.azure.android.communication.chat.models.ChatPushNotification; |
| 33 | + import com.google.firebase.messaging.FirebaseMessagingService; |
| 34 | + import com.google.firebase.messaging.RemoteMessage; |
| 35 | + |
| 36 | + import java.util.concurrent.Semaphore; |
| 37 | + |
| 38 | + public class MyFirebaseMessagingService extends FirebaseMessagingService { |
| 39 | + private static final String TAG = "MyFirebaseMsgService"; |
| 40 | + public static Semaphore initCompleted = new Semaphore(1); |
| 41 | + |
| 42 | + @Override |
| 43 | + public void onMessageReceived(RemoteMessage remoteMessage) { |
| 44 | + try { |
| 45 | + Log.d(TAG, "Incoming push notification."); |
| 46 | + |
| 47 | + initCompleted.acquire(); |
| 48 | + |
| 49 | + if (remoteMessage.getData().size() > 0) { |
| 50 | + ChatPushNotification chatPushNotification = |
| 51 | + new ChatPushNotification().setPayload(remoteMessage.getData()); |
| 52 | + sendPushNotificationToActivity(chatPushNotification); |
| 53 | + } |
| 54 | + |
| 55 | + initCompleted.release(); |
| 56 | + } catch (InterruptedException e) { |
| 57 | + Log.e(TAG, "Error receiving push notification."); |
| 58 | + } |
| 59 | + } |
| 60 | + |
| 61 | + private void sendPushNotificationToActivity(ChatPushNotification chatPushNotification) { |
| 62 | + Log.d(TAG, "Passing push notification to Activity: " + chatPushNotification.getPayload()); |
| 63 | + Intent intent = new Intent("<your_intent_name>"); |
| 64 | + intent.putExtra("PushNotificationPayload", chatPushNotification); |
| 65 | + LocalBroadcastManager.getInstance(this).sendBroadcast(intent); |
| 66 | + } |
| 67 | + } |
| 68 | + |
| 69 | + ``` |
| 70 | + |
| 71 | +4. At the top of file `MainActivity.java`, add the following import statements: |
| 72 | + |
| 73 | + ```java |
| 74 | + import android.content.BroadcastReceiver; |
| 75 | + import android.content.Context; |
| 76 | + import android.content.Intent; |
| 77 | + import android.content.IntentFilter; |
| 78 | + |
| 79 | + import androidx.localbroadcastmanager.content.LocalBroadcastManager; |
| 80 | + import com.azure.android.communication.chat.models.ChatPushNotification; |
| 81 | + import com.google.android.gms.tasks.OnCompleteListener; |
| 82 | + import com.google.android.gms.tasks.Task; |
| 83 | + import com.google.firebase.messaging.FirebaseMessaging; |
| 84 | + ``` |
| 85 | + |
| 86 | +5. Add the following code to the `MainActivity` class: |
| 87 | + |
| 88 | + ```java |
| 89 | + private BroadcastReceiver firebaseMessagingReceiver = new BroadcastReceiver() { |
| 90 | + @Override |
| 91 | + public void onReceive(Context context, Intent intent) { |
| 92 | + ChatPushNotification pushNotification = |
| 93 | + (ChatPushNotification) intent.getParcelableExtra("PushNotificationPayload"); |
| 94 | + |
| 95 | + Log.d(TAG, "Push Notification received in MainActivity: " + pushNotification.getPayload()); |
| 96 | + |
| 97 | + boolean isHandled = chatAsyncClient.handlePushNotification(pushNotification); |
| 98 | + if (!isHandled) { |
| 99 | + Log.d(TAG, "No listener registered for incoming push notification!"); |
| 100 | + } |
| 101 | + } |
| 102 | + }; |
| 103 | + |
| 104 | + |
| 105 | + private void startFcmPushNotification() { |
| 106 | + FirebaseMessaging.getInstance().getToken() |
| 107 | + .addOnCompleteListener(new OnCompleteListener<String>() { |
| 108 | + @Override |
| 109 | + public void onComplete(@NonNull Task<String> task) { |
| 110 | + if (!task.isSuccessful()) { |
| 111 | + Log.w(TAG, "Fetching FCM registration token failed", task.getException()); |
| 112 | + return; |
| 113 | + } |
| 114 | + |
| 115 | + // Get new FCM registration token |
| 116 | + String token = task.getResult(); |
| 117 | + |
| 118 | + // Log and toast |
| 119 | + Log.d(TAG, "Fcm push token generated:" + token); |
| 120 | + Toast.makeText(MainActivity.this, token, Toast.LENGTH_SHORT).show(); |
| 121 | + |
| 122 | + chatAsyncClient.startPushNotifications(token, new Consumer<Throwable>() { |
| 123 | + @Override |
| 124 | + public void accept(Throwable throwable) { |
| 125 | + Log.w(TAG, "Registration failed for push notifications!", throwable); |
| 126 | + } |
| 127 | + }); |
| 128 | + } |
| 129 | + }); |
| 130 | + } |
| 131 | + |
| 132 | + ``` |
| 133 | + |
| 134 | +6. Update the function `onCreate` in `MainActivity`. |
| 135 | + |
| 136 | + ```java |
| 137 | + @Override |
| 138 | + protected void onCreate(Bundle savedInstanceState) { |
| 139 | + super.onCreate(savedInstanceState); |
| 140 | + setContentView(R.layout.activity_main); |
| 141 | + |
| 142 | + LocalBroadcastManager |
| 143 | + .getInstance(this) |
| 144 | + .registerReceiver( |
| 145 | + firebaseMessagingReceiver, |
| 146 | + new IntentFilter("<your_intent_name>")); |
| 147 | + } |
| 148 | + ``` |
| 149 | + |
| 150 | +7. Put the following code below the comment `<RECEIVE CHAT MESSAGES>` in `MainActivity`: |
| 151 | + |
| 152 | +```java |
| 153 | + startFcmPushNotification(); |
| 154 | + |
| 155 | + chatAsyncClient.addPushNotificationHandler(CHAT_MESSAGE_RECEIVED, (ChatEvent payload) -> { |
| 156 | + Log.i(TAG, "Push Notification CHAT_MESSAGE_RECEIVED."); |
| 157 | + ChatMessageReceivedEvent event = (ChatMessageReceivedEvent) payload; |
| 158 | + // You code to handle ChatMessageReceived event |
| 159 | + }); |
| 160 | +``` |
| 161 | + |
| 162 | +8. Add the `xmlns:tools` field to the `AndroidManifest.xml` file: |
| 163 | + |
| 164 | +``` |
| 165 | + <manifest xmlns:android="http://schemas.android.com/apk/res/android" |
| 166 | + xmlns:tools="http://schemas.android.com/tools" |
| 167 | + package="com.azure.android.communication.chat.sampleapp"> |
| 168 | +``` |
| 169 | + |
| 170 | +9. Disable the default initializer for `WorkManager` in `AndroidManifest.xml`: |
| 171 | + |
| 172 | +``` |
| 173 | + <!-- Disable the default initializer of WorkManager so that we could override it in MyAppConfiguration --> |
| 174 | + <provider |
| 175 | + android:name="androidx.startup.InitializationProvider" |
| 176 | + android:authorities="${applicationId}.androidx-startup" |
| 177 | + android:exported="false" |
| 178 | + tools:node="merge"> |
| 179 | + <!-- If you are using androidx.startup to initialize other components --> |
| 180 | + <meta-data |
| 181 | + android:name="androidx.work.WorkManagerInitializer" |
| 182 | + android:value="androidx.startup" |
| 183 | + tools:node="remove" /> |
| 184 | + </provider> |
| 185 | + <!-- End of Disabling default initializer of WorkManager --> |
| 186 | +``` |
| 187 | + |
| 188 | +10. Add the `WorkManager` dependency to your `build.gradle` file: |
| 189 | + |
| 190 | +``` |
| 191 | + def work_version = "2.7.1" |
| 192 | + implementation "androidx.work:work-runtime:$work_version" |
| 193 | +``` |
| 194 | + |
| 195 | +11. Add a custom `WorkManager` initializer by creating a class implementing `Configuration.Provider`: |
| 196 | + |
| 197 | +```java |
| 198 | +public class MyAppConfiguration extends Application implements Configuration.Provider { |
| 199 | + Consumer<Throwable> exceptionHandler = new Consumer<Throwable>() { |
| 200 | + @Override |
| 201 | + public void accept(Throwable throwable) { |
| 202 | + Log.i("YOUR_TAG", "Registration failed for push notifications!" + throwable.getMessage()); |
| 203 | + } |
| 204 | + }; |
| 205 | + @Override |
| 206 | + public void onCreate() { |
| 207 | + super.onCreate(); |
| 208 | + WorkManager.initialize(getApplicationContext(), getWorkManagerConfiguration()); |
| 209 | + } |
| 210 | + @NonNull |
| 211 | + @Override |
| 212 | + public Configuration getWorkManagerConfiguration() { |
| 213 | + return new Configuration.Builder(). |
| 214 | + setWorkerFactory(new RegistrationRenewalWorkerFactory(COMMUNICATION_TOKEN_CREDENTIAL, exceptionHandler)).build(); |
| 215 | + } |
| 216 | +} |
| 217 | +``` |
| 218 | + |
| 219 | +12. Add the `android:name=.MyAppConfiguration` field, which uses the class name from step 11, into `AndroidManifest.xml`: |
| 220 | + |
| 221 | +``` |
| 222 | +<application |
| 223 | + android:allowBackup="true" |
| 224 | + android:icon="@mipmap/ic_launcher" |
| 225 | + android:label="@string/app_name" |
| 226 | + android:roundIcon="@mipmap/ic_launcher_round" |
| 227 | + android:theme="@style/Theme.AppCompat" |
| 228 | + android:supportsRtl="true" |
| 229 | + android:name=".MyAppConfiguration" |
| 230 | +> |
| 231 | +``` |
0 commit comments