#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:
На самом деле, все начало работать должным образом, когда я произвел полную перезагрузку своего телефона, что наводит меня на мысль, что это была внутренняя проблема телефона, а не моя реализация.