How To Send Firebase Notifications To And From Two Separate Apps With Different Package Names Using Retrofit

The first thing you are going to need is to create a Firebase project. And then, in that same project, add the two apps that you want to communicate with each other (here, the assumption is that you have already created the actual apps in Android Studio). After you have created the apps in Android Studio and added them to Firebase, download the JSON file of the last app that you added. This is important. Don’t download different JSON files. Don’t download the JSON file of the first app you added. Download the latest JSON file from the last app that you added. Place the google-services.json file you just downloaded into the Android app module root directory of both your apps. The google-services.json file is the configuration file containing keys and identifiers for your project and app, or in this case apps, and helps them to know about each other. Think of it as if they are in the same room and are able to talk to each other. This is the most important part.

You are going to need an interface that authorizes the sending and receiving of FCM API as in the example below.

public interface APIService {
@Headers(
{
"Content-Type:application/json",
"Authorization:key=PUT_SERVER_KEY_HERE" // Your server key
}
)

@POST("fcm/send")
Call<MyResponse> sendNotification(@Body NotificationSender body);
}

You are going to need to set, get and update tokens. The token is what is used for sending messages to an application instance, a sort of identifier. This is handled in a Firebase Id Service which extends the FirebaseMessagingService.

public class Token {
private String token;

public Token(String token) {
this.token = token;
}

public Token() {
}

public String getToken() {
return token;
}

public void setToken(String token) {
this.token = token;
}
}

Most APIs have some authentication to secure access to it. The above calls for authentication and logging are going to be handled by Retrofit. Retrofit is a type-safe HTTP client for Android and Java. It needs the base URL which is going to be used for every service call and a converter factory, which takes care of the parsing of data we’re sending and also the responses we get.

public class Client {
private static Retrofit retrofit = null;

public static Retrofit getClient(String url) {
if (retrofit == null) {
retrofit = new Retrofit.Builder().baseUrl(url).addConverterFactory(GsonConverterFactory.create()).build();
}
return retrofit;
}

Here is the rest of the code.

To set and get data, you are going to need a data.java class.

public class Data {
private String Title;
private String Message;

public Data(String title, String message) {
Title = title;
Message = message;
}

public Data() {
}

public String getTitle() {
return Title;
}

public void setTitle(String title) {
Title = title;
}

public String getMessage() {
return Message;
}

public void setMessage(String message) {
Message = message;
}

}

You are going to need a FirebaseIdService.java class.

public class MyFirebaseIdService extends FirebaseMessagingService {

@Override
public void onNewToken(@NonNull String s) {
super.onNewToken(s);
FirebaseUser firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
String refreshToken = FirebaseInstanceId.getInstance().getToken();
if (firebaseUser != null) {
updateToken(refreshToken);
}
}

private void updateToken(String refreshToken) {
FirebaseUser firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
Token token1 = new Token(refreshToken);
FirebaseDatabase.getInstance().getReference("Tokens").child(Objects.requireNonNull(FirebaseAuth.getInstance().getCurrentUser()).getUid()).setValue(token1);
}
}

You are going to need the FirebaseMessagingService.java class.

public class MyFireBaseMessagingService extends FirebaseMessagingService {
String title, message;

@Override
public void onMessageReceived(@NonNull RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
title = remoteMessage.getData().get("Title");
message = remoteMessage.getData().get("Message");

NotificationCompat.Builder builder =
new NotificationCompat.Builder(getApplicationContext())
.setSmallIcon(R.drawable.common_google_signin_btn_icon_dark)
.setContentTitle(title)
.setContentText(message);
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(0, builder.build());
}

@Override
public void onNewToken(@NonNull String s) {
super.onNewToken(s);
}

}

A Response.java class to handle the responses.

public class MyResponse {
public int success;

}

A NotificationSender.java class.

public class NotificationSender {
public Data data;
public String to;

public NotificationSender(Data data, String to) {
this.data = data;
this.to = to;
}

public NotificationSender() {
}
}

With all this in place, you now need to create two methods in whichever activity you want to send the notification from, UpdateToken() to update your tokens whenever they change, and sendNotifications(), which you will use to send the notifications.

private void UpdateToken() {
FirebaseUser firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
String refreshToken = FirebaseInstanceId.getInstance().getToken();
Token token = new Token(refreshToken);
FirebaseDatabase.getInstance().getReference("Tokens").child(Objects.requireNonNull(FirebaseAuth.getInstance().getCurrentUser()).getUid()).setValue(token);
}

public void sendNotifications(String usertoken, String title, String message) {
Data data = new Data(title, message);
NotificationSender sender = new NotificationSender(data, usertoken);
apiService.sendNotification(sender).enqueue(new Callback<MyResponse>() {
@Override
public void onResponse(@NonNull Call<MyResponse> call, @NonNull Response<MyResponse> response) {
if (response.code() == 200) {
assert response.body() != null;
if (response.body().success != 1) {
Toast.makeText(Main.this, "Failed ", Toast.LENGTH_LONG).show();
}
}
}

@Override
public void onFailure(@NonNull Call<MyResponse> call, @NonNull Throwable t) {

}
});
}

And lastly, you are going to need to call the UpdateToken() method from your OnCreate(), and then pass the data that you want to send to the parameters of the sendNotifications() method, from a button click, for example. Remember to pass the user ID of the user you want to send the notification to in:

UpdateToken();

You can either pass the user ID manually or dynamically, and you can get this from the Firebase Realtime Database. To send to multiple users, implement some sort of a loop.

Don’t forget to add all the appropriate dependencies:

implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'

And to register all the relevant activities in the manifest:

<!-- [START firebase_service] -->
<service
android:name=".MyFireBaseMessagingService"
android:enabled="true"
android:exported="false"
>
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<service
android:name=".MyFirebaseIdService"
android:enabled="true"
android:exported="false"
>
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<!-- [END firebase_service] -->

All of these classes and interfaces have to be implemented in both apps. That’s all. Happy coding.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store