一段时间或重启后未收到 FCM 推送通知
FCM Push Notification not received after some time or reboot
这里有个小问题,不幸的是,我目前无法真正解决它,所以在这里寻求帮助。
我正在尝试在我的应用程序中构建推送通知,并且我正在使用 FCM。
对于整个过程,我使用:
- Android 使用 firebase 的应用
- PHP 发送 FCM 推送通知的脚本
- MySQL 用于存储令牌的数据库。
它的工作方式如下:每次生成新令牌时,我都会将此令牌发送到我的 MySQL 数据库,然后将其存储在那里。我有一个 PHP 脚本读取数据库以获取它可以找到的所有令牌并将推送通知发送到所有设备。
我看了很多 youtube 视频并阅读了多篇关于如何做到这一点的文章,我设法让它工作,但是,它非常不稳定,我无法让它持续工作。
在某些情况下它无法正常工作,我不知道是什么原因。
案例一:
- 第 1 天:
我刚刚安装了应用程序,启动了它,然后将其置于后台。发送 Push 并成功接收。 3-4小时后我再次发送通知并成功收到。
- 第 2 天:在第 1 天之后,第二天凌晨 1 点,我再次发送通知,但从未收到。我去睡觉了,早上仍然没有收到消息,所以我尝试再次发送消息,我的 php 脚本说收到了消息(根据 Firebase 控制台响应),但从未显示通知。
-- 注意:我还在“onMessageReceived()”中实现了一个方法来将消息保存到 MySQL 这样我就可以亲自监控设备是否至少收到了消息以更好地理解它是如何有效,但设备从未收到它。
案例二:
- 第 1 天:安装应用程序。启动它,关闭它并发送 Push。成功领取。
1 小时后,我重新启动 phone。 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"
}
}
请帮我理解这里。也许我做错了什么或者我错过了什么。
事实上,当我硬重置 phone 时,一切都开始正常工作,这让我相信这是内部 phone 问题,而不是我的实现问题。
这里有个小问题,不幸的是,我目前无法真正解决它,所以在这里寻求帮助。
我正在尝试在我的应用程序中构建推送通知,并且我正在使用 FCM。 对于整个过程,我使用:
- Android 使用 firebase 的应用
- PHP 发送 FCM 推送通知的脚本
- MySQL 用于存储令牌的数据库。
它的工作方式如下:每次生成新令牌时,我都会将此令牌发送到我的 MySQL 数据库,然后将其存储在那里。我有一个 PHP 脚本读取数据库以获取它可以找到的所有令牌并将推送通知发送到所有设备。
我看了很多 youtube 视频并阅读了多篇关于如何做到这一点的文章,我设法让它工作,但是,它非常不稳定,我无法让它持续工作。
在某些情况下它无法正常工作,我不知道是什么原因。
案例一:
- 第 1 天: 我刚刚安装了应用程序,启动了它,然后将其置于后台。发送 Push 并成功接收。 3-4小时后我再次发送通知并成功收到。
- 第 2 天:在第 1 天之后,第二天凌晨 1 点,我再次发送通知,但从未收到。我去睡觉了,早上仍然没有收到消息,所以我尝试再次发送消息,我的 php 脚本说收到了消息(根据 Firebase 控制台响应),但从未显示通知。
-- 注意:我还在“onMessageReceived()”中实现了一个方法来将消息保存到 MySQL 这样我就可以亲自监控设备是否至少收到了消息以更好地理解它是如何有效,但设备从未收到它。
案例二:
- 第 1 天:安装应用程序。启动它,关闭它并发送 Push。成功领取。 1 小时后,我重新启动 phone。 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"
}
}
请帮我理解这里。也许我做错了什么或者我错过了什么。
事实上,当我硬重置 phone 时,一切都开始正常工作,这让我相信这是内部 phone 问题,而不是我的实现问题。