Solución:
Firebase tiene dos funciones para enviar mensajes a dispositivos:
- el panel de Notificaciones en tu Firebase Console te permite enviar notificaciones a dispositivos específicos, grupos de usuarios o temas a los que los usuarios se suscribieron.
- al llamar a la API de Firebase Cloud Messaging, puede enviar mensajes con la estrategia de orientación que prefiera. Llamar a la API de FCM requiere acceso a su servidor key, que nunca debe exponer en dispositivos cliente. Es por eso que siempre debe ejecutar dicho código en un servidor de aplicaciones.
La documentación de Firebase muestra esto visualmente:
El envío de mensajes desde un dispositivo directamente a otro dispositivo no es compatible con Firebase Cloud Messaging.
Actualizar: Escribí una publicación de blog que detalla cómo enviar notificaciones entre dispositivos Android usando Firebase Database, Cloud Messaging y Node.js.
Actualización 2: Ahora también puede usar Cloud Functions para Firebase para enviar mensajes de forma segura, sin activar un servidor. Vea este caso de uso de muestra para comenzar.
Advertencia Hay una razón muy importante por la que no mencionamos este enfoque en ninguna parte. Esto expone su servidor key en el APK que colocas en cada dispositivo cliente. Puede (y, por lo tanto, se tomará) de allí y puede dar lugar a un abuso de su proyecto. Recomiendo encarecidamente no adoptar este enfoque, a excepción de las aplicaciones que solo coloca en sus propios dispositivos. – Frank van Puffelen
Ok, entonces la respuesta de Frank fue correcta que Firebase
no es compatible de forma nativa con la mensajería de dispositivo a dispositivo. Sin embargo, hay una laguna en eso. El servidor de Firebase no identifica si ha enviado la solicitud desde un servidor real o lo está haciendo desde su dispositivo.
Así que todo lo que tienes que hacer es enviar un Post Request
para Firebase
servidor de mensajería junto con la clave del servidor. Solo tenga esto en cuenta que el servidor key no se supone que esté en el dispositivo, pero no hay otra opción si desea la mensajería de dispositivo a dispositivo mediante Firebase Messaging.
Estoy usando OkHTTP en lugar de la forma predeterminada de llamar a la API Rest. El código es algo como esto:
public static final String FCM_MESSAGE_URL = "https://fcm.googleapis.com/fcm/send";
OkHttpClient mClient = new OkHttpClient();
public void sendMessage(final JSONArray recipients, final String title, final String body, final String icon, final String message)
new AsyncTask()
@Override
protected String doInBackground(String... params)
try
JSONObject root = new JSONObject();
JSONObject notification = new JSONObject();
notification.put("body", body);
notification.put("title", title);
notification.put("icon", icon);
JSONObject data = new JSONObject();
data.put("message", message);
root.put("notification", notification);
root.put("data", data);
root.put("registration_ids", recipients);
String result = postToFCM(root.toString());
Log.d(TAG, "Result: " + result);
return result;
catch (Exception ex)
ex.printStackTrace();
return null;
@Override
protected void onPostExecute(String result)
try
JSONObject resultJson = new JSONObject(result);
int success, failure;
success = resultJson.getInt("success");
failure = resultJson.getInt("failure");
Toast.makeText(getCurrentActivity(), "Message Success: " + success + "Message Failed: " + failure, Toast.LENGTH_LONG).show();
catch (JSONException e)
e.printStackTrace();
Toast.makeText(getCurrentActivity(), "Message Failed, Unknown error occurred.", Toast.LENGTH_LONG).show();
.execute();
String postToFCM(String bodyString) throws IOException
RequestBody body = RequestBody.create(JSON, bodyString);
Request request = new Request.Builder()
.url(FCM_MESSAGE_URL)
.post(body)
.addHeader("Authorization", "key=" + SERVER_KEY)
.build();
Response response = mClient.newCall(request).execute();
return response.body().string();
Espero que Firebase venga con una mejor solución en el futuro. Pero hasta entonces, creo que esta es la única forma. La otra forma sería enviar mensajes temáticos o mensajes grupales. Pero eso no estaba en el ámbito de la pregunta.
Actualizar:
El JSONArray se define así:
JSONArray regArray = new JSONArray(regIds);
regIds es una cadena array de identificadores de registro, al que desea enviar este mensaje. Tenga en cuenta que los ID de registro siempre deben estar en un array, incluso si desea enviarlo a un solo destinatario.
También he estado usando mensajes directos de dispositivo a dispositivo gcm en mi prototipo. Ha funcionado muy bien. No tenemos ningún servidor. Intercambiamos la identificación del registro de GCM usando sms / text y luego nos comunicamos usando GCM después de eso. Estoy poniendo aquí código relacionado con el manejo de GCM
************** Envío de mensaje GCM *************
//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");
************** Recibiendo mensaje GCM *************
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) 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");
Comentarios y valoraciones
Eres capaz de añadir valor a nuestra información contribuyendo tu experiencia en las referencias.