Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to send one to one message using Firebase Messaging

I have been trying to read the official docs and guides about how to send message from one device to another. I have saved registration token of both devices in the Real Time Database, thus I have the registration token of another device. I have tried the following way to send the message

RemoteMessage message = new RemoteMessage.Builder(getRegistrationToken())
                    .setMessageId(incrementIdAndGet())
                    .addData("message", "Hello")
                    .build();
FirebaseMessaging.getInstance().send(message);

However this is not working. The other device doesn't receive any message. I am not even sure, if I can use upstream message sending to conduct device to device communication.

PS: I just want to know if device-to-device messaging is possible using FCM? If yes, then is the code I used have some issue? If yes, then what is the correct way.

Update:
My question was to ask whether device to device messaging without using any separate server other than firebase could messaging is possible or not, if yes than how, since there's no documentation about it. I do not understand what is left to explain here? Anyways I got the answer and will update it as an answer once the question gets reopened.

like image 356
noob Avatar asked Jun 23 '16 11:06

noob


People also ask

How to send a message using Firebase?

Go to Firebase console — →Project Settings — →Cloud Messaging. To send the message select Body — →Raw — →JSON(application/json). You can send Notification Payload , Data Payload and even both using POSTMAN service.


2 Answers

Firebase has two features to send messages to devices:

  • the Notifications panel in your Firebase Console allows you to send notifications to specific devices, groups of users, or topics that users subscribed to.
  • by calling Firebase Cloud Messaging API, you can send messages with whatever targeting strategy you prefer. Calling the FCM API requires access to your Server key, which you should never expose on client devices. That's why you should always run such code on an app server.

The Firebase documentation shows this visually:

The two ways to send messages to device with Firebase

Sending messages from one device directly to another device is not supported through Firebase Cloud Messaging.

Update: I wrote a blog post detailing how to send notifications between Android devices using Firebase Database, Cloud Messaging and Node.js.

Update 2: You can now also use Cloud Functions for Firebase to send messages securely, without spinning up a server. See this sample use-case to get started. If you don't want to use Cloud Functions, you can run the same logic on any trusted environment you already have, such as your development machine, or a server you control.

like image 88
Frank van Puffelen Avatar answered Nov 11 '22 01:11

Frank van Puffelen


I have also been using direct device to device gcm messaging in my prototype. It has been working very well. We dont have any server. We exchange GCM reg id using sms/text and then communicate using GCM after that. I am putting here code related to GCM handling

**************Sending GCM Message*************

//Sends gcm message Asynchronously
public class GCM_Sender extends IntentService{
    final String API_KEY = "****************************************";

    //Empty constructor
    public GCM_Sender() {
        super("GCM_Sender");
    }

    //Processes gcm send messages
    @Override
    protected void onHandleIntent(Intent intent) {  

        Log.d("Action Service", "GCM_Sender Service Started");
        //Get message from intent
        String msg = intent.getStringExtra("msg");
        msg =  "\"" + msg + "\"";
        try{
            String ControllerRegistrationId = null;                 
            //Check registration id in db       
            if(RegistrationIdAdapter.getInstance(getApplicationContext()).getRegIds().size() > 0 ) {
                String controllerRegIdArray[] = RegistrationIdAdapter.getInstance(getApplicationContext()).getRegIds().get(1);
                if(controllerRegIdArray.length>0)
                    ControllerRegistrationId = controllerRegIdArray[controllerRegIdArray.length-1];

                if(!ControllerRegistrationId.equalsIgnoreCase("NULL")){
                    // 1. URL
                    URL url = new URL("https://android.googleapis.com/gcm/send");
                    // 2. Open connection
                    HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
                    // 3. Specify POST method
                    urlConnection.setRequestMethod("POST");
                    // 4. Set the headers
                    urlConnection.setRequestProperty("Content-Type", "application/json");
                    urlConnection.setRequestProperty("Authorization", "key=" + API_KEY);
                    urlConnection.setDoOutput(true);
                    // 5. Add JSON data into POST request body
                    JSONObject obj = new JSONObject("{\"time_to_live\": 0,\"delay_while_idle\": true,\"data\":{\"message\":" + msg + "},\"registration_ids\":[" + ControllerRegistrationId + "]}");
                    // 6. Get connection output stream
                    OutputStreamWriter out = new OutputStreamWriter(urlConnection.getOutputStream());
                    out.write(obj.toString());
                    out.close();
                    // 6. Get the response
                    int responseCode = urlConnection.getResponseCode();

                    BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
                    String inputLine;
                    StringBuffer response = new StringBuffer();
                    while ((inputLine = in.readLine()) != null){
                        response.append(inputLine);
                    }
                    in.close();
                    Log.d("GCM getResponseCode:", new Integer(responseCode).toString());
                }else{
                    Log.d("GCM_Sender:","Field REGISTRATION_TABLE is null");
                }
            }else {
                Log.d("GCM_Sender:","There is no Registration ID in DB ,please sync devices");
            }
        } catch (Exception e) {
            e.printStackTrace();
            //MessageSender.getInstance().sendMessage(msg, Commands.SMS_MESSAGE);
        } 
    }

    //Called when service is no longer alive
    @Override
    public void onDestroy() {
        super.onDestroy();
        //Do a log that GCM_Sender service has been destroyed
        Log.d("Action Service", "GCM_Sender Service Destroyed");
    }
}

**************Receiving GCM Message*************

public class GCM_Receiver extends WakefulBroadcastReceiver {
    public static final String RETRY_ACTION ="com.google.android.c2dm.intent.RETRY";
    public static final String REGISTRATION ="com.google.android.c2dm.intent.REGISTRATION";
    public SharedPreferences preferences;

    //Processes Gcm message .
    @Override
    public void onReceive(Context context, Intent intent) {
        ComponentName comp = new ComponentName(context.getPackageName(),
                GCMNotificationIntentService.class.getName());
        //Start GCMNotificationIntentService to handle gcm message asynchronously
        startWakefulService(context, (intent.setComponent(comp)));
        setResultCode(Activity.RESULT_OK);

        /*//Check if DatabaseService is running .
        if(!DatabaseService.isServiceRunning) {
            Intent dbService = new Intent(context,DatabaseService.class);
            context.startService(dbService);
        }*/
        //Check if action is RETRY_ACTION ,if it is then do gcm registration again .
        if(intent.getAction().equals(RETRY_ACTION)) {
            String registrationId = intent.getStringExtra("registration_id");

            if(TextUtils.isEmpty(registrationId)){
                DeviceRegistrar.getInstance().register(context);
            }else {
                //Save registration id to prefs .
                preferences = PreferenceManager.getDefaultSharedPreferences(context);
                SharedPreferences.Editor editor = preferences.edit();
                editor.putString("BLACKBOX_REG_ID",registrationId);
                editor.commit();
            }
        } else if (intent.getAction().equals(REGISTRATION)) {
        }

    }
}

//Processes gcm messages asynchronously .
public class GCMNotificationIntentService extends IntentService{
    public static final int NOTIFICATION_ID = 1;
    private NotificationManager mNotificationManager;
    String gcmData;
    private final String TAG = "GCMNotificationIntentService";

    //Constructor with super().
    public GCMNotificationIntentService() {
        super("GcmIntentService");
    }

    //Called when startService() is called by its Client .
    //Processes gcm messages .
    @Override
    protected void onHandleIntent(Intent intent) {

        Log.d("GCMNotificationIntentService", "GCMNotificationIntentService Started");
        Bundle extras = intent.getExtras();
        //Get instance of GoogleCloudMessaging .
        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
        //Get gcm message type .
        String messageType = gcm.getMessageType(intent);

        if (!extras.isEmpty()) {
            if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR
                    .equals(messageType)) {
                sendNotification("Send error: " + extras.toString());
            } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED
                    .equals(messageType)) {
                sendNotification("Deleted messages on server: "
                        + extras.toString());
            } else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE
                    .equals(messageType)) {
                Log.i(TAG, "Completed work @ " + SystemClock.elapsedRealtime());

                gcmData = extras.getString("message");
                Intent actionService = new Intent(getApplicationContext(),Action.class);    
                actionService.putExtra("data", gcmData);
                //start Action service .
                startService(actionService);

                //Show push notification .
                sendNotification("Action: " + gcmData);
                //Process received gcmData.

                Log.d(TAG,"Received Gcm Message from Controller : " + extras.getString("message"));
            }
        }
        GCM_Receiver.completeWakefulIntent(intent);
    }

    //Shows notification on device notification bar .
    private void sendNotification(String msg) {
        mNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
        Intent notificationIntent = new Intent(this, BlackboxStarter.class);
        //Clicking on GCM notification add new layer of app.
        notificationIntent.setFlags( Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
                this).setSmallIcon(R.drawable.gcm_cloud)
                .setContentTitle("Notification from Controller")
                .setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
                .setContentText(msg);
        mBuilder.setContentIntent(contentIntent);
        mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
        //Play default notification
        try {
            Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
            Ringtone r = RingtoneManager.getRingtone(getApplicationContext(), notification);
            r.play();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //Called when service is no longer be available .
    @Override
    public void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        Log.d("GCMNotificationIntentService", "GCMNotificationIntentService Destroyed");
    }

}
like image 36
vsrivas Avatar answered Nov 11 '22 01:11

vsrivas