Push-уведомление FCM не получено через некоторое время или перезагрузка

#android #firebase #firebase-cloud-messaging

#Android #firebase #firebase-облако-обмен сообщениями

Вопрос:

Здесь у меня небольшая проблема, которую я, к сожалению, в настоящее время не могу решить самостоятельно, поэтому прошу помощи здесь.

Я пытаюсь создать push-уведомления в своем приложении и использую FCM. Для всего этого процесса я использую:

  • Приложение для Android с firebase
  • PHP-скрипт для отправки Push-уведомлений FCM
  • База данных MySQL для хранения токенов.

Это работает следующим образом: каждый раз, когда генерируется новый токен, я отправляю этот токен в свою базу данных MySQL, где он затем сохраняется. PHP-скрипт, который у меня есть, считывает базу данных для всех токенов, которые он может найти, и отправляет push-уведомление на все устройства.

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

Вот несколько сценариев, в которых это не работает по неизвестной мне причине.

Случай 1:

  • День 1: Я только что установил приложение, запустил его, а затем перевел в фоновый режим. Отправил Push и получил его успешно. Через 3-4 часа я снова отправляю уведомление и успешно получаю его.
  • День 2: Сразу после первого дня, в 1 час ночи 2-го дня, я снова отправил уведомление, но оно так и не было получено. Я лег спать, а утром сообщение так и не было получено, поэтому я попытался отправить сообщение снова, и мой php-скрипт говорит, что сообщение было получено (согласно ответу консоли Firebase), но уведомление никогда не показывается.

— Примечание: Я также внедрил метод внутри «onMessageReceived ()» для сохранения сообщения в MySQL, чтобы я мог лично отслеживать, получило ли устройство хотя бы сообщение, чтобы лучше понять, как оно работает, но устройство даже не получило его.

Случай 2:

  • День 1: Установлено приложение. Запустил его, закрыл и отправил Push. Успешно получено. Через 1 час я перезагружаю свой телефон. через 20 минут я попытался отправить Push, но так и не получил его. Я попытался запустить приложение и перевести его в фоновый режим, но все равно ничего не получил. Я пытался отправлять некоторые уведомления не с помощью PHP-скрипта, а с помощью консоли FCM, но по-прежнему ничего. Только через 10 минут я получил уведомления, которые я отправлял некоторое время назад, но я попытался отправить уведомления с помощью моего PHP-скрипта, и это все еще не сработало, и только еще через несколько минут я снова смог отправлять уведомления с помощью моего PHP.

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

Мой код:

PHP скрипт:

 <?php 

function send_notification ($tokens, $data, $priority)
{
    $url = 'https://fcm.googleapis.com/fcm/send';
    $fields = array(
        'delay_while_idle' => false,
        'android' => $priority,
        'data' => $data,
        'registration_ids' => $tokens
    );

    //var_dump($fields);

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

   $ch = curl_init();
   curl_setopt($ch, CURLOPT_URL, $url);
   curl_setopt($ch, CURLOPT_POST, true);
   curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
   curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);  
   curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
   curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
   $result = curl_exec($ch);
   
   print($ch);
   print("<br>");
   print("<br>");
   print($result);
   print("<br>");
   print("<br>");
   print(json_encode($fields));
   print("<br>");
   print("<br>");
   
   if ($result === FALSE) {
       die('Curl failed: ' . curl_error($ch));
   }
   curl_close($ch);
   return $result;
}

$conn = mysqli_connect('ip_address', 'username', "password", 'mydatabasename');

$sql = "SELECT TOKEN FROM users";

$result = mysqli_query($conn,$sql);
$tokens = array();

if(mysqli_num_rows($result) > 0 ){

    while ($row = mysqli_fetch_assoc($result)) {
        $tokens[] = $row["TOKEN"];
    }
}

mysqli_close($conn);

$data = array(
    'title' => 'This is title of the message',
    'body' => 'This is body of the message',
    'contents' => 'Simple contents of the message'
    );

$android = array(
    'priority' => 'high'
);

$message_status = send_notification($tokens, $data, $android);
echo $message_status;
  

Android:

MyFirebaseMessagingService

 class MyFirebaseMessagingService : FirebaseMessagingService() {

    /**
     * Called when message is received.
     *
     * @param remoteMessage Object representing the message received from Firebase Cloud Messaging.
     */
    override fun onMessageReceived(remoteMessage: RemoteMessage) {

        // Save received message to MySQL
        HUC.success()

        // Check if message contains a data payload.
        if (remoteMessage.data.isNotEmpty()) {
            Log.d(TAG, "Message data payload: ${remoteMessage.data}")
        }

        // Check if message contains a notification payload.
        remoteMessage.notification?.let {
            Log.d(TAG, "Message Notification Body: ${it.body}")
        }

        // Send notification containing the body of data payload
        sendNotification(remoteMessage.data["body"].toString())
    }
    // [END receive_message]

    // [START on_new_token]
    /**
     * Called if InstanceID token is updated. This may occur if the security of
     * the previous token had been compromised. Note that this is called when the InstanceID token
     * is initially generated so this is where you would retrieve the token.
     */
    override fun onNewToken(token: String) {
        Log.d(TAG, "Refreshed token: $token")
        
        // Saving my registration token to MySQL
        sendRegistrationToServer(token)
    }
    // [END on_new_token]

    /**
     * Persist token to third-party servers.
     *
     * Modify this method to associate the user's FCM InstanceID token with any server-side account
     * maintained by your application.
     *
     * @param token The new token.
     */
    private fun sendRegistrationToServer(token: String?) {
        CoroutineScope(IO).launch {
            // HttpURLConnection function to save token to MySQL
            val response = HUC.saveToken(token)
            withContext(Main){
                Log.d(TAG, "Server response: $response")
            }
        }
    }

    /**
     * Create and show a simple notification containing the received FCM message.
     *
     * @param messageBody FCM message body received.
     */
    private fun sendNotification(messageBody: String) {
        val intent = Intent(this, MainActivity::class.java)
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
        val pendingIntent = PendingIntent.getActivity(
            this, 0 /* Request code */, intent,
            PendingIntent.FLAG_ONE_SHOT
        )

        val channelId = getString(R.string.default_notification_channel_id)
        val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
        val notificationBuilder = NotificationCompat.Builder(this, channelId)
            .setSmallIcon(R.drawable.ic_notification)
            .setContentTitle(getString(R.string.fcm_message))
            .setContentText(messageBody)
            .setAutoCancel(true)
            .setSound(defaultSoundUri)
            .setContentIntent(pendingIntent)

        val notificationManager =
            getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        // Since android Oreo notification channel is needed.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                channelId,
                "Channel human readable title",
                NotificationManager.IMPORTANCE_HIGH
            )
            notificationManager.createNotificationChannel(channel)
        }

        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build())
    }

    companion object {
        private const val TAG = "MyFirebaseMsgService"
    }
}
  

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

Комментарии:

1. Привет, @ Rey-0, что касается вашего случая 1, вы перезапускали приложение между тестами «День 1» и «День 2»? Возможно, уведомления о данных не доставляются должным образом, если приложение было отключено Android (что может произойти, если оставить его в фоновом режиме так долго). На основе вашего onMessageRetrieved кажется, что вы полагаетесь на уведомления о данных, если это работает для вашего варианта использования, возможно, стоит вместо этого просмотреть сообщения с уведомлениями [ firebase.google.com/docs/cloud-messaging / …

2. @Marino Привет. Нет, я не перезапускал телефон между днем 1 и днем 2. О сообщении уведомления — Из того, что у меня есть здесь, в stackoverflow, мне показалось, что для того, чтобы мое приложение получало Push-уведомления, даже если оно работает в фоновом режиме, я должен использовать сообщения данных, поскольку при получении сообщений данных вызывается «onMessageReceived», даже если приложение отключено или работает в фоновом режиме. Возможно, я что-то неправильно понял, поэтому, пожалуйста, поправьте меня, если я ошибаюсь.

3. Я имел в виду перезапуск приложения, которого должно быть достаточно 🙂 На самом деле, оставаясь в документах (ссылка выше), оба Notification Messages и Data Notifications будут получены в фоновом режиме. Разница в том, что для Data устройств только часть из них доставляется в панель уведомлений в фоновом режиме, поскольку полезная нагрузка данных будет обрабатываться только тогда, когда пользователь нажимает на уведомление. Messages notifications вместо этого они автоматически обрабатываются FCM, поэтому их использование может помочь исключить некоторые фрагменты и начать выяснять, в чем проблема 🙂

4. @Marino Я вижу. Я еще раз более тщательно изучу эту документацию и, надеюсь, смогу разобраться в этом. Большое вам спасибо за ваш вклад.

Ответ №1:

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