Skip to content

Commit bff1ce9

Browse files
authored
Merge pull request #71 from Iterable/feature/MOB-109-custom-firebase-service-support
[MOB-109] Custom Firebase messaging service support
2 parents 99dfb6c + 98348e3 commit bff1ce9

File tree

7 files changed

+77
-19
lines changed

7 files changed

+77
-19
lines changed

README.md

+23-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,29 @@ compile 'com.iterable:iterableapi:3.0.5'
3434
compile 'com.google.firebase:firebase-messaging:X.X.X' // Min version 9.0.0
3535
```
3636

37-
See [Bintray](https://bintray.com/davidtruong/maven/Iterable-SDK) for the latest version of the Iterable Android SDK.
37+
See [Bintray](https://bintray.com/davidtruong/maven/Iterable-SDK) for the latest version of the Iterable Android SDK.
38+
39+
#### Handling Firebase push messages and tokens
40+
41+
The SDK adds a FirebaseMessagingService and FirebaseInstanceIdService to the app manifest automatically, so you don't have to do any extra setup to handle incoming push messages.
42+
If your application implements its own FirebaseMessagingService, make sure you forward `onMessageReceived` and `onNewToken` calls to `IterableFirebaseMessagingService.handleMessageReceived` and `IterableFirebaseInstanceIDService.handleTokenRefresh`, respectively:
43+
44+
```java
45+
public class MyFirebaseMessagingService extends FirebaseMessagingService {
46+
47+
@Override
48+
public void onMessageReceived(RemoteMessage remoteMessage) {
49+
IterableFirebaseMessagingService.handleMessageReceived(this, remoteMessage);
50+
}
51+
52+
@Override
53+
public void onNewToken(String s) {
54+
IterableFirebaseInstanceIDService.handleTokenRefresh();
55+
}
56+
}
57+
```
58+
59+
Note that `FirebaseInstanceIdService` is deprecated and replaced with `onNewToken` in recent versions of Firebase.
3860

3961
# Using the SDK
4062

iterableapi/src/main/AndroidManifest.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@
99
<service
1010
android:name="com.iterable.iterableapi.IterableFirebaseMessagingService"
1111
android:exported="false">
12-
<intent-filter>
12+
<intent-filter android:priority="-1">
1313
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
1414
</intent-filter>
1515
</service>
1616

1717
<service
1818
android:name="com.iterable.iterableapi.IterableFirebaseInstanceIDService"
1919
android:exported="false">
20-
<intent-filter>
20+
<intent-filter android:priority="-1">
2121
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
2222
</intent-filter>
2323
</service>

iterableapi/src/main/java/com/iterable/iterableapi/IterableApi.java

+4
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,10 @@ public void updateUser(JSONObject dataFields) {
754754
* user email or user ID is set before calling this method.
755755
*/
756756
public void registerForPush() {
757+
if (!checkSDKInitialization()) {
758+
return;
759+
}
760+
757761
if (config.pushIntegrationName == null) {
758762
IterableLogger.e(TAG, "registerForPush: pushIntegrationName is not set");
759763
return;

iterableapi/src/main/java/com/iterable/iterableapi/IterableFirebaseInstanceIDService.java

+8
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ public class IterableFirebaseInstanceIDService extends FirebaseInstanceIdService
1818

1919
@Override
2020
public void onTokenRefresh() {
21+
handleTokenRefresh();
22+
}
23+
24+
/**
25+
* Handles token refresh
26+
* Call this from a custom {@link FirebaseInstanceIdService} to register the new token with Iterable
27+
*/
28+
public static void handleTokenRefresh() {
2129
String registrationToken = FirebaseInstanceId.getInstance().getToken();
2230
IterableLogger.d(TAG, "New Firebase Token generated: " + registrationToken);
2331
IterableApi.getInstance().registerForPush();

iterableapi/src/main/java/com/iterable/iterableapi/IterableFirebaseMessagingService.java

+25-14
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
package com.iterable.iterableapi;
22

3-
import android.content.ComponentName;
43
import android.content.Context;
5-
import android.content.Intent;
6-
import android.content.pm.PackageManager;
74
import android.os.AsyncTask;
85
import android.os.Bundle;
96

@@ -18,40 +15,54 @@ public class IterableFirebaseMessagingService extends FirebaseMessagingService {
1815

1916
@Override
2017
public void onMessageReceived(RemoteMessage remoteMessage) {
21-
if (remoteMessage.getData().size() > 0) {
22-
Map<String,String> messageData = remoteMessage.getData();
23-
handlePushReceived(messageData);
24-
IterableLogger.d(TAG, "Message data payload: " + remoteMessage.getData());
18+
handleMessageReceived(this, remoteMessage);
19+
}
20+
21+
/**
22+
* Handles receiving an incoming push notification from the intent.
23+
*
24+
* Call this from a custom {@link FirebaseMessagingService} to pass Iterable push messages to
25+
* Iterable SDK for tracking and rendering
26+
* @param remoteMessage Remote message received from Firebase in
27+
* {@link FirebaseMessagingService#onMessageReceived(RemoteMessage)}
28+
* @return Boolean indicating whether it was an Iterable message or not
29+
*/
30+
public static boolean handleMessageReceived(Context context, RemoteMessage remoteMessage) {
31+
Map<String,String> messageData = remoteMessage.getData();
32+
33+
if (messageData == null || messageData.size() == 0) {
34+
return false;
2535
}
2636

37+
IterableLogger.d(TAG, "Message data payload: " + remoteMessage.getData());
2738
// Check if message contains a notification payload.
2839
if (remoteMessage.getNotification() != null) {
2940
IterableLogger.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
3041
}
31-
}
3242

33-
/**
34-
* Handles receiving an incoming push notification from the intent.
35-
* @param messageData
36-
*/
37-
private void handlePushReceived(Map<String,String> messageData) {
3843
Bundle extras = new Bundle();
3944
for (Map.Entry<String, String> entry : messageData.entrySet()) {
4045
extras.putString(entry.getKey(), entry.getValue());
4146
}
4247

48+
if (!IterableNotificationBuilder.isIterablePush(extras)) {
49+
IterableLogger.d(TAG, "Not an Iterable push message");
50+
return false;
51+
}
52+
4353
if (!IterableNotificationBuilder.isGhostPush(extras)) {
4454
if (!IterableNotificationBuilder.isEmptyBody(extras)) {
4555
IterableLogger.d(TAG, "Iterable push received " + messageData);
4656
IterableNotificationBuilder notificationBuilder = IterableNotificationBuilder.createNotification(
47-
getApplicationContext(), extras);
57+
context.getApplicationContext(), extras);
4858
new IterableNotificationManager().execute(notificationBuilder);
4959
} else {
5060
IterableLogger.d(TAG, "Iterable OS notification push received");
5161
}
5262
} else {
5363
IterableLogger.d(TAG, "Iterable ghost silent push received");
5464
}
65+
return true;
5566
}
5667
}
5768

iterableapi/src/main/java/com/iterable/iterableapi/IterableNotificationBuilder.java

+4
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,10 @@ private static int getIconId(Context context) {
376376
return iconId;
377377
}
378378

379+
static boolean isIterablePush(Bundle extras) {
380+
return extras != null && extras.containsKey(IterableConstants.ITERABLE_DATA_KEY);
381+
}
382+
379383
/**
380384
* Returns if the given notification is a ghost/silent push notification
381385
*

iterableapi/src/test/java/com/iterable/iterableapi/IterableFirebaseMessagingServiceTest.java

+11-2
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,24 @@
1313
import org.junit.Before;
1414
import org.junit.Test;
1515
import org.mockito.ArgumentCaptor;
16+
import org.mockito.Mockito;
1617
import org.powermock.api.mockito.PowerMockito;
1718
import org.powermock.core.MockRepository;
1819
import org.powermock.core.classloader.annotations.PrepareForTest;
1920
import org.robolectric.Robolectric;
2021
import org.robolectric.RuntimeEnvironment;
2122
import org.robolectric.android.controller.ServiceController;
2223

24+
import java.util.HashMap;
25+
import java.util.Map;
26+
2327
import okhttp3.mockwebserver.MockWebServer;
2428

2529
import static com.iterable.iterableapi.unit.IterableTestUtils.bundleToMap;
2630
import static com.iterable.iterableapi.unit.IterableTestUtils.getMapFromJsonResource;
31+
import static junit.framework.Assert.assertEquals;
2732
import static junit.framework.Assert.assertTrue;
33+
import static org.mockito.ArgumentMatchers.any;
2834
import static org.mockito.ArgumentMatchers.eq;
2935
import static org.mockito.Mockito.mock;
3036
import static org.mockito.Mockito.spy;
@@ -72,15 +78,18 @@ public void tearDown() throws Exception {
7278
@Test
7379
public void testOnMessageReceived() throws Exception {
7480
PowerMockito.mockStatic(IterableNotificationBuilder.class);
81+
Mockito.when(IterableNotificationBuilder.isIterablePush(any(Bundle.class))).thenCallRealMethod();
7582

7683
RemoteMessage.Builder builder = new RemoteMessage.Builder("[email protected]");
77-
builder.setData(getMapFromJsonResource("push_payload_custom_action.json"));
84+
builder.addData(IterableConstants.ITERABLE_DATA_KEY, IterableTestUtils.getResourceString("push_payload_custom_action.json"));
7885
controller.get().onMessageReceived(builder.build());
7986

8087
PowerMockito.verifyStatic(IterableNotificationBuilder.class);
8188
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
8289
IterableNotificationBuilder.createNotification(eq(RuntimeEnvironment.application), bundleCaptor.capture());
83-
assertTrue(bundleToMap(bundleCaptor.getValue()).equals(getMapFromJsonResource("push_payload_custom_action.json")));
90+
Map<String, String> expectedPayload = new HashMap<>();
91+
expectedPayload.put(IterableConstants.ITERABLE_DATA_KEY, IterableTestUtils.getResourceString("push_payload_custom_action.json"));
92+
assertEquals(expectedPayload, bundleToMap(bundleCaptor.getValue()));
8493
}
8594

8695
}

0 commit comments

Comments
 (0)