【问题标题】:FCM Push Notification not received after some time or reboot一段时间后未收到 FCM 推送通知或重新启动
【发布时间】:2020-12-04 11:09:23
【问题描述】:

我这里有个小问题,很遗憾,我目前无法真正自己解决,所以在这里寻求帮助。

我正在尝试在我的应用中构建推送通知,并且我正在使用 FCM。 对于我使用的整个过程:

  • 带有 Firebase 的 Android 应用程序
  • 发送 FCM 推送通知的 PHP 脚本
  • 用于存储令牌的 MySQL DB。

它的工作方式如下:每次生成新令牌时,我都会将此令牌发送到我的 MySQL 数据库,然后将其存储在其中。我已经为它可以找到的所有令牌读取 db 并向所有设备发送推送通知的 PHP 脚本。

我观看了许多 youtube 视频并阅读了多篇关于如何做到这一点的文章,我设法让它工作,但是它非常不稳定,我无法让它持续工作。

这里有一些我不知道原因的情况下它不起作用。

案例一:

  • 第 1 天: 我刚刚安装了应用程序,启动它,然后把它放在后台。发送 Push 并成功接收。 3-4 小时后,我再次发送通知并成功接收。
  • 第 2 天:就在第 1 天之后,在第 2 天凌晨 1 点,我再次发送通知,但从未收到。我上床睡觉,早上仍然没有收到消息,所以我尝试再次发送消息,我的 php 脚本说收到了消息(根据 Firebase 控制台响应),但从未显示通知。

-- 注意:我还在 "onMessageReceived()" 中实现了一个方法来将消息保存到 MySQL,这样我就可以亲自监控设备是否至少收到了消息以更好地了解它是如何工作的,但设备永远不会甚至收到了。

案例 2:

  • 第 1 天:已安装应用程序。启动它,关闭它并发送推送。成功接收。 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;

安卓:

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

请帮助我理解这里。也许我做错了什么,或者我错过了什么。

【问题讨论】:

  • 嘿@Rey-0,关于您的案例 1,您是否在“第 1 天”和“第 2 天”测试之间重新启动了应用程序?如果应用程序已被 android 杀死(将其置于后台很长时间可能会发生这种情况),则可能会出现数据通知未正确传递的情况。根据您的onMessageRetrieved,您似乎依赖于数据通知,如果它适用于您的用例,则可能值得研究通知消息 [firebase.google.com/docs/cloud-messaging/…
  • @Marino 你好。不,我在第 1 天和第 2 天之间没有重新启动手机。 关于通知消息 - 根据我在 stackoverflow 上的内容 在我看来,为了让我的应用程序即使在后台也能接收推送通知,我应该正在使用数据消息,因为当收到数据消息时,即使应用程序被杀死或在后台,也会调用“onMessageReceived”。也许我误解了什么,所以如果我在这里错了,请纠正我。
  • 我的意思是重新启动应用程序,这应该足够了 :) 实际上,留在文档(上面链接)时,Notification MessagesData Notifications 在后台都会收到。不同之处在于Data 在后台时只有一部分被传送到通知托盘,因为只有在用户点击通知时才会处理数据负载。 Messages notifications 由 FCM 自动处理,因此试一试可能有助于排除某些部分并开始找出问题所在:)
  • @Marino 我明白了。我将再次更彻底地阅读该文档,并希望能够解决这个问题。非常感谢您的意见。

标签: android firebase firebase-cloud-messaging


【解决方案1】:

事实上,当我硬重置手机时,一切都开始正常工作,这让我相信这是手机内部问题,而不是我的实现。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-11
    • 2017-11-20
    • 2017-12-22
    • 1970-01-01
    相关资源
    最近更新 更多