Android не получает push-уведомления Firebase — MismatchSenderId

Я пытаюсь работать над приложением для обмена сообщениями, но проблема в том, что у меня есть 2 объекта (т. е. 2 приложения A и B).

Теперь я пытаюсь поместить логику обмена сообщениями между ними, используя Firebase. Firebase не поддерживает обмен данными между двумя разными приложениями (A и B) по одному и тому же URL-адресу проекта. Чтобы обойти это ограничение, я использовал тот же google-service.json приложения A и для приложения B.

Для приложения B я только что изменил проект id и auth key. Кажется, это сработало, как я и предполагал. Я также протестировал push-уведомление с помощью консоли Firebase, и, похоже, оно работало.

Затем я попытался реализовать серверную логику. Чтобы отправить уведомление один на один.

СЛУЧАЙ 1

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

{"multicast_id":[removed],"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"MismatchSenderId"}]}

СЛУЧАЙ 2

и для приложения A вот следующий ответ, который я получаю:

{"multicast_id":[removed],"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1473661851590851%0e4bcac9f9fd7ecd"}]}

Для этого значение успеха равно 1, следовательно, уведомление должно быть отправлено, но оно не отправляется, когда я делаю запрос с устройства. Но он работает безупречно, когда я выполняю тот же вызов сервера, используя Postman или любой другой клиент.

Вот мои коды MyFirebaseInstanceIDService.java

public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {

private static final String TAG = "MyFirebaseIIDService";
private static final String FRIENDLY_ENGAGE_TOPIC = "friendly_engage";


@Override
public void onCreate() {
    String savedToken = Utility.getFirebaseInstanceId(getApplicationContext());
    String defaultToken = getApplication().getString(R.string.pref_firebase_instance_id_default_key);
    Log.d("GCM", savedToken);
    if (savedToken.equalsIgnoreCase(defaultToken))
    //currentToken is null when app is first installed and token is not available
    //also skip if token is already saved in preferences...
    {
        String CurrentToken = FirebaseInstanceId.getInstance().getToken();
        if (CurrentToken != null)
            Utility.setFirebaseInstanceId(getApplicationContext(), CurrentToken);
        Log.d("Value not set", CurrentToken);
        updateFCMTokenId(CurrentToken);
    }
    super.onCreate();
}

/**
 * The Application's current Instance ID token is no longer valid
 * and thus a new one must be requested.
 */
@Override
public void onTokenRefresh() {
    // If you need to handle the generation of a token, initially or
    // after a refresh this is where you should do that.
    String token = FirebaseInstanceId.getInstance().getToken();
    Log.d(TAG, "FCM Token: " + token);
    Utility.setFirebaseInstanceId(getApplicationContext(), token);
    updateFCMTokenId(token);
}

private void updateFCMTokenId(final String token) {
    SQLiteHandler db = new SQLiteHandler(getBaseContext());
    final HashMap<String, String> map = db.getUserDetails();
    //update fcm token for push notifications
    StringRequest str = new StringRequest(Request.Method.POST, AppConfig.UPDATE_GCM_ID, new Response.Listener<String>() {
        @Override
        public void onResponse(String response) {

            Log.d("GCM RESPONSE", response);

        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {

        }
    }) {
        @Override
        protected Map<String, String> getParams() throws AuthFailureError {
            HashMap<String, String> param = new HashMap<>();
            param.put("user_id", map.get("uid"));
            param.put("gcm_registration_id", token);
            return param;
        }
    };
    str.setShouldCache(false);
    str.setRetryPolicy(new DefaultRetryPolicy(AppConfig.DEFAULT_RETRY_TIME, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
    AppController.getInstance().addToRequestQueue(str);
}

}

FirebaseMessagingService.java

public class MyFirebaseMessagingService extends FirebaseMessagingService {

private static final String TAG = "MyFirebaseMsgService";

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    //Displaying data in log
    //It is optional
    try {
        Log.d(TAG, "From: " + remoteMessage.getFrom());

        Log.d(TAG, "Notification Message Body: " + remoteMessage.getData().get("message"));
    } catch (Exception e) {
        e.printStackTrace();
    }

    //Calling method to generate notification
    sendNotification(remoteMessage.getData().get("message"));
}

//This method is only generating push notification
//It is same as we did in earlier posts
private void sendNotification(String messageBody) {
    Intent intent = new Intent(this, ChatRoomActivity.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,
            PendingIntent.FLAG_ONE_SHOT);

    Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
    android.support.v4.app.NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentTitle("NAME")
            .setContentText(messageBody)
            .setAutoCancel(true)
            .setSound(defaultSoundUri)
            .setContentIntent(pendingIntent);

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

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

А вот объявление в Manifest.xml внутри тега Application

 <service
        android:name=".MyFirebaseMessagingService"
        android:exported="false">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
    </service>

    <service
        android:name=".MyFirebaseInstanceIDService"
        android:exported="false">
        <intent-filter>
            <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
        </intent-filter>
    </service>

ТИА

ДЕЛО 1 Решено

Мне удалось решить СЛУЧАЙ 1, где для B мне пришлось использовать ключ API сервера B, аналогично для A

ИЗМЕНИТЬ 2

Добавлен серверный код

public function sendNotification($message, $gcm_id, $user_level)
{
    if ($user_level == "level") {
        $server_key = "xys";
    } else  $server_key = "ABC";
    $msg = array
    (
        'message' => $message,
        'title' => 'Title',
        'vibrate' => 1,
        'sound' => 1,
        'largeIcon' => 'large_icon',
        'smallIcon' => 'small_icon'
    );
    $fields = array
    (
        'to' => $gcm_id,
        'data' => $msg
    );


    $headers = array
    (
        'Authorization: key=' . $server_key,
        'Content-Type: application/json'
    );

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, 'https://fcm.googleapis.com/fcm/send');
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
    $result = curl_exec($ch);
    curl_close($ch);
    echo $result;
}

person silverFoxA    schedule 12.09.2016    source источник
comment
Я не понимаю, что такое приложение A и приложение B. Это два разных приложения из двух разных проектов? Или это просто два разных экземпляра одного и того же проекта? For app B, I have just changed the project id and auth key - мне кажется запутанным!   -  person Sudip Podder    schedule 12.09.2016
comment
@SudipPodder это два разных проекта   -  person silverFoxA    schedule 12.09.2016
comment
Можете ли вы прикрепить запрос httppost, который вы делаете со своего устройства?   -  person Sudip Podder    schedule 12.09.2016
comment
@SudipPodder со стороны клиента. Я запрашиваю указанный выше код на стороне сервера, используя залп.   -  person silverFoxA    schedule 13.09.2016


Ответы (2)


Редактировать №1:

1) Убедитесь, что вы отправляете действительный json в fcm. 2) Убедитесь, что вы отправляете на правильный токен.

Другая информация о том, как отправлять уведомления:

Отправлять сообщения на определенные устройства

Чтобы отправлять сообщения на определенные устройства, установите токен регистрации для конкретного экземпляра приложения.

curl -H "Content-type: application/json" -H "Authorization:key=<Your Api key>"  -X POST -d '{ "data": { "score": "5x1","time": "15:10"},"to" : "<registration token>"}' https://fcm.googleapis.com/fcm/send

Отправлять сообщения в темы

вот тема: /topics/foo-bar

curl -H "Content-type: application/json" -H "Authorisation:key=<Your Api key>"  -X POST -d '{ "to": "/topics/foo-bar","data": { "message": "This is a Firebase Cloud Messaging Topic Message!"}}' https://fcm.googleapis.com/fcm/send

Отправлять сообщения группам устройств

Отправка сообщений группе устройств очень похожа на отправку сообщений отдельному устройству. Установите для параметра to уникальный ключ уведомления для группы устройств.

curl -H "Content-type: application/json" -H "Authorisation:key=<Your Api key>"  -X POST -d '{"to": "<aUniqueKey>","data": {"hello": "This is a Firebase Cloud Messaging Device Group Message!"}}' https://fcm.googleapis.com/fcm/send

Оригинал:

Проблема в конфигурации вашего сервера. Если вы хотите управлять двумя приложениями firebase на одном сервере, вам нужно настроить два приложения firebase с вашим Firebase APK_KEY, который находится по адресу:

Перейдите к своим приложениям в консоли Firebase -> Нажмите на три точки в правом верхнем углу -> Управление -> ОБЛАЧНЫЕ СООБЩЕНИЯ -> (Ключ сервера)

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

var firebaseLib = require("firebase");

var app1Config = {
    apiKey: "<PROJECT_1_API_KEY>",
    authDomain: "<PROJECT_1_ID>.firebaseapp.com",
    databaseURL: "https://<PROJECT_1_DATABASE_NAME>.firebaseio.com",
    storageBucket: "<PROJECT_1_BUCKET>.appspot.com",
}
var app2Config = {
    apiKey: "<PROJECT_2_API_KEY>",
    authDomain: "<PROJECT_2_ID>.firebaseapp.com",
    databaseURL: "https://<PROJECT_2_DATABASE_NAME>.firebaseio.com",
    storageBucket: "<PROJECT_2_BUCKET>.appspot.com",
}

var firebaseApp1 = firebaseLib.initailize(app1Config); // Primary
var firebaseApp2 = firebaseLib.initailize(app2Config, "Secondary"); // Secondary
person David Antoon    schedule 12.09.2016
comment
Пожалуйста, проверьте мой обновленный вопрос. Мне удалось заставить приложение работать, изменив ключ сервера в соответствии с приложениями, но когда запрос отправляется с устройства, он не будет работать - person silverFoxA; 12.09.2016
comment
Я не вижу ни одного запроса, отправленного с устройства на уведомление, можете ли вы опубликовать свой код здесь - person David Antoon; 12.09.2016
comment
Я делаю запрос на сервер приложений, чтобы отправить уведомление - person silverFoxA; 12.09.2016
comment
Почему бы не использовать модуль firebase nodejs fcm? - person David Antoon; 12.09.2016
comment
Извиняюсь! Я не знаю об этом... Сервер обрабатывает только php - person silverFoxA; 12.09.2016

Я исправил ошибку MismatchSenderId

Пример ниже:

действительный токен: cwsm26j-8qM:APA91bEGbg5xxxxxxxxxxxxxxxxxxxxxxxx

недействительный токен: APA91bEGbg5xxxxxxxxxxxxxxxxxxxxxx

person Thanh    schedule 14.12.2016
comment
Пожалуйста, опишите свое решение, так как приведенный выше ответ не дает четкого понимания - person silverFoxA; 14.12.2016
comment
Я думаю, что причина ошибки связана с приложением для Android, когда получение из firebase devicetoken не получает первую часть токена. - person Thanh; 14.12.2016