Kanały powiadomień dla Firebase

Kanały powiadomień dla Firebase
Marcin Kosela
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 36
0

Cześć,

nie będę oszukiwał i przyznam się od razu, że nie mam żadnego doświadczenia w programowaniu aplikacji mobilnych. Potrzebuję jednak napisać prosty program który wyświetli powiadomienia przychodzące na Firebase. Udało mi się stworzyć prostą aplikację w Kotlin. Powiadomienia są poprawnie obsługiwane jednak chciałbym rozróżnić 2 typy powiadomień:

  1. Alarm - przychodzące powiadomienie powinno uruchomić wcześniej skonfigurowany dźwięk alarmu i działać z pominięciem trybu "nie przeszkadzać"
  2. Powiadomienie - standardowe powiadomienie które może być obsłużone nawet bez dźwięku

Udało mi się ustawić obydwa powiadomienia ale działa to tylko wtedy dgy utrzymuję aplikację uruchomioną. Gdy tylko ją zminimalizuję/zamknę powiadomienie przychodzi tylko z dźwiękiem skonfigurowanym jako:

Kopiuj
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_channel_id"
            android:value="@string/channel_name_notification" />

Najważniejsze funkcje:

Kopiuj
private fun createNotificationChannel() {
        val name = "MyHome Notification channel"
        val descriptionText = getString(R.string.channel_description_notification)
        val importance = NotificationManager.IMPORTANCE_DEFAULT
        val soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)

        val audioAttributes = AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
            .setUsage(AudioAttributes.USAGE_NOTIFICATION)
            .build()

        val channel = NotificationChannel(getString(R.string.channel_name_notification), name, importance).apply {
            description = descriptionText
            setSound(soundUri, audioAttributes)
            enableVibration(true)
            vibrationPattern = longArrayOf(1000, 1000, 1000, 1000, 1000)
        }

        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.createNotificationChannel(channel)
    }

    private fun createAlarmNotificationChannel() {
        val name = "MyHome Alarm channel"
        val descriptionText = getString(R.string.channel_description_alarm)
        val importance = NotificationManager.IMPORTANCE_HIGH

        val soundUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + this.packageName + "/" + R.raw.alarm_sound)

        val audioAttributes = AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
            .setUsage(AudioAttributes.USAGE_ALARM)
            .build()

        val channel = NotificationChannel(getString(R.string.channel_name_alarm), name, importance).apply {
            description = descriptionText
            setSound(soundUri, audioAttributes)
            enableVibration(true)
            vibrationPattern = longArrayOf(1000, 1000, 1000, 1000, 1000)
        }
        channel.setBypassDnd(true)

        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.createNotificationChannel(channel)
    }
Kopiuj
   private fun sendNotification(title: String?, messageBody: String?) {
        val intent = Intent(this, MainActivity::class.java).apply {
            addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
        }
        val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE)

        val isAlarm = title?.contains("Alarm!", ignoreCase = true) ?: false
        val channelId = if (isAlarm) {
            getString(R.string.channel_name_alarm)
        } else {
            getString(R.string.channel_name_notification)
        }

        Log.d(TAG, "Sending notification: Title: $title -> is alarm?: $isAlarm -> Channel ID: $channelId")

        val soundUri = if (isAlarm) {
            Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + this.packageName + "/" + R.raw.alarm_sound)
        } else {
            RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
        }

        val notificationBuilder = NotificationCompat.Builder(this, channelId)
            .setSmallIcon(R.drawable.ic_notification)
            .setContentTitle(title)
            .setContentText(messageBody)
            .setAutoCancel(true)
            .setContentIntent(pendingIntent)
            .setSound(soundUri)

        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.notify(if (isAlarm) alarmId else notificationId, notificationBuilder.build())
    }

    companion object {
        private const val TAG = "MyFirebaseMsgService"
    }

Gdzieś wyczytałem, że po zminimalizowaniu aplikacji, android kasuje inne niż domyślny kanał powiadomień dla danej aplikacji więc można używać tylko jednego. Może jest jakiś prosty sposób żeby to rozwiązać?

KO
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Miasto Spotkań
  • Postów: 34
0

Skąd wywołujesz te funkcje? Pod tym linkiem masz małą tabelkę jak to działa na foreground i background https://firebase.google.com/docs/cloud-messaging/android/receive

Marcin Kosela
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 36
0

createNotificationChannel() i createAlarmNotificationChannel() z MainActivity w funkcji onCreate(). Do powiadomień mam utworzoną usługę:

Kopiuj
        <service
            android:name=".MyFirebaseMessagingService"
            android:exported="true">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT"/>
            </intent-filter>
        </service>

i w MyFirebaseMessagingService:

Kopiuj
class MyFirebaseMessagingService : FirebaseMessagingService() {
    private val notificationId = Constants.NOTIFICATIONID
    private val alarmId = Constants.ALARMID

    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        remoteMessage.notification?.let {
            Log.d(TAG, "Received push message: ${it.title}")
            sendNotification(it.title, it.body)
        }
    }

    override fun onNewToken(token: String) {
        Log.d(TAG, "Refreshed token: $token")
        sendToken("KoSik", "Majeczka11", token)
    }

    private fun sendNotification(title: String?, messageBody: String?) {
        val intent = Intent(this, MainActivity::class.java).apply {
            addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
        }
        val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE)

        val isAlarm = title?.contains("Alarm!", ignoreCase = true) ?: false
        val channelId = if (isAlarm) {
            getString(R.string.channel_name_alarm)
        } else {
            getString(R.string.channel_name_notification)
        }

        Log.d(TAG, "Sending notification: Title: $title -> is alarm?: $isAlarm -> Channel ID: $channelId")

        val soundUri = if (isAlarm) {
            Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + this.packageName + "/" + R.raw.alarm_sound)
        } else {
            RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
        }

        val notificationBuilder = NotificationCompat.Builder(this, channelId)
            .setSmallIcon(R.drawable.ic_notification)
            .setContentTitle(title)
            .setContentText(messageBody)
            .setAutoCancel(true)
            .setContentIntent(pendingIntent)
            .setSound(soundUri)

        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.notify(if (isAlarm) alarmId else notificationId, notificationBuilder.build())
    }

    companion object {
        private const val TAG = "MyFirebaseMsgService"
    }

Przejrzałem artykuł z linku i jeśli dobrze to rozumiem to u mnie wszystko się zgadza

KO
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Miasto Spotkań
  • Postów: 34
0

No to jest dokładnie to co opisałem. System tray w tej tabelce oznacza, że nie dostajesz callbacku w onMessageReceived tylko system wysyła powiadomienie. Nie masz nad nim kontroli w zasadzie @Marcin Kosela

Marcin Kosela
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 36
0
kosiarska_ napisał(a):

No to jest dokładnie to co opisałem. System tray w tej tabelce oznacza, że nie dostajesz callbacku w onMessageReceived tylko system wysyła powiadomienie. Nie masz nad nim kontroli w zasadzie @Marcin Kosela

Przepraszam, że tak późno ale zaginąłem w innych projektach. Dziękuję za małą podpowiedź. Moje pytanie jednak brzmiało "może jest jakiś prosty sposób żeby to rozwiązać?"

KO
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Miasto Spotkań
  • Postów: 34
0

Tzn jeżeli masz ograniczenia platformowe to raczej tego nie pokonasz. W pewnych sytuacjach notyfikacja przychodzi bez Twojej wiedzy (jakby poza Twoim kodem). Można zaimplementować notification listener service i nasłuchiwać przychodzących powiadomień, wtedy dostaniesz callback w kodzie jak przyjdzie notyfikacja i możesz zrobić z tym co tylko chcesz.

Marcin Kosela
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 36
0

Jakie to durne, że nie ma prostego rozwiązania na zaimpementowanie tak prostej i wydawałoby się, oczywistej funkcjonalności. Dziękuję Ci za pomoc. Skorzystam z Twojego pomysłu albo uruchomię po prostu 2 osobne usługi (2 osobne programy) z których każdy będzie obsługiwał inne powiadomienia

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.