From 14537af498ca762d8191bbb4147292c38d00ea64 Mon Sep 17 00:00:00 2001 From: Yvonne Pan <103622026+yvonnep165@users.noreply.github.com> Date: Thu, 21 May 2026 12:49:33 -0400 Subject: [PATCH 1/4] Enable fid and deprecate token for Message Class --- .../google/firebase/messaging/Message.java | 37 ++++++++++++++++++- .../firebase/messaging/MessageTest.java | 22 +++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/google/firebase/messaging/Message.java b/src/main/java/com/google/firebase/messaging/Message.java index 1514fce3d..da790fa7f 100644 --- a/src/main/java/com/google/firebase/messaging/Message.java +++ b/src/main/java/com/google/firebase/messaging/Message.java @@ -54,9 +54,16 @@ public class Message { @Key("apns") private final ApnsConfig apnsConfig; + /** + * @deprecated Use {@link #fid} instead. + */ + @Deprecated @Key("token") private final String token; + @Key("fid") + private final String fid; + @Key("topic") private final String topic; @@ -74,11 +81,14 @@ private Message(Builder builder) { this.apnsConfig = builder.apnsConfig; int count = Booleans.countTrue( !Strings.isNullOrEmpty(builder.token), + !Strings.isNullOrEmpty(builder.fid), !Strings.isNullOrEmpty(builder.topic), !Strings.isNullOrEmpty(builder.condition) ); - checkArgument(count == 1, "Exactly one of token, topic or condition must be specified"); + checkArgument(count == 1, + "Exactly one of token, fid, topic or condition must be specified"); this.token = builder.token; + this.fid = builder.fid; this.topic = stripPrefix(builder.topic); this.condition = builder.condition; this.fcmOptions = builder.fcmOptions; @@ -109,11 +119,20 @@ ApnsConfig getApnsConfig() { return apnsConfig; } + /** + * @deprecated Use {@link #getFid()} instead. + */ + @Deprecated @VisibleForTesting String getToken() { return token; } + @VisibleForTesting + String getFid() { + return fid; + } + @VisibleForTesting String getTopic() { return topic; @@ -166,7 +185,9 @@ public static class Builder { private AndroidConfig androidConfig; private WebpushConfig webpushConfig; private ApnsConfig apnsConfig; + @Deprecated private String token; + private String fid; private String topic; private String condition; private FcmOptions fcmOptions; @@ -222,12 +243,26 @@ public Builder setApnsConfig(ApnsConfig apnsConfig) { * * @param token A valid device registration token. * @return This builder. + * @deprecated Use {@link #setFid(String)} instead. */ + @Deprecated public Builder setToken(String token) { this.token = token; return this; } + /** + * Sets the Firebase Installation ID (FID) of the app instance to which the message + * should be sent. + * + * @param fid A valid Firebase Installation ID. + * @return This builder. + */ + public Builder setFid(String fid) { + this.fid = fid; + return this; + } + /** * Sets the name of the FCM topic to which the message should be sent. Topic names may * contain the {@code /topics/} prefix. diff --git a/src/test/java/com/google/firebase/messaging/MessageTest.java b/src/test/java/com/google/firebase/messaging/MessageTest.java index 94ca4fa4a..0bca10df1 100644 --- a/src/test/java/com/google/firebase/messaging/MessageTest.java +++ b/src/test/java/com/google/firebase/messaging/MessageTest.java @@ -54,6 +54,28 @@ public void testEmptyMessage() throws IOException { Message.builder().setCondition("'foo' in topics").build()); assertJsonEquals(ImmutableMap.of("token", "test-token"), Message.builder().setToken("test-token").build()); + assertJsonEquals(ImmutableMap.of("fid", "test-fid"), + Message.builder().setFid("test-fid").build()); + } + + @Test + public void testMultipleTargets() { + List builders = ImmutableList.of( + Message.builder().setToken("token").setFid("fid"), + Message.builder().setToken("token").setTopic("topic"), + Message.builder().setFid("fid").setCondition("cond"), + Message.builder().setTopic("topic").setCondition("cond"), + Message.builder().setToken("token").setFid("fid").setTopic("topic").setCondition("cond") + ); + for (int i = 0; i < builders.size(); i++) { + try { + builders.get(i).build(); + fail("No error thrown for multiple targets: " + i); + } catch (IllegalArgumentException expected) { + assertEquals("Exactly one of token, fid, topic or condition must be specified", + expected.getMessage()); + } + } } @Test From b75992ddb3fa305e59c2b97b2a31db43a8b62f10 Mon Sep 17 00:00:00 2001 From: Yvonne Pan <103622026+yvonnep165@users.noreply.github.com> Date: Thu, 21 May 2026 15:48:23 -0400 Subject: [PATCH 2/4] Add fid supported methods and deprecate the token methods for the MulticastMessage Class --- .../firebase/messaging/MulticastMessage.java | 81 ++++++++++++-- .../messaging/MulticastMessageTest.java | 101 ++++++++++++++++++ 2 files changed, 171 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/google/firebase/messaging/MulticastMessage.java b/src/main/java/com/google/firebase/messaging/MulticastMessage.java index cc43b187b..b1f24770c 100644 --- a/src/main/java/com/google/firebase/messaging/MulticastMessage.java +++ b/src/main/java/com/google/firebase/messaging/MulticastMessage.java @@ -45,7 +45,9 @@ */ public class MulticastMessage { + @Deprecated private final List tokens; + private final List fids; private final Map data; private final Notification notification; private final AndroidConfig androidConfig; @@ -55,11 +57,18 @@ public class MulticastMessage { private MulticastMessage(Builder builder) { this.tokens = builder.tokens.build(); - checkArgument(!this.tokens.isEmpty(), "at least one token must be specified"); - checkArgument(this.tokens.size() <= 500, "no more than 500 tokens can be specified"); + this.fids = builder.fids.build(); + int tokensSize = this.tokens.size(); + int fidsSize = this.fids.size(); + checkArgument(tokensSize + fidsSize > 0, "at least one token or fid must be specified"); + checkArgument(tokensSize + fidsSize <= 500, + "no more than 500 tokens and fids combined can be specified"); for (String token : this.tokens) { checkArgument(!Strings.isNullOrEmpty(token), "none of the tokens can be null or empty"); } + for (String fid : this.fids) { + checkArgument(!Strings.isNullOrEmpty(fid), "none of the fids can be null or empty"); + } this.data = builder.data.isEmpty() ? null : ImmutableMap.copyOf(builder.data); this.notification = builder.notification; this.androidConfig = builder.androidConfig; @@ -69,6 +78,26 @@ private MulticastMessage(Builder builder) { } List getMessageList() { + ImmutableList.Builder messages = ImmutableList.builder(); + + if (!this.tokens.isEmpty()) { + Message.Builder tokenBuilder = getMetadataBuilder(); + for (String token : this.tokens) { + messages.add(tokenBuilder.setToken(token).build()); + } + } + + if (!this.fids.isEmpty()) { + Message.Builder fidBuilder = getMetadataBuilder(); + for (String fid : this.fids) { + messages.add(fidBuilder.setFid(fid).build()); + } + } + + return messages.build(); + } + + private Message.Builder getMetadataBuilder() { Message.Builder builder = Message.builder() .setNotification(this.notification) .setAndroidConfig(this.androidConfig) @@ -78,11 +107,7 @@ List getMessageList() { if (this.data != null) { builder.putAllData(this.data); } - ImmutableList.Builder messages = ImmutableList.builder(); - for (String token : this.tokens) { - messages.add(builder.setToken(token).build()); - } - return messages.build(); + return builder; } /** @@ -96,7 +121,9 @@ public static Builder builder() { public static class Builder { + @Deprecated private final ImmutableList.Builder tokens = ImmutableList.builder(); + private final ImmutableList.Builder fids = ImmutableList.builder(); private final Map data = new HashMap<>(); private Notification notification; private AndroidConfig androidConfig; @@ -107,29 +134,61 @@ public static class Builder { private Builder() {} /** - * Adds a token to which the message should be sent. Up to 500 tokens can be specified on - * a single instance of {@link MulticastMessage}. + * Adds a token to which the message should be sent. Up to 500 tokens + * and FIDs combined can be specified on a single instance of + * {@link MulticastMessage}. * * @param token A non-null, non-empty Firebase device registration token. * @return This builder. + * @deprecated Use {@link #addFid(String)} instead. */ + @Deprecated public Builder addToken(@NonNull String token) { this.tokens.add(token); return this; } /** - * Adds a collection of tokens to which the message should be sent. Up to 500 tokens can be - * specified on a single instance of {@link MulticastMessage}. + * Adds a Firebase Installation ID (FID) to which the message should be sent. + * Up to 500 tokens and FIDs combined can be specified on a single instance + * of {@link MulticastMessage}. + * + * @param fid A non-null, non-empty Firebase Installation ID. + * @return This builder. + */ + public Builder addFid(@NonNull String fid) { + this.fids.add(fid); + return this; + } + + /** + * Adds a collection of tokens to which the message should be sent. Up to 500 + * tokens and FIDs combined can be specified on a single instance of + * {@link MulticastMessage}. * * @param tokens Collection of Firebase device registration tokens. * @return This builder. + * @deprecated Use {@link #addAllFids(Collection)} instead. */ + @Deprecated public Builder addAllTokens(@NonNull Collection tokens) { this.tokens.addAll(tokens); return this; } + /** + * Adds a collection of Firebase Installation IDs (FIDs) to which the message + * should be sent. Up to 500 tokens and FIDs combined can be specified on a + * single instance of {@link MulticastMessage}. + * + * @param fids Collection of Firebase Installation IDs. + * @return This builder. + */ + public Builder addAllFids(@NonNull Collection fids) { + this.fids.addAll(fids); + return this; + } + /** * Sets the notification information to be included in the message. * diff --git a/src/test/java/com/google/firebase/messaging/MulticastMessageTest.java b/src/test/java/com/google/firebase/messaging/MulticastMessageTest.java index aa0dae10c..481ccccc9 100644 --- a/src/test/java/com/google/firebase/messaging/MulticastMessageTest.java +++ b/src/test/java/com/google/firebase/messaging/MulticastMessageTest.java @@ -86,6 +86,21 @@ public void testTooManyTokens() { } } + @Test + public void testTooManyFids() { + MulticastMessage.Builder builder = MulticastMessage.builder(); + for (int i = 0; i < 501; i++) { + builder.addFid("fid" + i); + } + try { + builder.build(); + fail("No error thrown for more than 500 fids"); + } catch (IllegalArgumentException expected) { + assertEquals("no more than 500 tokens and fids combined can be specified", + expected.getMessage()); + } + } + @Test(expected = NullPointerException.class) public void testNullToken() { MulticastMessage.builder().addToken(null).build(); @@ -96,6 +111,92 @@ public void testEmptyToken() { MulticastMessage.builder().addToken("").build(); } + @Test + public void testMulticastMessageFids() { + MulticastMessage multicastMessage = MulticastMessage.builder() + .setAndroidConfig(ANDROID) + .setApnsConfig(APNS) + .setWebpushConfig(WEBPUSH) + .setNotification(NOTIFICATION) + .setFcmOptions(FCM_OPTIONS) + .putData("key1", "value1") + .putAllData(ImmutableMap.of("key2", "value2")) + .addFid("fid1") + .addAllFids(ImmutableList.of("fid2", "fid3")) + .build(); + + List messages = multicastMessage.getMessageList(); + + assertEquals(3, messages.size()); + for (int i = 0; i < 3; i++) { + Message message = messages.get(i); + assertMessageFid(message, "fid" + (i + 1)); + } + } + + @Test + public void testMulticastMessageMixed() { + MulticastMessage multicastMessage = MulticastMessage.builder() + .setAndroidConfig(ANDROID) + .setApnsConfig(APNS) + .setWebpushConfig(WEBPUSH) + .setNotification(NOTIFICATION) + .setFcmOptions(FCM_OPTIONS) + .putData("key1", "value1") + .putAllData(ImmutableMap.of("key2", "value2")) + .addToken("token1") + .addFid("fid1") + .addToken("token2") + .addFid("fid2") + .build(); + + List messages = multicastMessage.getMessageList(); + + assertEquals(4, messages.size()); + assertMessage(messages.get(0), "token1"); + assertMessage(messages.get(1), "token2"); + assertMessageFid(messages.get(2), "fid1"); + assertMessageFid(messages.get(3), "fid2"); + } + + @Test + public void testTooManyTargetsCombined() { + MulticastMessage.Builder builder = MulticastMessage.builder(); + for (int i = 0; i < 250; i++) { + builder.addToken("token" + i); + } + for (int i = 0; i < 251; i++) { + builder.addFid("fid" + i); + } + try { + builder.build(); + fail("No error thrown for more than 500 combined targets"); + } catch (IllegalArgumentException expected) { + assertEquals("no more than 500 tokens and fids combined can be specified", + expected.getMessage()); + } + } + + @Test(expected = NullPointerException.class) + public void testNullFid() { + MulticastMessage.builder().addFid(null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void testEmptyFid() { + MulticastMessage.builder().addFid("").build(); + } + + private void assertMessageFid(Message message, String expectedFid) { + assertSame(ANDROID, message.getAndroidConfig()); + assertSame(APNS, message.getApnsConfig()); + assertSame(WEBPUSH, message.getWebpushConfig()); + assertSame(NOTIFICATION, message.getNotification()); + assertSame(FCM_OPTIONS, message.getFcmOptions()); + assertEquals(ImmutableMap.of("key1", "value1", "key2", "value2"), message.getData()); + assertEquals(expectedFid, message.getFid()); + } + private void assertMessage(Message message, String expectedToken) { assertSame(ANDROID, message.getAndroidConfig()); assertSame(APNS, message.getApnsConfig()); From 57e3cccf44a136784265b4b01112eeb7bb0c284a Mon Sep 17 00:00:00 2001 From: Yvonne Pan <103622026+yvonnep165@users.noreply.github.com> Date: Thu, 21 May 2026 16:30:25 -0400 Subject: [PATCH 3/4] Add integration tests and update all public multicast send methods --- .../firebase/messaging/FirebaseMessaging.java | 40 ++++++++------- .../messaging/FirebaseMessagingIT.java | 51 +++++++++++++++++++ 2 files changed, 73 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/google/firebase/messaging/FirebaseMessaging.java b/src/main/java/com/google/firebase/messaging/FirebaseMessaging.java index bb7b8208f..2b36e8c72 100644 --- a/src/main/java/com/google/firebase/messaging/FirebaseMessaging.java +++ b/src/main/java/com/google/firebase/messaging/FirebaseMessaging.java @@ -265,12 +265,13 @@ protected SendResponse execute() { } /** - * Sends the given multicast message to all the FCM registration tokens specified in it. + * Sends the given multicast message to all the FCM registration tokens and/or FIDs + * specified in it. * *

This method uses the {@link #sendEach(List)} API under the hood to send the given * message to all the target recipients. The list of responses obtained by calling * {@link BatchResponse#getResponses()} on the return value is in the same order as the - * tokens in the {@link MulticastMessage}. + * tokens and/or FIDs in the {@link MulticastMessage}. * * @param message A non-null {@link MulticastMessage} * @return A {@link BatchResponse} indicating the result of the operation. @@ -285,17 +286,18 @@ public BatchResponse sendEachForMulticast( } /** - * Sends the given multicast message to all the FCM registration tokens specified in it. + * Sends the given multicast message to all the FCM registration tokens and/or FIDs + * specified in it. * - *

If the {@code dryRun} option is set to true, the message will not be actually sent. Instead - * FCM performs all the necessary validations, and emulates the send operation. The {@code dryRun} - * option is useful for determining whether an FCM registration has been deleted. But it cannot be - * used to validate APNs tokens. + *

If the {@code dryRun} option is set to true, the message will not be actually sent. + * Instead FCM performs all the necessary validations, and emulates the send operation. + * The {@code dryRun} option is useful for determining whether an FCM registration has + * been deleted. But it cannot be used to validate APNs tokens. * *

This method uses the {@link #sendEach(List)} API under the hood to send the given * message to all the target recipients. The list of responses obtained by calling * {@link BatchResponse#getResponses()} on the return value is in the same order as the - * tokens in the {@link MulticastMessage}. + * tokens and/or FIDs in the {@link MulticastMessage}. * * @param message A non-null {@link MulticastMessage}. * @param dryRun A boolean indicating whether to perform a dry run (validation only) of the send. @@ -417,12 +419,13 @@ public ApiFuture sendAllAsync( } /** - * Sends the given multicast message to all the FCM registration tokens specified in it. + * Sends the given multicast message to all the FCM registration tokens and/or FIDs + * specified in it. * *

This method uses the {@link #sendAll(List)} API under the hood to send the given * message to all the target recipients. The responses list obtained by calling - * {@link BatchResponse#getResponses()} on the return value corresponds to the order of tokens - * in the {@link MulticastMessage}. + * {@link BatchResponse#getResponses()} on the return value corresponds to the order of + * tokens and/or FIDs in the {@link MulticastMessage}. * * @param message A non-null {@link MulticastMessage} * @return A {@link BatchResponse} indicating the result of the operation. @@ -439,17 +442,18 @@ public BatchResponse sendMulticast( } /** - * Sends the given multicast message to all the FCM registration tokens specified in it. + * Sends the given multicast message to all the FCM registration tokens and/or FIDs + * specified in it. * - *

If the {@code dryRun} option is set to true, the message will not be actually sent. Instead - * FCM performs all the necessary validations, and emulates the send operation. The {@code dryRun} - * option is useful for determining whether an FCM registration has been deleted. But it cannot be - * used to validate APNs tokens. + *

If the {@code dryRun} option is set to true, the message will not be actually sent. + * Instead FCM performs all the necessary validations, and emulates the send operation. + * The {@code dryRun} option is useful for determining whether an FCM registration has + * been deleted. But it cannot be used to validate APNs tokens. * *

This method uses the {@link #sendAll(List)} API under the hood to send the given * message to all the target recipients. The responses list obtained by calling - * {@link BatchResponse#getResponses()} on the return value corresponds to the order of tokens - * in the {@link MulticastMessage}. + * {@link BatchResponse#getResponses()} on the return value corresponds to the order of + * tokens and/or FIDs in the {@link MulticastMessage}. * * @param message A non-null {@link MulticastMessage}. * @param dryRun A boolean indicating whether to perform a dry run (validation only) of the send. diff --git a/src/test/java/com/google/firebase/messaging/FirebaseMessagingIT.java b/src/test/java/com/google/firebase/messaging/FirebaseMessagingIT.java index e084b8c29..9bdbf6a04 100644 --- a/src/test/java/com/google/firebase/messaging/FirebaseMessagingIT.java +++ b/src/test/java/com/google/firebase/messaging/FirebaseMessagingIT.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import com.google.api.client.http.HttpResponseException; import com.google.common.collect.ImmutableList; @@ -97,6 +98,28 @@ public void testSendError() throws InterruptedException { } } + @Test + public void testSendFidError() throws InterruptedException { + FirebaseMessaging messaging = FirebaseMessaging.getInstance(); + Message message = Message.builder() + .setNotification(Notification.builder() + .setTitle("Title") + .setBody("Body") + .build()) + .setFid("not-a-fid") + .build(); + try { + messaging.sendAsync(message, true).get(); + fail("No exception thrown for invalid FID"); + } catch (ExecutionException e) { + FirebaseMessagingException cause = (FirebaseMessagingException) e.getCause(); + assertEquals(ErrorCode.INVALID_ARGUMENT, cause.getErrorCode()); + assertEquals(MessagingErrorCode.INVALID_ARGUMENT, cause.getMessagingErrorCode()); + assertNotNull(cause.getHttpResponse()); + assertTrue(cause.getCause() instanceof HttpResponseException); + } + } + @Test public void testSendEach() throws Exception { List messages = new ArrayList<>(); @@ -194,6 +217,34 @@ public void testSendEachForMulticast() throws Exception { } } + @Test + public void testSendEachForMulticastFidsError() throws Exception { + MulticastMessage multicastMessage = MulticastMessage.builder() + .setNotification(Notification.builder() + .setTitle("Title") + .setBody("Body") + .build()) + .addFid("not-a-fid") + .addFid("also-not-a-fid") + .build(); + + BatchResponse response = FirebaseMessaging.getInstance().sendEachForMulticast( + multicastMessage, true); + + assertEquals(0, response.getSuccessCount()); + assertEquals(2, response.getFailureCount()); + assertEquals(2, response.getResponses().size()); + for (SendResponse sendResponse : response.getResponses()) { + assertFalse(sendResponse.isSuccessful()); + assertNull(sendResponse.getMessageId()); + assertNotNull(sendResponse.getException()); + assertEquals(ErrorCode.INVALID_ARGUMENT, + sendResponse.getException().getErrorCode()); + assertEquals(MessagingErrorCode.INVALID_ARGUMENT, + sendResponse.getException().getMessagingErrorCode()); + } + } + @Test public void testSubscribe() throws Exception { FirebaseMessaging messaging = FirebaseMessaging.getInstance(); From da5efd9b202eae0adab6d9dc209a11635c0bc9ef Mon Sep 17 00:00:00 2001 From: Yvonne Pan <103622026+yvonnep165@users.noreply.github.com> Date: Thu, 21 May 2026 19:54:38 -0400 Subject: [PATCH 4/4] Update docstring --- .../firebase/messaging/FirebaseMessaging.java | 12 ++++++++---- .../firebase/messaging/MulticastMessage.java | 16 +++++++++------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/google/firebase/messaging/FirebaseMessaging.java b/src/main/java/com/google/firebase/messaging/FirebaseMessaging.java index 2b36e8c72..0e9831588 100644 --- a/src/main/java/com/google/firebase/messaging/FirebaseMessaging.java +++ b/src/main/java/com/google/firebase/messaging/FirebaseMessaging.java @@ -271,7 +271,8 @@ protected SendResponse execute() { *

This method uses the {@link #sendEach(List)} API under the hood to send the given * message to all the target recipients. The list of responses obtained by calling * {@link BatchResponse#getResponses()} on the return value is in the same order as the - * tokens and/or FIDs in the {@link MulticastMessage}. + * tokens and/or FIDs in the {@link MulticastMessage}. If both tokens and FIDs are + * provided, tokens are processed first, followed by FIDs. * * @param message A non-null {@link MulticastMessage} * @return A {@link BatchResponse} indicating the result of the operation. @@ -297,7 +298,8 @@ public BatchResponse sendEachForMulticast( *

This method uses the {@link #sendEach(List)} API under the hood to send the given * message to all the target recipients. The list of responses obtained by calling * {@link BatchResponse#getResponses()} on the return value is in the same order as the - * tokens and/or FIDs in the {@link MulticastMessage}. + * tokens and/or FIDs in the {@link MulticastMessage}. If both tokens and FIDs are + * provided, tokens are processed first, followed by FIDs. * * @param message A non-null {@link MulticastMessage}. * @param dryRun A boolean indicating whether to perform a dry run (validation only) of the send. @@ -425,7 +427,8 @@ public ApiFuture sendAllAsync( *

This method uses the {@link #sendAll(List)} API under the hood to send the given * message to all the target recipients. The responses list obtained by calling * {@link BatchResponse#getResponses()} on the return value corresponds to the order of - * tokens and/or FIDs in the {@link MulticastMessage}. + * tokens and/or FIDs in the {@link MulticastMessage}. If both tokens and FIDs are + * provided, tokens are processed first, followed by FIDs. * * @param message A non-null {@link MulticastMessage} * @return A {@link BatchResponse} indicating the result of the operation. @@ -453,7 +456,8 @@ public BatchResponse sendMulticast( *

This method uses the {@link #sendAll(List)} API under the hood to send the given * message to all the target recipients. The responses list obtained by calling * {@link BatchResponse#getResponses()} on the return value corresponds to the order of - * tokens and/or FIDs in the {@link MulticastMessage}. + * tokens and/or FIDs in the {@link MulticastMessage}. If both tokens and FIDs are + * provided, tokens are processed first, followed by FIDs. * * @param message A non-null {@link MulticastMessage}. * @param dryRun A boolean indicating whether to perform a dry run (validation only) of the send. diff --git a/src/main/java/com/google/firebase/messaging/MulticastMessage.java b/src/main/java/com/google/firebase/messaging/MulticastMessage.java index b1f24770c..a880a88f2 100644 --- a/src/main/java/com/google/firebase/messaging/MulticastMessage.java +++ b/src/main/java/com/google/firebase/messaging/MulticastMessage.java @@ -30,18 +30,20 @@ /** * Represents a message that can be sent to multiple devices via Firebase Cloud Messaging (FCM). - * Contains payload information as well as the list of device registration tokens to which the - * message should be sent. A single {@code MulticastMessage} may contain up to 500 registration - * tokens. + * Contains payload information as well as the list of device registration tokens and/or + * Firebase Installation IDs (FIDs) to which the message should be sent. A single + * {@code MulticastMessage} may contain up to 500 registration tokens and FIDs combined. * *

Instances of this class are thread-safe and immutable. Use {@link MulticastMessage.Builder} * to create new instances. See {@link FirebaseMessaging#sendMulticast(MulticastMessage)} for * details on how to send the message to FCM for multicast delivery. * - *

This class and the associated Builder retain the order of tokens. Therefore the order of - * the responses list obtained by calling {@link BatchResponse#getResponses()} on the return value - * of {@link FirebaseMessaging#sendMulticast(MulticastMessage)} corresponds to the order in which - * tokens were added to the {@link MulticastMessage.Builder}. + *

This class and the associated Builder retain the order of tokens and FIDs. Therefore + * the order of the responses list obtained by calling {@link BatchResponse#getResponses()} + * on the return value of {@link FirebaseMessaging#sendMulticast(MulticastMessage)} + * corresponds to the order in which targets were added to the + * {@link MulticastMessage.Builder}. If both tokens and FIDs are provided, tokens are + * processed first, followed by FIDs. */ public class MulticastMessage {