使用 Kotlin 的 Firebase 云消息传递 Android

Posted

技术标签:

【中文标题】使用 Kotlin 的 Firebase 云消息传递 Android【英文标题】:Firebase Cloud Messaging Android using Kotlin 【发布时间】:2020-07-04 10:39:17 【问题描述】:

我正在尝试从 Firebase 控制台向我的应用发送云消息(推送通知)。我在这里看到了类似的问题,但对我没有任何帮助。 我遵循了文档,观看了教程,在线搜索和 ***,似乎没有什么对我有用。 MainActivity,我正在获取令牌并尝试使用它来发送测试消息。

FirebaseInstanceId.getInstance().instanceId
            .addOnCompleteListener(OnCompleteListener  task ->
                if (!task.isSuccessful) 
                    Log.w(TAG, "getInstanceId failed", task.exception)
                    return@OnCompleteListener
                

                // Get new Instance ID token
                val token = task.result?.token

                // Log and toast
                val msg = getString(R.string.msg_token_fmt, token)
                Log.d(TAG, msg)
            )

MyFirebaseMessagingService 类似于文档中的代码

class MyFirebaseMessagingService : FirebaseMessagingService() 

    override fun onMessageReceived(remoteMessage: RemoteMessage) 
        // [START_EXCLUDE]
        // There are two types of messages data messages and notification messages. Data messages are handled
        // here in onMessageReceived whether the app is in the foreground or background. Data messages are the type
        // traditionally used with GCM. Notification messages are only received here in onMessageReceived when the app
        // is in the foreground. When the app is in the background an automatically generated notification is displayed.
        // When the user taps on the notification they are returned to the app. Messages containing both notification
        // and data payloads are treated as notification messages. The Firebase console always sends notification
        // messages. For more see: https://firebase.google.com/docs/cloud-messaging/concept-options
        // [END_EXCLUDE]

        Log.e(TAG, "From: $remoteMessage.from")

        // Check if message contains a data payload.
        if (remoteMessage.data.isNotEmpty()) 
            Log.d(TAG, "Message data payload: $remoteMessage.data")

            if (/* Check if data needs to be processed by long running job */ true) 
                // For long-running tasks (10 seconds or more) use WorkManager.
                scheduleJob()
             else 
                // Handle message within 10 seconds
                handleNow()
            
        

        // Check if message contains a notification payload.
        remoteMessage.notification?.let 
            Log.d(TAG, "Message Notification Body: $it.body")

            sendNotification(it.body.toString())
        

        // Also if you intend on generating your own notifications as a result of a received FCM
        // message, here is where that should be initiated. See sendNotification method below.
    
    // [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")

        // If you want to send messages to this application instance or
        // manage this apps subscriptions on the server side, send the
        // Instance ID token to your app server.
        sendRegistrationToServer(token)
    
    // [END on_new_token]

    /**
     * Schedule async work using WorkManager.
     */
    private fun scheduleJob() 
        // [START dispatch_job]
        val work = OneTimeWorkRequest.Builder(MyWorkerActivity::class.java).build()
        WorkManager.getInstance().beginWith(work).enqueue()
        // [END dispatch_job]
    

    /**
     * Handle time allotted to BroadcastReceivers.
     */
    private fun handleNow() 
        Log.d(TAG, "Short lived task is done.")
    

    /**
     * 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?) 
        // TODO: Implement this method to send token to your app server.
        Log.d(TAG, "sendRegistrationTokenToServer($token)")
    

    /**
     * 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_stat_sample_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_DEFAULT)
            notificationManager.createNotificationChannel(channel)
        

        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build())
    

    companion object 

        private const val TAG = "MyFirebaseMsgService"
    

在我的 AndroidManifest 文件中,我有这个

<!-- [START firebase_service] -->
        <service
            android:name=".ui.services.MyFirebaseMessagingService"
            android:exported="false">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>
        <!-- [END firebase_service] -->

我看到了一个类似的问题,其中有一个关于降级 firebase 消息传递依赖项的答案,我也尝试过,但没有成功。如果有必要,我会发布更多。任何帮助将不胜感激,谢谢。

【问题讨论】:

【参考方案1】:

首先只需确保测试通知有效,在 onNewToken 位置只需记录令牌并尝试手动发送,确保您的软件在后台接受/接收通知。(打开设置并转到应用程序和通知。在该屏幕中,点击查看所有 X 应用程序(其中 X 是您已安装的应用程序数量),然后选择您的应用程序并确保“后台活动”已打开。 也试试这个,它对我有用。我希望它可以帮助 依赖:implementation 'com.google.firebase:firebase-messaging:20.2.0'

class MyFirebaseMessagingService : FirebaseMessagingService() 
    val TAG = "FirebaseMessagingService"

    @SuppressLint("LongLogTag")
    override fun onMessageReceived(remoteMessage: RemoteMessage) 
        Log.d(TAG, "msg received: $remoteMessage.from")
        if (remoteMessage.notification != null) 
            showNotification(remoteMessage.notification?.title, remoteMessage.notification?.body)
        
    
    override fun onNewToken(token: String) 
        Log.d("TAG", "Refreshed token: $token")
    
    private fun showNotification(title: String?, body: String?) 
        val intent = Intent(this, MainActivity::class.java)
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
        val pendingIntent = PendingIntent.getActivity(this, 0, intent,
            PendingIntent.FLAG_ONE_SHOT)
        val soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
        val notificationBuilder = NotificationCompat.Builder(this)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentTitle(title)
            .setContentText(body)
            .setAutoCancel(true)
            .setSound(soundUri)
            .setContentIntent(pendingIntent)
        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.notify(0, notificationBuilder.build())
    

【讨论】:

如果您的设备是华为,请查看itechify.com/2016/02/01/… 感谢您的回答,将尝试您所说的,我会告诉您进展如何。 我已经尝试了您的所有建议,但没有成功,我找不到“后台活动”选项。如果有帮助,我正在使用 OnePlus 5t 手机。 三星设备中的后台活动,请查看itechify.com/2016/02/01/… 我找不到它,但在我的设置中一切正常。我想这可能是我缺少的东西。再次感谢您提供帮助。【参考方案2】:

事实证明,我必须重新输入我的服务才能使其正常工作。我必须记住不要再复制和粘贴了。将把它留给将来遇到这个问题的任何人。编码愉快!

class FCMService : FirebaseMessagingService() 

    val TAG = "FCMService"

    override fun onMessageReceived(remoteMessage: RemoteMessage) 
        super.onMessageReceived(remoteMessage)

        Log.d(TAG,"From: $remoteMessage.from")

        if (remoteMessage.data.isNotEmpty()) 
            Log.d(TAG, "Message data payload: $remoteMessage.data")

            if (true) 
                scheduleJob()
            else 
                handleNow()
            
        

        remoteMessage.notification?.let 
            Log.d(TAG, "Message notification body: $it.body")

            sendNotification(it.body.toString())
        

    

    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,
            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_stat_sample_notification)
            .setContentTitle(getString(R.string.fcm_message))
            .setContentText(messageBody)
            .setAutoCancel(false)
            .setSound(defaultSoundUri)
            .setContentIntent(pendingIntent)

        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) 
            val channel = NotificationChannel(channelId,
                "Channel human readable title",
                NotificationManager.IMPORTANCE_DEFAULT)
            notificationManager.createNotificationChannel(channel)
        

        notificationManager.notify(0, notificationBuilder.build())

    

    override fun onNewToken(token: String) 
        //super.onNewToken(token)

        Log.d(TAG, token)
    

    private fun handleNow() 
        Log.d(TAG, "Short lived task done")
    

    private fun scheduleJob() 
        TODO("Not yet implemented")
    



<service
            android:name=".ui.services.FCMService"
            android:enabled="false"
            android:exported="false">

            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>

        </service>

【讨论】:

以上是关于使用 Kotlin 的 Firebase 云消息传递 Android的主要内容,如果未能解决你的问题,请参考以下文章

使用 Kotlin Coroutines 替换 LocalBroadcastManager 进行 Firebase 消息传递

Firebase 云函数 - 对象不能用 JSON 编码 - Kotlin 数据类

未能将价值纳入日志消息? Kotlin - Firebase

Firebase 云消息传递重复通知

验证没有 Firebase 身份验证的电子邮件 - Kotlin [重复]

如何使用 Firebase 云消息设置图像?