How to send device to device messages using Firebase Cloud Messaging?

After searching the docs I could not find any info on how to send device to device messages using FCM without the use of an external server.

For example, if I was creating a chat application I would need to send push notifications to users about unread messages since they won’t be online all the time and I can’t have a persistent service in the background that would always be connected to the real time database because that would be too resource heavy.

  • Firebase 3x method not working in real device but working on simulator Swift 3.0
  • Firebase Cloud Messaging development and release profile
  • Cannot call value of non-function type 'Any?!' :- Firebase,Swift3
  • How to obtain values without key of dictionary?
  • Iterate over snapshot children in Swift (Firebase)
  • “Copy this file to your authentication server” - Firebase Custom auth
  • So how would I send a push notification to a user “A” when a certain user “B” sends him/her a chat message? Do I need an external server for this or can it be done with just Firebase servers?

    11 Solutions Collect From Internet About “How to send device to device messages using Firebase Cloud Messaging?”

    According to the docs you must implement a server for handling push notifications in device to device communication.

    Before you can write client apps that use Firebase Cloud Messaging, you must have an app server that meets the following criteria:

    You’ll need to decide which FCM connection server protocol(s) you want to use to enable your app server to interact with FCM connection servers. Note that if you want to use upstream messaging from your client applications, you must use XMPP. For a more detailed discussion of this, see Choosing an FCM Connection Server Protocol.

    If you only need to send basic notifications to your users from the server. You can use their serverless solution, Firebase Notifications.

    See a comparison here between FCM and Firebase Notifications:
    https://firebase.google.com/support/faq/#messaging-difference

    UPDATE: It is now possible to use firebase cloud functions as the server for handling push notifications. Check out their documentation here

    I figured out like this:-
    Making a HTTP POST request with the link “https://fcm.googleapis.com/fcm/send” with required header and data referenced HERE.
    Constants.LEGACY_SERVER_KEY is a local class variable, you can find this at your Firebase Project Settings–>CLOUD MESSAGING–>Legacy Server key. You need to pass device registration token(reg_token) in below code snippet referenced HERE.
    However you need okhttp library dependency in order to get this snippet work.

    public static final MediaType JSON
            = MediaType.parse("application/json; charset=utf-8");
    private void sendNotification(final String reg_token) {
        new AsyncTask<Void,Void,Void>(){
            @Override
            protected Void doInBackground(Void... params) {
                try {
                    OkHttpClient client = new OkHttpClient();
                    JSONObject json=new JSONObject();
                    JSONObject dataJson=new JSONObject();
                    dataJson.put("body","Hi this is sent from device to device");
                    dataJson.put("title","dummy title");
                    json.put("notification",dataJson);
                    json.put("to",regToken);
                    RequestBody body = RequestBody.create(JSON, json.toString());
                    Request request = new Request.Builder()
                            .header("Authorization","key="+Constants.LEGACY_SERVER_KEY)
                            .url("https://fcm.googleapis.com/fcm/send")
                            .post(body)
                            .build();
                    Response response = client.newCall(request).execute();
                    String finalResponse = response.body().string();
                }catch (Exception e){
                    //Log.d(TAG,e+"");
                }
                return null;
            }
        }.execute();
    
    }
    

    further if you want to send message to a particular topic, replace ‘regToken’ in json like this

    json.put("to","/topics/foo-bar")
    

    and at last don’t forget to add INTERNET permission in your AndroidManifest.xml.

    IMPORTANT : – Using above code means your server key resides in the client application. That is dangerous as someone can dig into your application and get the server key to send malicious notifications to your users.

    1) subscribe an identical topic name, for example:

    • ClientA.subcribe(“to/topic_users_channel”)
    • ClientB.subcribe(“to/topic_users_channel”)

    2) send messages inside the application

    GoogleFirebase : How-to send topic messages

    Yes, it’s possible to do it without any server. You can create a device group client side and then you exchange messages in the group. However there are limitations:

    1. You have to use the same Google account on the devices
    2. You can’t send high priority messages

    Reference: Firebase doc See the section “Managing device groups on Android client apps”

    If you have fcm(gcm) token of the device to whom you want to send notification. It’s just a post request to send the notification.

    https://github.com/prashanthd/google-services/blob/master/android/gcm/gcmsender/src/main/java/gcm/play/android/samples/com/gcmsender/GcmSender.java

    You can use Retrofit. Subscribe devices to topic news. Send notification from one device to other.

    public void onClick(View view) {
    
        HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
        logging.setLevel(HttpLoggingInterceptor.Level.BODY);
    
        OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
        httpClient.addInterceptor(new Interceptor() {
            @Override
            public okhttp3.Response intercept(Chain chain) throws IOException {
                Request original = chain.request();
    
                // Request customization: add request headers
                Request.Builder requestBuilder = original.newBuilder()
                        .header("Authorization", "key=legacy server key from FB console"); // <-- this is the important line
                Request request = requestBuilder.build();
                return chain.proceed(request);
            }
        });
    
        httpClient.addInterceptor(logging);
        OkHttpClient client = httpClient.build();
    
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://fcm.googleapis.com")//url of FCM message server
                .client(client)
                .addConverterFactory(GsonConverterFactory.create())//use for convert JSON file into object
                .build();
    
        // prepare call in Retrofit 2.0
        FirebaseAPI firebaseAPI = retrofit.create(FirebaseAPI.class);
    
        //for messaging server
        NotifyData notifydata = new NotifyData("Notification title","Notification body");
    
    Call<Message> call2 = firebaseAPI.sendMessage(new Message("topic or deviceID", notifydata));
    
        call2.enqueue(new Callback<Message>() {
            @Override
            public void onResponse(Call<Message> call, Response<Message> response) {
    
                Log.d("Response ", "onResponse");
                t1.setText("Notification sent");
    
            }
    
            @Override
            public void onFailure(Call<Message> call, Throwable t) {
                Log.d("Response ", "onFailure");
                t1.setText("Notification failure");
            }
        });
    }
    

    POJOs

    public class Message {
    String to;
    NotifyData notification;
    
    public Message(String to, NotifyData notification) {
        this.to = to;
        this.notification = notification;
    }
    
    }
    

    and

    public class NotifyData {
    String title;
    String body;
    
    public NotifyData(String title, String body ) {
    
        this.title = title;
        this.body = body;
    }
    
    }
    

    and FirebaseAPI

    public interface FirebaseAPI {
    
    @POST("/fcm/send")
    Call<Message> sendMessage(@Body Message message);
    
    }
    

    You can do it using Volly Jsonobject request….

    follow this Steps first:

    1 copy legacy server key and store it as Legacy_SERVER_KEY

    Legacy Server key

    you can see in picture how to get

    2 You need Volley dependency

    compile ‘com.mcxiaoke.volley:library:1.0.19’

    enter image description here

    Code for send Push:-

        private void sendFCMPush() {
    
                String Legacy_SERVER_KEY = YOUR_Legacy_SERVER_KEY;
                String msg = "this is test message,.,,.,.";
                String title = "my title";
                String token = FCM_RECEIVER_TOKEN;
    
                JSONObject obj = null;
            JSONObject objData = null;
            JSONObject dataobjData = null;
    
            try {
                obj = new JSONObject();
                objData = new JSONObject();
    
                objData.put("body", msg);
                objData.put("title", title);
                objData.put("sound", "default");
                objData.put("icon", "icon_name"); //   icon_name image must be there in drawable
                objData.put("tag", token);
                objData.put("priority", "high");
    
                dataobjData = new JSONObject();
                dataobjData.put("text", msg);
                dataobjData.put("title", title);
    
                obj.put("to", token);
                //obj.put("priority", "high");
    
                obj.put("notification", objData);
                obj.put("data", dataobjData);
                Log.e("!_@rj@_@@_PASS:>", obj.toString());
            } catch (JSONException e) {
                e.printStackTrace();
            }
    
                JsonObjectRequest jsObjRequest = new JsonObjectRequest(Request.Method.POST, Constants.FCM_PUSH_URL, obj,
                        new Response.Listener<JSONObject>() {
                            @Override
                            public void onResponse(JSONObject response) {
                                Log.e("!_@@_SUCESS", response + "");
                            }
                        },
                        new Response.ErrorListener() {
                            @Override
                            public void onErrorResponse(VolleyError error) {
                                Log.e("!_@@_Errors--", error + "");
                            }
                        }) {
                    @Override
                    public Map<String, String> getHeaders() throws AuthFailureError {
                        Map<String, String> params = new HashMap<String, String>();
                        params.put("Authorization", "key=" + Legacy_SERVER_KEY);
                        params.put("Content-Type", "application/json");
                        return params;
                    }
                };
                RequestQueue requestQueue = Volley.newRequestQueue(this);
                int socketTimeout = 1000 * 60;// 60 seconds
                RetryPolicy policy = new DefaultRetryPolicy(socketTimeout, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
                jsObjRequest.setRetryPolicy(policy);
                requestQueue.add(jsObjRequest);
    }
    

    Just Call sendFCMPush();

    So I had an idea here. See: If the FCM, as well as the GCM, has a endpoit to http request where we can send a post json with our message data, including the token (s) of devices that we want this message to be delivered.

    So why not send a post to Firebase server with this notification to be delivered to user B? you understand ?

    So, you send the message and chat with a call post to ensure delivery of the notification if the user is with your app in the background. I am also in need of it soon, I will test later. What do you say about?

    You can use firebase realtime database to do so. You can create data structure for storing chats and add observers for the conversation threads for both users. It still does device – server – device architecture, but in this case there is no additional server on the developers’ part. This uses the firebase servers. You can check out a tutorial here (ignore the UI part, although, that is also a good starting point for chat UI frameworks).

    Firebase Realtime Chat

    I had spent tons of time on this topic, as my requirement didn’t exactly need an AppServer, and I felt it like a burden as well as performance bottleneck – due to apparent round trip.

    Even though according to official docs you need an external 3rd party AppServer to forward/generate downstream push notification to clients, you can actually mask the function of an AppServer by generating the HTTP POST requests (which according to docs, should be generated from 3rd party Appserver) from the clients itself. Here is a code snippet of technique HTTP POST FCM Message from clients:

        public class FcmDeviceNotifier {
    
    private final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
    private final String TAG = FcmDeviceNotifier.class.getSimpleName();
    private String requestType;
    private JSONObject payloadJson;
    
    public FcmDeviceNotifier(String requestType /*can be "notification" or "data"*/) {
        this.requestType = requestType;
    }
    
    public void setValuePairs(Map<String, String> valuePairs) {
        try {
            payloadJson = new JSONObject();
            Iterator<Map.Entry<String,String>> iterator = valuePairs.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String,String> entry = iterator.next();
                payloadJson.put(entry.getKey(), entry.getValue());
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
    
    public void sendNotification(final String regToken /*Token of target device*/) {
        new AsyncTask<Void,Void,Void>(){
            @Override
            protected Void doInBackground(Void... params) {
                try {
                    OkHttpClient client = new OkHttpClient();
                    JSONObject fcmJson = new JSONObject();
                    fcmJson.put(requestType, payloadJson);
                    fcmJson.put(TO, regToken);
                    RequestBody body = RequestBody.create(JSON, fcmJson.toString());
                    Request request = new Request.Builder()
                            .header(AUTHORIZATION, "key=" + Constants.FCM_LEGACY_KEY)
                            .url("https://fcm.googleapis.com/fcm/send")
                            .post(body)
                            .build();
                    Response response = client.newCall(request).execute();
                    String finalResponse = response.body().string();
                    Log.d(TAG, "sendNotification: " + finalResponse);
                }catch (Exception e){
                    Log.e(TAG, "sendNotification: " + e.getMessage());
                }
                return null;
            }
        }.execute();
    }
    

    }

    Courtesy of brijesh kumar

    Simplest way :

    void sendFCMPush(String msg,String token) {
        HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
        logging.setLevel(HttpLoggingInterceptor.Level.BODY);
    
        OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
        httpClient.addInterceptor(new Interceptor() {
            @Override
            public okhttp3.Response intercept(Chain chain) throws IOException {
                Request original = chain.request();
    
                // Request customization: add request headers
                Request.Builder requestBuilder = original.newBuilder()
                        .header("Authorization", "key="+Const.FIREBASE_LEGACY_SERVER_KEY); // <-- this is the important line
                Request request = requestBuilder.build();
                return chain.proceed(request);
            }
        });
    
        httpClient.addInterceptor(logging);
        OkHttpClient client = httpClient.build();
    
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://fcm.googleapis.com/")//url of FCM message server
                .client(client)
                .addConverterFactory(GsonConverterFactory.create())//use for convert JSON file into object
                .build();
    
        // prepare call in Retrofit 2.0
        FirebaseAPI firebaseAPI = retrofit.create(FirebaseAPI.class);
    
        //for messaging server
        NotifyData notifydata = new NotifyData("Chatting", msg);
    
        Call<Message> call2 = firebaseAPI.sendMessage(new Message(token, notifydata));
    
        call2.enqueue(new Callback<Message>() {
            @Override
            public void onResponse(Call<Message> call, retrofit2.Response<Message> response) {
                Log.e("#@ SUCCES #E$#", response.body().toString());
            }
    
            @Override
            public void onFailure(Call<Message> call, Throwable t) {
    
                Log.e("E$ FAILURE E$#", t.getMessage());
            }
        });
    }
    

    Create Class to make Object:

    public class Message {
    String to;
    NotifyData data;
    
    public Message(String to, NotifyData data) {
        this.to = to;
        this.data = data;
    }
    }
    

    Create Class to make Object:

    public class Notification {
    String title;
    String message;
    enter code here`enter code here`
    public Notification(String title, String message) {
        this.title = title;
        this.message = message;
    }
    }