0

I'm asking how I can send a notification to a specific user device by using the FCM token. The token is stored in the RealtimeDatabase in Firebase which is structured like this:

project-name: {
   users: {
      username: {
         name: "..."
         token: "..."
      }
   }
}

This is the code I use to store the token

    FirebaseInstanceId.getInstance().getInstanceId().addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
    @Override
    public void onComplete(@NonNull Task<InstanceIdResult> task) {
       if (task.isSuccessful()) {
          String token = task.getResult().getToken();
          saveToken(token);
       }
    }
});
                                                    
private void saveToken(String token) {
   reference.setValue(token);
}

where "reference" is the correct pointer to the db.. this works properly. I want to use the token stored to send a push-notification to the user targeted. I also have implemented the class MyFirebaseMessagingService but I don't know how to use it to send notification to a specific user using his FCM token that I stored as I posted above.

public class MyFirebaseMessagingService extends FirebaseMessagingService {

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        Log.d(TAG, "From: " + remoteMessage.getFrom());

    }

    @Override
    public void onNewToken(String token) {
        Log.d(TAG, "Refreshed token: " + token);

        sendRegistrationToServer(token);
    }

    private void sendRegistrationToServer(String token) {
        //here I have code that store the token correctly
    }

    private void sendNotification(String messageBody) {
        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
                PendingIntent.FLAG_ONE_SHOT);

        String channelId = getString(R.string.default_notification_channel_id);
        Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        NotificationCompat.Builder notificationBuilder =
                new NotificationCompat.Builder(this, channelId)
                        .setSmallIcon(R.drawable.ic_default)
                        .setContentTitle(getString(R.string.fcm_message))
                        .setContentText(messageBody)
                        .setAutoCancel(true)
                        .setSound(defaultSoundUri)
                        .setContentIntent(pendingIntent);

        NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(channelId,
                    "Channel human readable title",
                    NotificationManager.IMPORTANCE_DEFAULT);
            notificationManager.createNotificationChannel(channel);
        }

        notificationManager.notify(0, notificationBuilder.build());
    }
}

So I want to target a specific user by his FCM token and sending him a notification but I can't find a way to do this. Please help me.

sdresdre
  • 1
  • 1
  • 1
  • Sending messages **to** a device requires that you specify the FCM server key when calling the FCM API. As its name implies, this key should only be used on a trusted environment, such as your development machine, a server you control, or Cloud Functions. It is **not** possible to directly send messages to a user from within your Android code, as that would be a major abuse vector. See https://stackoverflow.com/questions/38432243/how-to-send-device-to-device-notification-by-using-fcm-without-using-xmpp-or-any – Frank van Puffelen Sep 29 '20 at 13:44

2 Answers2

2

To send the notification to a specific user you have to call this API:

https://fcm.googleapis.com/fcm/send

with Authorization:"key=YOUR_FCM_KEY" and Content-Type:"application/json" in header and the request body should be like:

{ 
  "to": "FCM Token",
  "priority": "high",
  "notification": {
    "title": "Your Title",
    "text": "Your Text"
  },
  "data": {
    "customId": "02",
    "badge": 1,
    "sound": "",
    "alert": "Alert"
  }
}

You should call this api from backend (Recommended). You can also call it from your android device, but

Be aware of hijacking your API Key

For android you can use okhttp for calling API

implementation("com.squareup.okhttp3:okhttp:4.9.0")

and the sample code will be like

public static void senPushdNotification(final String body, final String title, final String fcmToken) {
    new AsyncTask<Void, Void, Void>() {
        @Override
        protected Void doInBackground(Void... params) {
            try {
                OkHttpClient client = new OkHttpClient();
                JSONObject json = new JSONObject();
                JSONObject notificationJson = new JSONObject();
                JSONObject dataJson = new JSONObject();
                notificationJson.put("text", body);
                notificationJson.put("title", title);
                notificationJson.put("priority", "high");
                dataJson.put("customId", "02");
                dataJson.put("badge", 1);
                dataJson.put("alert", "Alert");
                json.put("notification", notificationJson);
                json.put("data", dataJson);
                json.put("to", fcmToken);
                RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json.toString());
                Request request = new Request.Builder()
                        .header("Authorization", "key=YOUR_FCM_KEY")
                        .url("https://fcm.googleapis.com/fcm/send")
                        .post(body)
                        .build();
                Response response = client.newCall(request).execute();
                String finalResponse = response.body().string();
                Log.i("TAG", finalResponse);
            } catch (Exception e) {

                Log.i("TAG", e.getMessage());
            }
            return null;
        }
    }.execute();
}
Anisuzzaman Babla
  • 6,510
  • 7
  • 36
  • 53
1

You have to create a backend server to send notifications for specific actions: https://firebase.google.com/docs/cloud-messaging/send-message

Although you can use Firebase Realtime Database with Cloud Functions to achieve that also:

https://medium.com/@97preveenraj/firebase-cloud-messaging-fcm-with-firebase-realtime-database-7388493cb869

Mariusz Brona
  • 1,549
  • 10
  • 12
  • Ideally, this "backend" will keep a map of userId + FCM Token, so when you know you need to message userId = 10, then you have access to his/her latest FCM Token (that your FirebaseMessagingService should send to the backend when Google calls you back on that Broadcast Receiver with a new Token). Keep in mind the FCM token *can and will* change at random intervals throughout an App's session; it may not change for weeks, but it can suddenly do (if google invalidates it due to a security update or something), so you always have to react to this and update it in your servers. – Martin Marconcini Sep 29 '20 at 10:33
  • Is there a complete tutorial to implement this? It is very difficult – sdresdre Sep 29 '20 at 10:41