Как отправить сообщение устройства на устройство с помощью Firebase Cloud Messaging? - программирование

Как отправить сообщение устройства на устройство с помощью Firebase Cloud Messaging?

После поиска документов я не смог найти информацию о том, как отправлять сообщения устройства на устройство с помощью FCM без использования внешнего сервера.

Например, если я создавал приложение для чата, мне нужно было бы отправлять push-уведомления пользователям о непрочитанных сообщениях, так как они не будут в сети все время, и я не могу иметь постоянную службу в фоновом режиме, которая всегда будет быть подключенным к базе данных реального времени, потому что это будет слишком тяжелым ресурсом.

Итак, как я могу отправить push-уведомление пользователю "A", когда определенный пользователь "B" отправляет ему чат-сообщение? Нужен ли мне внешний сервер для этого или может быть сделано только с серверами Firebase?

4b9b3361

Ответ 1

UPDATE: теперь можно использовать функции облачной службы firebase в качестве сервера для обработки push-уведомлений. Ознакомьтесь с их документацией здесь.

============

В соответствии с документами вы должны внедрить сервер для обработки push-уведомлений в устройстве для связи с устройством.

Прежде чем вы сможете писать клиентские приложения, использующие Firebase Cloud Messaging, у вас должен быть сервер приложений, который отвечает следующим критериям:

...

Вам нужно будет решить, какой протокол сервера соединений FCM вы хотите использовать, чтобы ваш сервер приложений мог взаимодействовать с серверами соединений FCM. Обратите внимание: если вы хотите использовать восходящую передачу сообщений из ваших клиентских приложений, вы должны использовать XMPP. Подробнее об этом см. В разделе Выбор протокола сервера соединений FCM.

Если вам нужно отправлять основные уведомления пользователям с сервера. Вы можете использовать их безсерверное решение Firebase Notifications.

См. Здесь сравнение между FCM и уведомлениями Firebase: https://firebase.google.com/support/faq/#messaging-difference

Ответ 2

Мне помог запрос HTTP POST со ссылкой https://fcm.googleapis.com/fcm/send с обязательным заголовком и данными. В приведенном ниже фрагменте кода Constants.LEGACY_SERVER_KEY - это локальная переменная класса, вы можете найти ее в своем проекте Firebase Settings->Cloud Messaging->Legacy Server key. Вам необходимо передать маркер регистрации устройства, т.е. regToken в приведенном ниже фрагменте кода, на который ссылается ЗДЕСЬ.

Наконец, вам нужна зависимость от библиотеки okhttp, чтобы этот фрагмент работал.

public static final MediaType JSON
        = MediaType.parse("application/json; charset=utf-8");
private void sendNotification(final String regToken) {
    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();

}

далее, если вы хотите отправить сообщение на определенную тему, замените regToken на json следующим образом

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

и не забудьте добавить разрешение INTERNET в ваш AndroidManifest.xml.

ВАЖНО: - Использование приведенного выше кода означает, что ваш ключ сервера находится в клиентском приложении. Это опасно, поскольку кто-то может зайти в ваше приложение и получить ключ сервера для отправки вредоносных уведомлений вашим пользователям.

Ответ 3

Да, это возможно сделать без какого-либо сервера. Вы можете создать клиентскую группу группы устройств, а затем обмениваться сообщениями в группе. Однако существуют ограничения:

  • Вы должны использовать ту же учетную запись Google на устройствах
  • Вы не можете отправлять сообщения с высоким приоритетом

Ссылка: Firebase doc См. раздел "Управление группами устройств в клиентских приложениях Android"

Ответ 5

Вы можете сделать это, используя запрос Volly Jsonobject....

выполните следующие шаги:

1 скопируйте старый ключ сервера и сохраните его как Legacy_SERVER_KEY

Легальный серверный ключ

вы можете видеть на картинке, как получить

2 Вам нужна зависимость от Volley

compile 'com.mcxiaoke.volley: library: 1.0.19'

введите описание изображения здесь

Код для отправки 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("[email protected]@[email protected]@_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("[email protected]@_SUCESS", response + "");
                        }
                    },
                    new Response.ErrorListener() {
                        @Override
                        public void onErrorResponse(VolleyError error) {
                            Log.e("[email protected]@_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);
}

Просто позвонив sendFCMPush();

Ответ 7

Вы можете использовать "Дооснащение". Подписывайте устройства для обсуждения новостей. Отправлять уведомление с одного устройства на другое.

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;
}

}

и

public class NotifyData {
String title;
String body;

public NotifyData(String title, String body ) {

    this.title = title;
    this.body = body;
}

}

и FirebaseAPI

public interface FirebaseAPI {

@POST("/fcm/send")
Call<Message> sendMessage(@Body Message message);

}

Ответ 8

Облачные функции Google теперь позволяют отправлять push-уведомления с устройства на устройство без сервера приложений.

На соответствующей странице в облачных функциях Google:

Разработчики могут использовать функции Cloud, чтобы поддерживать пользователей и до дату с соответствующей информацией о приложении. Рассмотрим, например, приложение, которое позволяет пользователям следить друг за другом в приложении. В таком приложении функция, запускаемая базой данных Realtime, записывает в новые подписчики могут создавать Firebase Cloud Messaging (FCM) уведомления, чтобы соответствующие пользователи знали, что они получили новых последователей.

Пример:

  • Функция запускает запись в путь базы данных Realtime, где хранятся последователи.

  • Функция создает сообщение для отправки через FCM.

  • FCM отправляет уведомление на пользовательское устройство.

Вот демонстрационный проект для отправки push-уведомлений устройства на устройство с Firebase и облачными функциями Google.

Ответ 9

Облачные функции Google теперь позволяют отправлять push-уведомления с устройства на устройство без сервера приложений. Я сделал облачную функцию, которая запускается при добавлении нового сообщения в базу данных.

Это код node.js

'use strict';

const functions = require('firebase-functions');
const admin = require('firebase-admin'); admin.initializeApp();

exports.sendNotification = functions.database.ref('/conversations/{chatLocation}/{messageLocation}')
  .onCreate((snapshot, context) => {
      // Grab the current value of what was written to the Realtime Database.
      const original = snapshot.val();

       const toIDUser = original.toID;
       const isGroupChat = original.isGroupChat;

       if (isGroupChat) {
       const tokenss =  admin.database().ref('/users/${toIDUser}/tokens').once('value').then(function(snapshot) {

// Handle Promise
       const tokenOfGroup = snapshot.val()

      // get tokens from the database  at particular location get values 
       const valuess = Object.keys(tokenOfGroup).map(k => tokenOfGroup[k]);

     //console.log(' ____________ddd((999999ddd_________________ ' +  valuess );
    const payload = {
       notification: {
                 title:   original.senderName + " :- ",
                 body:    original.content
    }
  };

  return admin.messaging().sendToDevice(valuess, payload);



}, function(error) {

  console.error(error);
});

       return ;
          } else {
          // get token from the database  at particular location
                const tokenss =  admin.database().ref('/users/${toIDUser}/credentials').once('value').then(function(snapshot) {
                // Handle Promise
  // The Promise was "fulfilled" (it succeeded).

     const credentials = snapshot.val()



    // console.log('snapshot ......snapshot.val().name****^^^^^^^^^^^^kensPromise****** :- ', credentials.name);
     //console.log('snapshot.....****snapshot.val().token****^^^^^^^^^^^^kensPromise****** :- ', credentials.token);


     const deviceToken = credentials.token;

    const payload = {
       notification: {
                 title:   original.senderName + " :- ",
                 body:    original.content
    }
  };

  return admin.messaging().sendToDevice(deviceToken, payload);


}, function(error) {

  console.error(error);
});


          }





  return ;


    });

Ответ 10

В моем случае я использую модификацию с этим классом Message:

public class Message {

    private String to;
    private String collapseKey;
    private Notification notification;
    private Data data;

    public Message(String to, String collapseKey, Notification notification, Data data) {
        this.to = to;
        this.collapseKey = collapseKey;
        this.notification = notification;
        this.data = data;
    }

Данные

public class Data {

    private String body;
    private String title;
    private String key1;
    private String key2;

    public Data(String body, String title, String key1, String key2) {
        this.body = body;
        this.title = title;
        this.key1 = key1;
        this.key2 = key2;
    }
}

уведомление

public class Notification {

    private String body;
    private String title;

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

это вызов

private void sentToNotification() {


            String to = "YOUR_TOKEN";
            String collapseKey = "";
            Notification notification = new Notification("Hello bro", "title23");
            Data data = new Data("Hello2", "title2", "key1", "key2");
            Message notificationTask = new Message(to, collapseKey, notification, data);

            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("https://fcm.googleapis.com/")//url of FCM message server
                    .addConverterFactory(GsonConverterFactory.create())//use for convert JSON file into object
                    .build();

            ServiceAPI api = new retrofit.create(ServiceAPI.class);

            Call<Message> call = api .sendMessage("key=YOUR_KEY", notificationTask);

            call.enqueue(new Callback<Message>() {
                @Override
                public void onResponse(Call<Message> call, retrofit2.Response<Message> response) {
                    Log.d("TAG", response.body().toString());
                }

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

                    Log.e("TAG", t.getMessage());
                }
            });
        }

наш ServiceAPi

public interface ServiceAPI {
    @POST("/fcm/send")
    Call<Message> sendMessage(@Header("Authorization") String token, @Body Message message);
}

Ответ 11

Вы можете использовать базу данных реального времени firebase для этого. Вы можете создать структуру данных для хранения чатов и добавить наблюдателей для потоков беседы для обоих пользователей. Он по-прежнему не обладает архитектурой device-server-device, но в этом случае на стороне разработчиков нет дополнительного сервера. Это использует серверы firebase. Вы можете ознакомиться с учебником здесь (игнорируйте часть пользовательского интерфейса, хотя это также хорошая отправная точка для пользовательских интерфейсов чата).

Firebase Realtime Chat

Ответ 12

Итак, у меня была идея. См.: Если FCM, а также GCM имеют доступ к HTTP-запросу, мы можем отправить сообщение json с данными наших сообщений, включая токены устройств, которые мы хотим, чтобы это сообщение было доставлено.

Так почему бы не отправить сообщение на сервер Firebase с этим уведомлением, которое будет доставлено пользователю B? вы понимаете?

Итак, вы отправляете сообщение и чат с сообщением о вызове, чтобы обеспечить доставку уведомления, если пользователь находится в вашем приложении в фоновом режиме. Я тоже скоро буду в этом нуждаться, я буду тестировать позже. Что вы говорите?

Ответ 13

Я потратил много времени на эту тему, так как моему требованию точно не нужен AppServer, и я чувствовал, что это как бремя, так и узкое место в производительности - из-за очевидной поездки в оба конца.

Несмотря на то, что согласно официальным документам вам нужен внешний сторонний AppServer для пересылки/генерации нисходящего push-уведомления клиентам, вы можете на самом деле замаскировать функцию AppServer, создав HTTP-запросы POST (которые, согласно документам, должны быть сгенерированы от стороннего Appserver) от самих клиентов. Вот фрагмент кода метода HTTP POST FCM Сообщение от клиентов:

    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();
}

}

Предоставлено brijesh kumar

Ответ 14

Простейший способ:

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());
        }
    });
}

Создать класс для создания объекта:

public class Message {
String to;
NotifyData data;

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

Создать класс для создания объекта:

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;
}
}