Android-AlarmManager不触发BroadcastReceiver以显示本地通知

问题描述 投票:2回答:2

我正在编写一个祈祷应用程序,该应用程序要求该应用程序在PrayerTimes上显示本地通知。祈祷时间每天都有所不同,因此,我使用下面的代码来显示来自BroadcastReceiver的位置通知,并紧接着安排下一个通知。

问题是,要求应用程序每天至少打开一次,以使通知按其特定时间触发。

是否可以使用警报管理器来调度BroadcastReceiver来触发本地通知而无需打开应用程序?

fun MakkahPrayer.setNotificationForPrayer(prayer: Prayer, date: Date) {
    val app = App.instance!!.applicationContext
    val preferences = PreferenceManager.getInstance(app)

    if(!preferences.isPrayerAlarmSet(prayer.name)) {
        val calendar = Calendar.getInstance()
        calendar.add(Calendar.DAY_OF_YEAR, 0)

        val dayOfYear = calendar[Calendar.DAY_OF_YEAR]

        NotificationUtils.instance.setNotification(date.time, prayer.name, dayOfYear.toString())
        preferences.setPrayerIsAlarmOn(prayer.name, true)
    }
}

NotificationUtils.kt

class NotificationUtils {
    companion object {
        val instance = NotificationUtils()
    }

    fun setNotification(timeInMilliSeconds: Long, name: String, day: String) {

        val cal = Calendar.getInstance()
        cal.time = Date()
        val millis = cal.timeInMillis

        if (timeInMilliSeconds > 0 && timeInMilliSeconds > millis) {

            val key = name + day

            val alarmManager =
                App.instance?.getSystemService(Activity.ALARM_SERVICE) as AlarmManager
            val alarmIntent = Intent(App.instance?.applicationContext, AlarmReceiver::class.java)

            alarmIntent.putExtra("prayer", name)
            alarmIntent.putExtra("timestamp", timeInMilliSeconds)
            alarmIntent.putExtra("notificationID", key)

            val calendar = Calendar.getInstance()
            calendar.timeInMillis = timeInMilliSeconds

            val pendingIntent = PendingIntent.getBroadcast(
                App.instance,
                timeInMilliSeconds.toInt(),
                alarmIntent,
                PendingIntent.FLAG_UPDATE_CURRENT
            )

            alarmManager.setExact(AlarmManager.RTC_WAKEUP, timeInMilliSeconds, pendingIntent)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timeInMilliSeconds, pendingIntent)
            } else {
                alarmManager.setExact(AlarmManager.RTC_WAKEUP, timeInMilliSeconds, pendingIntent)
            }
        }
    }
}

AlarmReceiver.kt

class AlarmReceiver : BroadcastReceiver() {
    companion object {
        private lateinit var mNotification: Notification

        const val CHANNEL_ID = "CHANNEL_ID"
        const val CHANNEL_NAME = "Prayer Notification"
    }

    override fun onReceive(context: Context, intent: Intent) {
        val manager = createChannel(context)
        showNotification(context, intent, manager)
        setNextPrayerAlarm(intent)
    }

    private fun setNextPrayerAlarm(intent: Intent) {
        if (intent.extras != null) {
            val prayerName = intent.extras!!.getString("prayer", "Prayer")
            val prayer = Prayer.valueOf(prayerName)
            MakkahPrayer.instance.removePrayerNotification(prayer)
        }

        val (nextPrayer, date) = MakkahPrayer.instance.nextPrayerWithTime()
        MakkahPrayer.instance.setNotificationForPrayer(nextPrayer, date)
    }

    private fun showNotification(
        context: Context,
        intent: Intent,
        notificationManager: NotificationManager
    ) {
        var timestamp: Long = 0
        var prayerName = "Prayer"

        var mNotificationId = ""

        if (intent.extras != null) {
            timestamp = intent.extras!!.getLong("timestamp")
            prayerName = intent.extras!!.getString("prayer", "Prayer")
            mNotificationId = intent.extras!!.getString("notificationID", "")
        }

        if (timestamp > 0) {
            val notifyIntent = Intent(context, MainActivity::class.java)

            val title = capitalize(prayerName)
            val message = "It is $title time"

            notifyIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK

            val calendar = Calendar.getInstance()
            calendar.timeInMillis = timestamp

            val pendingIntent = PendingIntent.getActivity(
                context,
                0,
                notifyIntent,
                PendingIntent.FLAG_UPDATE_CURRENT
            )
            val uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)

            mNotification = NotificationCompat.Builder(context, NotificationService.CHANNEL_ID)
                .setContentIntent(pendingIntent)
                .setSmallIcon(R.drawable.ic_alarm_black_24dp)
                .setLargeIcon(
                    BitmapFactory.decodeResource(
                        context.resources,
                        R.mipmap.ic_launcher
                    )
                )
                .setSound(uri)
                .setAutoCancel(true)
                .setContentTitle(title)
                .setStyle(
                    NotificationCompat.BigTextStyle()
                        .bigText(message)
                )
                .setColor(ContextCompat.getColor(context, R.color.colorSecondary))
                .setContentText(message).build()

            notificationManager.notify(timestamp.toInt(), mNotification)
        }
    }

    @SuppressLint("NewApi")
    private fun createChannel(context: Context): NotificationManager {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val soundUri =
                Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + App.instance?.applicationContext?.packageName + "/" + R.raw.azan)

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

            val notificationManager =
                context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

            val importance = NotificationManager.IMPORTANCE_HIGH
            val channel = NotificationChannel(CHANNEL_ID, CHANNEL_NAME, importance)
            channel.enableVibration(true)
            channel.setShowBadge(true)
            channel.canShowBadge()
            channel.enableLights(true)
            channel.lightColor = context.getColor(R.color.colorSecondary)
            channel.description =
                context.getString(R.string.notification_channel_description)
            channel.setSound(soundUri, audioAttributes)
            channel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC
            notificationManager.createNotificationChannel(channel)

            return notificationManager
        } else {
            return context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        }
    }
}
android kotlin broadcastreceiver alarmmanager android-notifications
2个回答
1
投票

您可以使用Androidx PrayerWorker创建Work Manager来安排后台API /通知设置(所有操作都无需使用打开的应用程序,而是在收到通知时进行触发。

可以找到文档here

您的setNextPrayerAlarm函数将把逻辑移到PrayerWorker,看起来像这样:

private fun setNextPrayerAlarm(intent: Intent) {
    if (intent.extras != null) {
        val oneTimeWorkRequestBuilder = OneTimeWorkRequest.Builder(PrayerWorker::class.java)
        oneTimeWorkRequestBuilder.setInputData(`put your input data here`)
        WorkManager.getInstance(context).enqueueUniqueWork("setPrayerWorker",ExistingWorkPolicy.REPLACE, oneTimeWorkRequestBuilder.build())
    }            
}

[PrayerWorker可能看起来像这样

class PrayerWorker(context: Context, workerParameters: WorkerParameters): Worker(context, workerParameters) {
    override fun doWork(): Result {
        //Insert logic to determine alarms to set 
        return Result.success() //for success case
    }
}

0
投票

尝试以下步骤

1。NotificationUtils.kt中添加一个意图标志FLAG_RECEIVER_FOREGROUND

如下所示,它将为您解决问题

        val alarmIntent = Intent(App.instance?.applicationContext, AlarmReceiver::class.java)
        alarmIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
        alarmIntent.putExtra("prayer", name)
        ....
        ...

[2。还要确保已在清单中注册了AlarmReceiver

如下所示

<receiver android:name="com.myapp.receiver.AlarmReceiver">
    </receiver>
© www.soinside.com 2019 - 2024. All rights reserved.