Виконав всі побажання з технічного завдання плюс ще зверху те що я запитував він реалізував.
Всім рекомендую фрілансера!
Є додаток для андроїду в якому реалізовані push сповіщення, але вони працюють не так як би мені хотілося. Якщо додаток відкритий то сповіщення вилітають вгорі і їх видно. Але якщо додаток згорнутий або не запущений то сповіщення приходять, але беззвучно і дізнатися про те що сповіщення прийшло можна лише відкривши шторку і знайшовши його.
Ось так в мене реалізовані сповіщення в файлі MessagingService.kt
package app.provapp.online
import android.Manifest
import android.annotation.SuppressLint
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.media.RingtoneManager
import android.os.Build
import android.util.Log
import android.widget.RemoteViews
import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
const val channelId = "main_channel"
SuppressLint("MissingFirebaseInstanceTokenRefresh") # Прибрав знак собаки бо фріланс не публікує проект думаючи що це імеіл :)
class MessagingService: FirebaseMessagingService() {
override fun onMessageReceived(message: RemoteMessage) {
message.notification!!.title?.let { message.notification!!.body?.let { it1 ->
createNotificationChannel(it, it1
) } }
Log.d("SDDS", "DSADAS")
}
private fun createNotificationChannel(title: String, body: String) {
val notificationChannel = NotificationChannel(channelId,
"Message Channel",
NotificationManager.IMPORTANCE_HIGH)
notificationChannel.canBypassDnd()
notificationChannel.setBypassDnd(true)
notificationChannel.enableVibration(true)
val notificationManager = NotificationManagerCompat.from(this)
notificationManager.createNotificationChannel(notificationChannel)
val notification: Notification = NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(title)
.setContentText(body)
.setChannelId(channelId)
.setDefaults(Notification.DEFAULT_ALL)
.setCategory(NotificationCompat.CATEGORY_CALL)
.setAutoCancel(true)
.setOnlyAlertOnce(true)
.setPriority(NotificationCompat.PRIORITY_HIGH) // heads-up
.setFullScreenIntent(null, true)
.build()
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.POST_NOTIFICATIONS
) != PackageManager.PERMISSION_GRANTED
) {
return
}
notificationManager.notify(0, notification)
}
}Той самий додаток має версію для айфона і там сповіщення працюють як треба - вони завжди вилітають вгорі навіть якщо додаток не запущений, таким чином користувач бачить, що сповіщення прийшло.
Бюджет: 500 UAH Термін: 1 день
Давайте розберемося у чому проблема.
Маю досвід з пушами.
Звертайтеся.
Бюджет: 500 UAH Термін: 1 день
Привіт!
Я готовий взятися за виконання цього завдання. Маю близько трьох досвіду розробки Android-застосунків, зокрема вже працював із подібними функціями. Можу швидко та якісно реалізувати потрібний функціонал.
Готовий обговорити всі деталі в особистих повідомленнях. Можу приступити до роботи сьогодні.
Буду радий співпраці!
1. Сповіщення обробляється у фоновому режимі Firebase SDK, але ви не встановлюєте правильний контекст для звукового сигналу.
2. Пріоритет повідомлення може бути недостатнім (хоча у вас стоїть PRIORITY_HIGH).
3. FullScreenIntent може бути некоректно реалізований або не потрібний.
Ось кілька способів вирішити проблему:
1. Налаштуйте звуковий сигнал
У вашому методі createNotificationChannel можна додати кастомний звук для каналу:
val soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
notificationChannel.setSound(soundUri, Notification.AUDIO_ATTRIBUTES_DEFAULT)
2. Оновіть FullScreenIntent
Замість null використовуйте PendingIntent для відкриття Activity, якщо це потрібно:
val intent = Intent(this, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
val pendingIntent = PendingIntent.getActivity(
this, 0, intent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
val notification: Notification = NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(title)
.setContentText(body)
.setChannelId(channelId)
.setDefaults(Notification.DEFAULT_ALL)
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setFullScreenIntent(pendingIntent, true) // Важливо!
.build()Це змушує Android відображати сповіщення навіть тоді, коли додаток не запущений.
3. Переконайтеся, що IMPORTANCE_HIGH
Канал сповіщень має мати максимальний рівень важливості, як ви вказали:
notificationChannel.importance = NotificationManager.IMPORTANCE_HIGH
4. Перевірте дозволи на сповіщення
Переконайтеся, що у вас є дозвіл POST_NOTIFICATIONS, який потрібен з Android 13. Для пристроїв нижче Android 13 це не потрібно:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.POST_NOTIFICATIONS
) != PackageManager.PERMISSION_GRANTED
) {
// Запросіть дозвіл
return
}
}
5. Обробка сповіщень у фоновому режимі
В Android, коли додаток у фоновому режимі, Firebase передає сповіщення напряму у системний менеджер сповіщень. У такому разі вам потрібно обробляти дані через RemoteMessage.data, якщо використовуються data-сповіщення:
override fun onMessageReceived(message: RemoteMessage) {
if (message.data.isNotEmpty()) {
val title = message.data["title"] ?: "Default Title"
val body = message.data["body"] ?: "Default Body"
createNotificationChannel(title, body)
} else {
message.notification?.let {
createNotificationChannel(it.title ?: "Default Title", it.body ?: "Default Body")
}
}
}
6. Перевірте серверну конфігурацію
Якщо ви використовуєте Firebase Console для надсилання сповіщень, переконайтеся, що обираєте опцію “High Priority”. Якщо це ваш сервер, у JSON-даних встановіть priority: "high":
{
"to": "DEVICE_TOKEN",
"priority": "high",
"notification": {
"title": "Заголовок",
"body": "Текст повідомлення"
}
}
Після внесення цих змін перевірте додаток. Це має вирішити проблему із фоновими сповіщеннями
При спробі додати
"priority" => "high",отримую помилку
{ "error": { "code": 400, "message": "Invalid JSON payload received. Unknown name \"priority\" at 'message': Cannot find field.", "status": "INVALID_ARGUMENT", "details": [ { "@type": "type.googleapis.com/google.rpc.BadRequest", "fieldViolations": [ { "field": "message", "description": "Invalid JSON payload received. Unknown name \"priority\" at 'message': Cannot find field." } ] } ] } }
Ось правильний формат для запиту до FCM API: {
"message": {
"token": "DEVICE_TOKEN",
"notification": {
"title": "Заголовок",
"body": "Текст повідомлення"
},
"android": {
"priority": "high"
}
}
}
Зараз все по старому: в шторці сповіщення з'являється, але heads-up не відбувається, тобто користувач може дізнатися що було сповіщення лише подивившись в шторці.
У вас буде час подивитися вихідний код андроїду? Може там щось не доналаштовано? Хоча я дивився всі ті параметри що ви наводили в мене прописані: і NotificationCompat.PRIORITY_HIGH і NotificationManager.IMPORTANCE_HIGH
1. Неправильний NotificationChannel
У вашому коді є правильне створення каналу сповіщень, але перевірте, чи дійсно канал налаштований правильно. Зокрема:
• Перевірте, чи використовується IMPORTANCE_HIGH, який дозволяє сповіщенням з’являтися у вигляді heads-up (спливаючих) повідомлень.
• Для пробудження екрана потрібно також забезпечити, щоб канал мав дозвіл на порушення режиму “Не турбувати”. Ви вже викликаєте setBypassDnd(true), але цього недостатньо — на деяких пристроях це потребує явного дозволу від користувача.
Рішення: Додайте код для перевірки та явного дозволу для обходу режиму DND:
if (!notificationManager.areNotificationsEnabled()) {
// Направляємо користувача до налаштувань
val intent = Intent(android.provider.Settings.ACTION_APP_NOTIFICATION_SETTINGS)
.putExtra(android.provider.Settings.EXTRA_APP_PACKAGE, packageName)
startActivity(intent)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = notificationManager.getNotificationChannel(channelId)
if (channel != null && !channel.canBypassDnd()) {
val intent = Intent(android.provider.Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
.putExtra(android.provider.Settings.EXTRA_APP_PACKAGE, packageName)
.putExtra(android.provider.Settings.EXTRA_CHANNEL_ID, channelId)
startActivity(intent)
}
}
2. setFullScreenIntent
Ваш setFullScreenIntent налаштований на null, що може не спрацьовувати для heads-up повідомлень або пробудження екрану.
Рішення: Використовуйте реальний PendingIntent:
val fullScreenIntent = Intent(this, MainActivity::class.java)
val fullScreenPendingIntent = PendingIntent.getActivity(
this, 0, fullScreenIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
val notification: Notification = NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(title)
.setContentText(body)
.setChannelId(channelId)
.setDefaults(Notification.DEFAULT_ALL)
.setCategory(NotificationCompat.CATEGORY_CALL)
.setAutoCancel(true)
.setOnlyAlertOnce(true)
.setPriority(NotificationCompat.PRIORITY_HIGH) // heads-up
.setFullScreenIntent(fullScreenPendingIntent, true) // Важливо
.build()3. Специфіка пристрою
Деякі пристрої, такі як Xiaomi, Huawei, Oppo, мають власні обмеження на показ сповіщень:
• Фонова активність: Переконайтесь, що ваш додаток має дозвіл на запуск у фоновому режимі.
• Автоматична оптимізація батареї: Відключіть оптимізацію батареї для вашого додатку через налаштування пристрою.
Код для вимкнення оптимізації батареї:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val intent = Intent(android.provider.Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
intent.data = Uri.parse("package:$packageName")
startActivity(intent)
}4. Налаштування екрану
Перевірте, чи дозволяє пристрій пробуджувати екран від сповіщень. Додайте це до коду:
val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
if (!powerManager.isInteractive) {
val wakeLock = powerManager.newWakeLock(
PowerManager.FULL_WAKE_LOCK or PowerManager.ACQUIRE_CAUSES_WAKEUP,
"app:WakeLock"
)
wakeLock.acquire(3000) // Пробудження на 3 секунди
}5. Додаткова перевірка дозволів
На Android 13 і вище потрібні дозволи для відображення heads-up сповіщень.
Переконайтесь, що дозволи POST_NOTIFICATIONS та USE_FULL_SCREEN_INTENT видані:
ActivityCompat.requestPermissions(this, arrayOf(
Manifest.permission.POST_NOTIFICATIONS
), 100)
android:exported
Ви встановили android:exported="false". Це означає, що цей сервіс може бути викликаний тільки вашим додатком, а не іншими програмами або системою.
Для Firebase Cloud Messaging (FCM) сервіс має бути доступним системі Firebase, тому android:exported має бути встановлено у true.
Ви отримуєте сповіщення, коли додаток не запущений? Чи тільки тоді, коли він запущений?
Є рішення для обох випадків…
Сповіщення приходять, але непомітно, тобто вони в шторці з'являються без видимого "вилітання" вгорі екрану (heads-up)
Здравствуйте, вы хотите, чтобы экран пробуждался, когда приходит уведомления?
Дорого, давайте за 500 грн як в задачі ))
Пуши в мене працюють, треба тільки щоб вони вспливали коли додаток згорнутий.
Напевно десь якийсь параметр треба написати і все. Тим паче якщо ви вже це робили то у вас це не займе багато часу.
Розробка під iOS (iPhone та iPad) 19 ставок 31 липня
Розробка під iOS (iPhone та iPad) 32 ставки 31 липня
31 ставка 29 липня
Розробка під iOS (iPhone та iPad) 53 ставки 22 липня