Ошибка недействительной регистрации при попытке использовать Volley для отправки push-уведомлений через FCM

#android #push-notification #firebase-cloud-messaging #android-volley

# #Android #push-уведомление #firebase-облако-обмен сообщениями #android-volley

Вопрос:

Я пытаюсь отправлять push-уведомления с помощью Volley в FCM, но они не принимаются с другой стороны. Ответ, который я получаю от Volley, таков

 {"multicast_id":7351526324257141941,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"InvalidRegistration"}]}
 

Я новичок в FCM и Volley и следовал этому руководству. Идея заключается в том, что каждый пользователь подписывается на свой uid в качестве темы, и когда происходит определенное действие, связанное с ними (например, кому-то нравится их фотография), тогда будет отправлено сообщение с темой в качестве идентификатора.

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

 val uid = FirebaseAuth.getInstance().uid
val userRef = FirebaseDatabase.getInstance().getReference("/users/$uid/services/firebase-token")
userRef.setValue(token)
FirebaseMessaging.getInstance().subscribeToTopic(uid)
 

В настоящее время я нахожусь в процессе тестирования, поэтому сообщение, которое я пытаюсь отправить, довольно общее. Это функции, которые должны ее выполнять.

 static void sendMessageTopic(String receiverId, String initiatorId, String post, Activity activity) {

        String NOTIFICATION_TITLE = "some title";

        String NOTIFICATION_MESSAGE = "This is the message";


        JSONObject notification = new JSONObject();
        JSONObject notificationBody = new JSONObject();
        try {
            notificationBody.put("title", NOTIFICATION_TITLE);
            notificationBody.put("message", NOTIFICATION_MESSAGE);

            notification.put("to", receiverId);
            notification.put("data", notificationBody);
        } catch (
                JSONException e) {
            Log.e("notificationStuff", "onCreate: "   e.getMessage());
        }

        sendNotification(notification, activity);
    }
 

Затем:

 static void sendNotification(JSONObject notification, Activity activity) {

        String FCM_API = "https://fcm.googleapis.com/fcm/send";
        String serverKey =
                "AAAAA6gibkM:APA91bG8UUtfNFwNLI6-Peu_KsbpTskmjutdJDyHq-qi5fj2UdCcjIVRCO5PlhZUNfJdeyW4-3oznOxMDWdjpfSAnpltlvtBFCoM_vir7pQLKbxc_aDzWJPs8xu27CADbMkHkq5tKgT7";

        JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(FCM_API, notification,
                new Response.Listener<JSONObject>() {
                    @Override
                    public void onResponse(JSONObject response) {
                        Log.i("notificationStuff", "onResponse: "   response.toString());
                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        Toast.makeText(activity, "Request error", Toast.LENGTH_LONG).show();
                        Log.i("notificationStuff", "onErrorResponse: Didn't work");
                    }
                }){
            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                Map<String, String> params = new HashMap<>();
                params.put("Authorization", "key="   serverKey);
                params.put("Content-Type", "application/json");
                return params;
            }
        };
        MySingleton.getInstance(activity.getApplicationContext()).addToRequestQueue(jsonObjectRequest);
    }
 

Синглтон:

 public class MySingleton {
    private  static MySingleton instance;
    private RequestQueue requestQueue;
    private Context ctx;

    private MySingleton(Context context) {
        ctx = context;
        requestQueue = getRequestQueue();
    }

    public static synchronized MySingleton getInstance(Context context) {
        if (instance == null) {
            instance = new MySingleton(context);
        }
        return instance;
    }

    public RequestQueue getRequestQueue() {
        if (requestQueue == null) {
            // getApplicationContext() is key, it keeps you from leaking the
            // Activity or BroadcastReceiver if someone passes one in.
            requestQueue = Volley.newRequestQueue(ctx.getApplicationContext());
        }
        return requestQueue;
    }

    public <T> void addToRequestQueue(Request<T> req) {
        getRequestQueue().add(req);
    }
}
 

А затем мой метод для перехвата получаемых сообщений:

 public class MyJavaFCM extends FirebaseMessagingService {

    private final String ADMIN_CHANNEL_ID ="admin_channel";

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        final Intent intent = new Intent(this, MainActivity.class);
        NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
        int notificationID = new Random().nextInt(3000);

      /*
        Apps targeting SDK 26 or above (Android O) must implement notification channels and add its notifications
        to at least one of them. Therefore, confirm if version is Oreo or higher, then setup notification channel
      */
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            setupChannels(notificationManager);
        }

        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this , 0, intent,
                PendingIntent.FLAG_ONE_SHOT);

        Bitmap largeIcon = BitmapFactory.decodeResource(getResources(),
                R.drawable.profile_icon);

        Uri notificationSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, ADMIN_CHANNEL_ID)
                .setSmallIcon(R.drawable.logo_fallback)
                .setLargeIcon(largeIcon)
                .setContentTitle(remoteMessage.getData().get("title"))
                .setContentText(remoteMessage.getData().get("message"))
                .setAutoCancel(true)
                .setSound(notificationSoundUri)
                .setContentIntent(pendingIntent);

        //Set notification color to match your app color template
        notificationBuilder.setColor(getResources().getColor(R.color.colorPrimaryDark));
        notificationManager.notify(notificationID, notificationBuilder.build());
    }


    @RequiresApi(api = Build.VERSION_CODES.O)
    private void setupChannels(NotificationManager notificationManager){
        CharSequence adminChannelName = "New notification";
        String adminChannelDescription = "Device to devie notification";

        NotificationChannel adminChannel;
        adminChannel = new NotificationChannel(ADMIN_CHANNEL_ID, adminChannelName, NotificationManager.IMPORTANCE_HIGH);
        adminChannel.setDescription(adminChannelDescription);
        adminChannel.enableLights(true);
        adminChannel.setLightColor(Color.RED);
        adminChannel.enableVibration(true);
        if (notificationManager != null) {
            notificationManager.createNotificationChannel(adminChannel);
        }
    }
}
 

Единственное указание на то, что я получаю не так, — это сообщение, которое я добавил в начале, но я не совсем уверен, что с этим делать (пытался прочитать об этом, но не смог понять многое из того, что было сказано, и не уверен, связано ли это с моим конкретным случаем.

Ответ №1:

Следуя руководству, автор написал назначение темы в формате, похожем на этот /topics/yourTopic , но я подумал, что так оно организовано в его базе данных или что-то в этом роде. Я не придал этому большого значения и не скопировал /topics часть в свой код, но именно по этой причине он не прошел.

Мне пришлось изменить это

 notification.put("to", receiverId); 
 

к этому:

 notification.put("to", "/topics/"   receiverId);