Home > Back-end >  FCM working in emulator, but not on real device
FCM working in emulator, but not on real device

Time:09-18

Main Activity

package com.example.pone

import android.content.ContentValues.TAG
import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.text.TextUtils
import android.util.Log
import com.google.firebase.messaging.FirebaseMessaging
import com.google.gson.Gson
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

const val TOPIC = "/topics/myTopic2"


class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)



    FirebaseService.sharedPref = getSharedPreferences("sharedPref", Context.MODE_PRIVATE)
    FirebaseMessaging.getInstance().token
        .addOnCompleteListener { task ->
            if (task.isSuccessful) {
                if (task.result != null && !TextUtils.isEmpty(task.result)) {
                    val token: String = task.result!!
                    etToken.setText(token.toString())
                }
            }
        }
    FirebaseMessaging.getInstance().subscribeToTopic(TOPIC)

    btnSend.setOnClickListener {
        val title = etTitle.text.toString()
        val message = etMessage.text.toString()
        val recipientToken = etToken.text.toString()
        if(title.isNotEmpty() && message.isNotEmpty() && recipientToken.isNotEmpty()) {
            PushNotification(
                NotificationData(title, message),
                recipientToken
            ).also {
                sendNotification(it)
            }
        }
    }
}

private fun sendNotification(notification: PushNotification) = CoroutineScope(Dispatchers.IO).launch {
    try {
        val response = RetrofitInstance.api.postNotification(notification)
        if(response.isSuccessful) {
            Log.d(TAG, "Response: ${Gson().toJson(response)}")
        } else {
            Log.e(TAG, response.errorBody().toString())
        }
    } catch(e: Exception) {
        Log.e(TAG, e.toString())
    }
}
}

Firebase Service Class

package com.example.pone

import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.NotificationManager.IMPORTANCE_HIGH
import android.app.PendingIntent
import android.app.PendingIntent.FLAG_ONE_SHOT
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.graphics.Color
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import kotlin.random.Random

private const val CHANNEL_ID = "my_channel"

class FirebaseService : FirebaseMessagingService() {

companion object {
    var sharedPref: SharedPreferences? = null

    var token: String?
        get() {
            return sharedPref?.getString("token", "")
        }
        set(value) {
            sharedPref?.edit()?.putString("token", value)?.apply()
        }
}

override fun onNewToken(newToken: String) {
    super.onNewToken(newToken)
    token = newToken
}

override fun onMessageReceived(message: RemoteMessage) {
    super.onMessageReceived(message)

    val intent = Intent(this, MainActivity::class.java)
    val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    val notificationID = Random.nextInt()

    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        createNotificationChannel(notificationManager)
    }

    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
    val pendingIntent = PendingIntent.getActivity(this, 0, intent, FLAG_ONE_SHOT)
    val notification = NotificationCompat.Builder(this, CHANNEL_ID)
        .setContentTitle(message.data["title"])
        .setContentText(message.data["message"])
        .setSmallIcon(R.drawable.common_google_signin_btn_icon_dark)
        .setAutoCancel(true)
        .setContentIntent(pendingIntent)
        .build()

    notificationManager.notify(notificationID, notification)
}

@RequiresApi(Build.VERSION_CODES.O)
private fun createNotificationChannel(notificationManager: NotificationManager) {
    val channelName = "channelName"
    val channel = NotificationChannel(CHANNEL_ID, channelName, IMPORTANCE_HIGH).apply {
        description = "My channel description"
        enableLights(true)
        lightColor = Color.GREEN
    }
    notificationManager.createNotificationChannel(channel)
}

}

PushNotification Data Class

data class PushNotification(
    val data: NotificationData,
    val to: String
)

NotificationAPI interface

import com.example.pone.Constants.Companion.CONTENT_TYPE
import com.example.pone.Constants.Companion.SERVER_KEY
import okhttp3.ResponseBody
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.Headers
import retrofit2.http.POST

interface NotificationAPI {

    @Headers("Authorization: key=$SERVER_KEY", "Content-Type:$CONTENT_TYPE")
    @POST("fcm/send")
    suspend fun postNotification(
        @Body notification: PushNotification
    ): Response<ResponseBody>
}

Notification Data Class

data class NotificationData(
    val title: String,
    val message: String
)

RetroFitIntance class

import com.example.pone.Constants.Companion.BASE_URL
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

class RetrofitInstance {

    companion object {
        private val retrofit by lazy {
            Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build()
        }

        val api by lazy {
            retrofit.create(NotificationAPI::class.java)
        }
    }
}

Constants

class Constants {

    companion object {
        const val BASE_URL = "https://fcm.googleapis.com"
        const val SERVER_KEY = "*****"
        const val CONTENT_TYPE = "application/json"
    }

}

I am receiving messages on emulator but not real device. I am able to send messages to emulator from real device but not receiving messages from emulator to real device.

Update

When I try to send message to real device itself, this error happens

2022-09-18 00:54:34.087 8325-8423/com.example.pone E/AndroidRuntime: FATAL EXCEPTION: Firebase-Messaging-Intent-Handle
    Process: com.example.pone, PID: 8325
    java.lang.IllegalArgumentException: com.example.pone: Targeting S  (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.
    Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if some functionality depends on the PendingIntent being mutable, e.g. if it needs to be used with inline replies or bubbles.
        at android.app.PendingIntent.checkFlags(PendingIntent.java:375)
        at android.app.PendingIntent.getActivityAsUser(PendingIntent.java:458)
        at android.app.PendingIntent.getActivity(PendingIntent.java:444)
        at android.app.PendingIntent.getActivity(PendingIntent.java:408)
        at com.example.pone.FirebaseService.onMessageReceived(FirebaseService.kt:52)
        at com.google.firebase.messaging.FirebaseMessagingService.dispatchMessage(FirebaseMessagingService.java:235)
        at com.google.firebase.messaging.FirebaseMessagingService.passMessageIntentToSdk(FirebaseMessagingService.java:185)
        at com.google.firebase.messaging.FirebaseMessagingService.handleMessageIntent(FirebaseMessagingService.java:172)
        at com.google.firebase.messaging.FirebaseMessagingService.handleIntent(FirebaseMessagingService.java:161)
        at com.google.firebase.messaging.EnhancedIntentService.lambda$processIntent$0$EnhancedIntentService(EnhancedIntentService.java:78)
        at com.google.firebase.messaging.EnhancedIntentService$$ExternalSyntheticLambda1.run(Unknown Source:6)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at com.google.android.gms.common.util.concurrent.zza.run(com.google.android.gms:play-services-basement@@18.1.0:2)
        at java.lang.Thread.run(Thread.java:920)

CodePudding user response:

This is kind of a bug of firebase. try after sometime, you will receive the fcm message on real device too.

CodePudding user response:

Update

Fixed

i replaced FLAG_ONE_SHOT with FLAG_MUTABLE

  • Related