Не приходят данные в функцию onMessageReceived в сервисе по приему push сообщений
У меня стоит задача: при передачи PUSH передать еще данные, скажем ИД чата или ИД клиента. Пробовал первым способом: не помогло: Способ первый: Значение Received data: {} при получении сообщения через fcm - пустое. Я хотел бы получать значение переменной ChatID, в функции onMessageReceived при приеме сообщения. При этом когда свернуто приложение, то title и body отображаются на эмуляторе-приемнике в пуш сообщении. Но не в в функции onMessageReceived. В функции onMessageReceived все пусто, данные пустые. Вот код сервиса:
@file:JvmName("PushNotificationServicelUtil")
package fcmpushnotificationshttpv1
import android.util.Log
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.firestore.FieldValue
import com.google.firebase.firestore.ktx.firestore
import com.google.firebase.ktx.Firebase
import com.google.firebase.messaging.FirebaseMessaging
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import com.google.firebase.messaging.ktx.messaging
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.future.future
import kotlinx.coroutines.launch
import kotlinx.coroutines.tasks.await
import java.util.Objects
import java.util.concurrent.CompletableFuture
class PushNotificationService: FirebaseMessagingService() {
val TAG: String = "0000"
override fun onNewToken(token: String) {
super.onNewToken(token)
sendTokenToServer(token)
// Update server
}
override fun onMessageReceived(message: RemoteMessage) {
Log.d(TAG, " onMessageReceived ")
super.onMessageReceived(message)
// message.data
val map: Map<String, String> = message.data
Log.d(TAG, "Received data: $map")
val title: String? = map["title"]
val chatId: String? = map["chatId"]
Log.d(TAG, " onMessageReceived : $chatId, title: $title")
// Respond to received messages
}
suspend fun getTokenMy(): String {
val token = Firebase.messaging.token.await()
return token.toString()
}
//сохраняет токен в БАЗУ ДАННЫХ
suspend fun saveMyToken(uid: String) {
val token = Firebase.messaging.token.await()
// Check whether the retrieved token matches the one on your server for this user's device
// Example shown below with Firestore
// Add token and timestamp to Firestore for this user
val deviceToken = hashMapOf(
"token" to token,
"timestamp" to FieldValue.serverTimestamp(),
)
// Get user ID from Firebase Auth or your own server
Firebase.firestore.collection("fcmTokens").document(uid)
.set(deviceToken).await()
}
fun saveTokenFromJava(uid: String) {
GlobalScope.launch {
saveMyToken(uid)
}
}
}
/**
* my Persist token to third-party servers.
*
* Modify this method to associate the user's FCM registration token with any server-side account
* maintained by your application.
*
* @param token The new token.
*/
private fun sendTokenToServer(token: String?) {
// If you're running your own server, call API to send token and today's date for the user
// Example shown below with Firestore
// Add token and timestamp to Firestore for this user
// val uid = Objects.requireNonNull(FirebaseAuth.getInstance().currentUser)
val deviceToken = hashMapOf(
"token" to token,
// "uid" to uid,
"timestamp" to FieldValue.serverTimestamp(),
)
//ChatUtil.createChat("ZqnkGaeyk3UkRLRJH8Qh1tQiF7d2");
// FirebaseDatabase.getInstance().getReference().child("Users").child("mdlfnx5Bo4dbpKOjwmUxaiyJzAY2")
// .child("chats").setValue(chatsUpd);
// val uid = Objects.requireNonNull(FirebaseAuth.getInstance().currentUser)
// Get user ID from Firebase Auth or your own server
val uid = Objects.requireNonNull(FirebaseAuth.getInstance().currentUser)
Firebase.firestore.collection("fcmTokens").document("uid".toString())
.set(deviceToken)
}
object TokenProvider {
@OptIn(DelicateCoroutinesApi::class)
@JvmStatic
suspend fun getFirebaseToken(): CompletableFuture<String> = GlobalScope.future {
return@future FirebaseMessaging.getInstance().token.await()
}
}
А вот код AndroidManifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:usesCleartextTraffic="true"
android:supportsRtl="true"
android:theme="@style/Theme.AndroidMessenger"
tools:targetApi="31">
<activity
android:name=".RegisterActivity"
android:exported="false" />
<activity
android:name=".LoginActivity"
android:exported="true"></activity>
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ChatActivity"
android:exported="false"
android:screenOrientation="sensor"
android:windowSoftInputMode="stateHidden">
<intent-filter>
<action android:name="ACTIVITY_XPTO" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name="fcmpushnotificationshttpv1.MainActivity"
android:exported="true"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name="fcmpushnotificationshttpv1.PushNotificationService"
android:exported="false"
>
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<meta-data
android:name="preloaded_fonts"
android:resource="@array/preloaded_fonts" />
</application>
</manifest>
При этом, в моем приложении 2 пакета. Но отправка сообщений производится через сервис, написанный и находящийся в пакете fcmpushnotificationshttpv1. При этом при приеме сообщения в логе пишет другой пакет dem.corp.androidmessenger:
---------------------------- PROCESS STARTED (4173) for package dem.corp.androidmessenger ----------------------------
2025-02-14 15:33:53.802 4173-4258 0000 dem.corp.androidmessenger D Received data: {}
Второй способ, пробую: не помогает: Обнолвние, Юрий СПБ. я попробовал так: добавил класс DataBody в SendMessagesDTO.kt:
package fcmpushnotificationshttpv1
data class SendMessageDto(
val to: String?,
val data: DataBody,
val notification: NotificationBody
)
data class DataBody(
val idoffer: String
)
data class NotificationBody(
val title: String,
val body: String,
val chatId: String,
val click_action: String
)
//@file:JvmName("ChatViewModel")
//@JvmMultifileClass
package fcmpushnotificationshttpv1
import android.annotation.SuppressLint
import android.content.ContentValues.TAG
import android.content.Context
import android.util.Log
import android.widget.Toast
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.firebase.ktx.Firebase
import com.google.firebase.messaging.ktx.messaging
import kotlinx.coroutines.launch
import kotlinx.coroutines.tasks.await
import retrofit2.HttpException
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import retrofit2.create
import java.io.IOException
import java.security.AccessController.getContext
class ChatViewModel: ViewModel() {
var state by mutableStateOf(ChatState())
private set
private val api: FcmApi = Retrofit.Builder()
// .baseUrl("http://10.0.2.2:8084/")
.baseUrl("http://109.195.103.21:8084/")
.addConverterFactory(MoshiConverterFactory.create())
.build()
.create()
init {
viewModelScope.launch {
Firebase.messaging.subscribeToTopic("chat").await()
}
}
fun onRemoteTokenChange(newToken: String) {
state = state.copy(
remoteToken = newToken
)
}
fun onSubmitRemoteToken() {
state = state.copy(
isEnteringToken = false
)
}
fun onMessageChange(message: String) {
state = state.copy(
messageText = message
)
}
@SuppressLint("RestrictedApi")
fun sendMessage(isBroadcast: Boolean, tokenTo: String, title: String, body: String, chatId: String, click_action: String) {
Log.d(TAG, "sendMessage: chatId: $chatId")
// Toast.makeText(Context!, "token", Toast.LENGTH_SHORT).show()
viewModelScope.launch {
val messageDto = SendMessageDto(
// to = if(isBroadcast) null else state.remoteToken,
to = tokenTo,
data = DataBody( idoffer = "41"),
notification = NotificationBody(
title = title,
// body = state.messageText
body = body,
chatId = chatId,
click_action = click_action
)
)
Log.d(TAG, "sendMessage: ")
Log.w(
FragmentManager.TAG,
"entering function : 2222 sendMessage is BROAADCAST = $isBroadcast"
)
// api.sendMessage(messageDto)
try {
if(isBroadcast) {
api.broadcast(messageDto)
} else {
api.sendMessage(messageDto)
Log.w(
FragmentManager.TAG,
"entering function : 2222 sendMessage"
)
}
state = state.copy(
messageText = ""
)
//state = "meggase text my";
} catch(e: HttpException) {
e.printStackTrace()
} catch(e: IOException) {
e.printStackTrace()
}
}
}
}
Такой же класс добавил на сервер KTOR:
import com.google.firebase.messaging.Message
import com.google.firebase.messaging.Notification
import io.ktor.http.*
import kotlinx.serialization.Serializable
@Serializable
data class SendMessageDto(
val to: String?,
val data: Databody,
val notification: NotificationBody
)
@Serializable
data class Databody(
val idoffer: String
)
@Serializable
data class NotificationBody(
val title: String,
val body: String,
val chatId: String,
val click_action: String
)
fun SendMessageDto.toMessage(): Message {
return Message.builder()
// .putData("ggg", "dddd")
.setNotification(
Notification.builder()
.setTitle(notification.title)
.setBody((notification.body))
// .setClickaction(notification.click_action)
// .
.build()
)
.apply {
if(to == null) {
setTopic("chat")
}
else {
setToken(to)
}
}
.build()
}
И пытаюсь в mainActivity поймать idoffer:
//my
String ifOffer = "";
Intent startingIntent = getIntent();
ifOffer = startingIntent.getStringExtra("idoffer");
Log.d(TAG, "idOffer = v main activity: " + ifOffer);
и пишет значение NULL
Юрий, что делать? подскажите, почему значение null?
верно ли я догадываюсь что в сервере ktor надо еще как-то добавить переменную данных?
Я точку нажимаю и есть SetBode, setTitle. Set Data нету:
Ответы (1 шт):
Про пакеты не вчитывался и ничего не понял. Про приём данных из пуша: скорее всего у вас проблема в том, что надо с бэка слать Data
пуши, а не Notification
пуши. Notification
работают по разному в зависимости от состояния приложения и в onMessageReceived
не всегда приходят. Моя многолетняя практика говорит о том, что их следует использовать никогда. И всегда слать Data
пуши. Они работают как надо вне зависимости от состояния приложения