新的通知框架

This commit is contained in:
renhaoting 2025-12-29 16:56:08 +08:00
parent b59b858352
commit 6018362656
7 changed files with 198 additions and 52 deletions

View File

@ -0,0 +1,14 @@
package com.remax.notification.newUtil
import android.content.Intent
class NotificationConfig(val notificationId: Int = System.currentTimeMillis().toInt(),
val channelId: String,
val channelName: String,
val title: String,
val content: String,
val smallIcon: Int,
val intent: Intent? = null,
val useFullScreenIntent: Boolean = false,
) {
}

View File

@ -0,0 +1,59 @@
package com.remax.notification.newUtil
import android.app.PendingIntent
import android.content.Intent
import com.ama.core.architecture.util.ResUtil
import com.remax.notification.R
import java.util.concurrent.ConcurrentHashMap
object NotificationDatas {
// notifi type
const val NOTI_TYPE_BG_WITHDRAW = "NOTI_TYPE_BG_WITHDRAW"
const val NOTI_TYPE_BG_RANDOM = "NOTI_TYPE_BG_RANDOM"
const val NOTI_TYPE_RESIDENT = "NOTI_TYPE_RESIDENT"
const val NOTI_TYPE_UNLOCK = "NOTI_TYPE_UNLOCK"
// notifi id
const val NOTI_ID_TYPE_BG_WITHDRAW = 666
const val NOTI_ID_TYPE_BG_RANDOM = 667
const val NOTI_ID_TYPE_RESIDENT = 668
const val NOTI_ID_TYPE_UNLOCK = 669
// channelId type
const val CHANNEL_TYPE_BG_WITHDRAW = "CHANNEL_TYPE_BG_WITHDRAW"
const val CHANNEL_TYPE_BG_RANDOM = "CHANNEL_TYPE_BG_RANDOM"
const val CHANNEL_TYPE_RESIDENT = "CHANNEL_TYPE_RESIDENT"
const val CHANNEL_TYPE_UNLOCK = "CHANNEL_TYPE_UNLOCK"
// channelId name
const val CHANNEL_TYPE_BG_WITHDRAW_NAME = "CHANNEL_TYPE_BG_WITHDRAW_NAME"
const val CHANNEL_TYPE_BG_RANDOM_NAME = "CHANNEL_TYPE_BG_RANDOM_NAME"
const val CHANNEL_TYPE_RESIDENT_NAME = "CHANNEL_TYPE_RESIDENT_NAME"
const val CHANNEL_TYPE_UNLOCK_NAME = "CHANNEL_TYPE_UNLOCK_NAME"
private val mConfigList: ConcurrentHashMap<String, NotificationConfig> = ConcurrentHashMap()
init {
mConfigList.put(NOTI_TYPE_BG_WITHDRAW, NotificationConfig(
NOTI_ID_TYPE_BG_WITHDRAW,
CHANNEL_TYPE_BG_WITHDRAW,
CHANNEL_TYPE_BG_WITHDRAW_NAME,
ResUtil.getString(R.string.title_bg_withdraw),
String.format(ResUtil.getString(R.string.content_bg_withdraw), 50),
R.mipmap.icon_bg_withdraw,
null,
true,
))
}
fun getConfigForType(notifiType: String): NotificationConfig? {
return mConfigList[notifiType]
}
}

View File

@ -9,8 +9,10 @@ import android.graphics.Color
import android.os.Build import android.os.Build
import android.widget.RemoteViews import android.widget.RemoteViews
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.annotation.RequiresPermission
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import com.ama.core.architecture.BaseApp
import com.ama.core.architecture.util.permission.PermissionUtil import com.ama.core.architecture.util.permission.PermissionUtil
class NotificationUtil private constructor() { class NotificationUtil private constructor() {
@ -25,15 +27,14 @@ class NotificationUtil private constructor() {
} }
} }
private lateinit var context: Context private val context = BaseApp.appContext()
private lateinit var notificationManager: NotificationManager private var notificationManager: NotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
/** /**
* 初始化工具类 * 初始化工具类
*/ */
fun init(context: Context) { fun init(context: Context) {
this.context = context.applicationContext
notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
} }
/** /**
@ -75,7 +76,7 @@ class NotificationUtil private constructor() {
.setPriority(NotificationCompat.PRIORITY_DEFAULT) .setPriority(NotificationCompat.PRIORITY_DEFAULT)
.build() .build()
showNotification(notificationId, notification) showNotification(notificationId, notification, "name")
} }
/** /**
@ -108,7 +109,7 @@ class NotificationUtil private constructor() {
.setAutoCancel(true) .setAutoCancel(true)
.build() .build()
showNotification(notificationId, notification) showNotification(notificationId, notification, "name")
} }
/** /**
@ -142,7 +143,7 @@ class NotificationUtil private constructor() {
.setAutoCancel(true) .setAutoCancel(true)
.build() .build()
showNotification(notificationId, notification) showNotification(notificationId, notification, "name")
} }
/** /**
@ -167,7 +168,7 @@ class NotificationUtil private constructor() {
.setAutoCancel(true) .setAutoCancel(true)
.build() .build()
showNotification(notificationId, notification) showNotification(notificationId, notification, "name")
} }
/** /**
@ -204,7 +205,7 @@ class NotificationUtil private constructor() {
builder.addAction(action.smallIcon, action.title, actionPendingIntent) builder.addAction(action.smallIcon, action.title, actionPendingIntent)
} }
showNotification(notificationId, builder.build()) showNotification(notificationId, builder.build(), "name")
} }
/** /**
@ -240,7 +241,7 @@ class NotificationUtil private constructor() {
.setNumber(lines.size) // 显示消息数量 .setNumber(lines.size) // 显示消息数量
.build() .build()
showNotification(notificationId, notification) showNotification(notificationId, notification, "name")
} }
/** /**
@ -277,7 +278,7 @@ class NotificationUtil private constructor() {
.setCustomContentView(remoteViews) // 设置自定义视图 .setCustomContentView(remoteViews) // 设置自定义视图
.build() .build()
showNotification(notificationId, notification) showNotification(notificationId, notification, "name")
} }
@ -295,21 +296,19 @@ class NotificationUtil private constructor() {
* @param useFullScreenIntent 是否使用全屏意图来电等高优先级场景 * @param useFullScreenIntent 是否使用全屏意图来电等高优先级场景
* @param notificationId 通知ID * @param notificationId 通知ID
*/ */
fun showHeadsUpNotification( fun showHeadsUpNotification(notifiConfig: NotificationConfig) {
channelId: String, val notificationId = notifiConfig.notificationId
channelName: String, val channelId = notifiConfig.channelId
title: String, val channelName = notifiConfig.channelName
content: String, val title = notifiConfig.title
smallIcon: Int, val content = notifiConfig.content
intent: Intent? = null, val smallIcon = notifiConfig.smallIcon
useFullScreenIntent: Boolean = false, val intent = notifiConfig.intent
notificationId: Int = System.currentTimeMillis().toInt() val useFullScreenIntent = notifiConfig.useFullScreenIntent
) {
// 1. 确保初始化
if (!this::context.isInitialized) {
throw IllegalStateException("NotificationUtil must be initialized first")
}
// 1. 确保初始化
val builder = NotificationCompat.Builder(context, channelId) val builder = NotificationCompat.Builder(context, channelId)
// 2. 设置通知基本内容 // 2. 设置通知基本内容
@ -348,7 +347,7 @@ class NotificationUtil private constructor() {
} }
// 6. 发送通知 // 6. 发送通知
showNotification(notificationId, builder.build()) showNotification(notificationId, builder.build(), "name")
} }
/** /**
@ -400,12 +399,13 @@ class NotificationUtil private constructor() {
private fun showNotification(notificationId: Int = System.currentTimeMillis().toInt(), notification: Notification) { private fun showNotification(notificationId: Int = System.currentTimeMillis().toInt(),
notification: Notification,
channelName: String) {
if (!isNotificationsEnabled()) { if (!isNotificationsEnabled()) {
PermissionUtil.checkPermission(Manifest.permission.POST_NOTIFICATIONS, object : PermissionUtil.ICallback() { PermissionUtil.checkPermission(Manifest.permission.POST_NOTIFICATIONS, object : PermissionUtil.ICallback() {
override fun onAllGranted() { override fun onAllGranted() {
NotificationManagerCompat.from(context).notify(notificationId, notification) doShowNotification(notificationId, notification, channelName)
} }
override fun onPartialGranted() { override fun onPartialGranted() {
@ -415,10 +415,18 @@ class NotificationUtil private constructor() {
} }
}) })
} else { } else {
NotificationManagerCompat.from(context).notify(notificationId, notification) doShowNotification(notificationId, notification, channelName)
} }
} }
@RequiresPermission(Manifest.permission.POST_NOTIFICATIONS)
private fun doShowNotification(notificationId: Int = System.currentTimeMillis().toInt(), notification: Notification, channelName: String) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel(notification.channelId, channelName, NotificationCompat.PRIORITY_HIGH)
}
NotificationManagerCompat.from(context).notify(notificationId, notification)
}
/** /**
* 检查通知权限 * 检查通知权限

View File

@ -21,6 +21,9 @@ import com.remax.base.report.DataReportManager
import com.remax.notification.config.NotificationConfigController import com.remax.notification.config.NotificationConfigController
import com.remax.notification.controller.NotificationTriggerController import com.remax.notification.controller.NotificationTriggerController
import com.remax.notification.check.NotificationCheckController import com.remax.notification.check.NotificationCheckController
import com.remax.notification.newUtil.NotificationDatas
import com.remax.notification.newUtil.NotificationDatas.NOTI_TYPE_BG_WITHDRAW
import com.remax.notification.newUtil.NotificationUtil
import com.remax.notification.utils.NotiLogger import com.remax.notification.utils.NotiLogger
import com.remax.notification.utils.FCMTopicManager import com.remax.notification.utils.FCMTopicManager
import com.remax.notification.service.FCMService import com.remax.notification.service.FCMService
@ -245,6 +248,28 @@ class NotificationTimingController private constructor() : LifecycleObserver {
triggerNotificationIfAllowed(NotificationCheckController.NotificationType.UNLOCK) triggerNotificationIfAllowed(NotificationCheckController.NotificationType.UNLOCK)
} }
/**
* 释放资源
*/
fun release() {
try {
screenReceiver?.let { receiver ->
context?.unregisterReceiver(receiver)
screenReceiver = null
}
ProcessLifecycleOwner.get().lifecycle.removeObserver(this)
isInitialized.set(false)
context = null
NotiLogger.d("通知时机控制器已释放")
} catch (e: Exception) {
NotiLogger.e("释放通知时机控制器失败", e)
}
}
/** /**
* 通用通知触发方法 * 通用通知触发方法
* @param type 通知类型 * @param type 通知类型
@ -258,10 +283,12 @@ class NotificationTimingController private constructor() : LifecycleObserver {
NotificationCheckController.NotificationType.RESIDENT -> "" NotificationCheckController.NotificationType.RESIDENT -> ""
} }
DataReportManager.reportData("Notific_Pull", mapOf("topic" to "localPush")) DataReportManager.reportData("Notific_Pull", mapOf("topic" to "localPush"))
// 检查是否可以触发通知,并获取具体的拦截原因 /*// 检查是否可以触发通知,并获取具体的拦截原因
val checkResult = NotificationCheckController.getInstance().canTriggerNotificationWithReason(type) val checkResult = NotificationCheckController.getInstance().canTriggerNotificationWithReason(type)
if (/*!checkResult.first*/false) { if (*//*!checkResult.first*//*false) {
val blockReason = checkResult.second val blockReason = checkResult.second
val reasonString = blockReason?.reason ?: "unknown" val reasonString = blockReason?.reason ?: "unknown"
val reasonDescription = blockReason?.description ?: "未知原因" val reasonDescription = blockReason?.description ?: "未知原因"
@ -277,28 +304,48 @@ class NotificationTimingController private constructor() : LifecycleObserver {
NotificationTriggerController.triggerGeneralNotification(type){ NotificationTriggerController.triggerGeneralNotification(type){
NotificationCheckController.getInstance().recordNotificationTrigger(type) NotificationCheckController.getInstance().recordNotificationTrigger(type)
NotificationCheckController.getInstance().incrementNotificationCount() NotificationCheckController.getInstance().incrementNotificationCount()
}*/
when (type) {
NotificationCheckController.NotificationType.UNLOCK -> {
//showNotifyUnlock()
}
NotificationCheckController.NotificationType.BACKGROUND -> {
showNotifyWithdraw()
//showNotifyRandom()
//showNotifyResident()
}
NotificationCheckController.NotificationType.KEEPALIVE -> {
}
NotificationCheckController.NotificationType.FCM -> {
}
NotificationCheckController.NotificationType.RESIDENT -> {
}
}
}
private fun showNotifyWithdraw() {
NotificationDatas.getConfigForType(NOTI_TYPE_BG_WITHDRAW)?.let {
NotificationUtil.getInstance().showHeadsUpNotification(it)
} }
} }
/**
* 释放资源
*/
fun release() {
try {
screenReceiver?.let { receiver ->
context?.unregisterReceiver(receiver)
screenReceiver = null
}
ProcessLifecycleOwner.get().lifecycle.removeObserver(this)
isInitialized.set(false)
context = null
NotiLogger.d("通知时机控制器已释放")
} catch (e: Exception) {
NotiLogger.e("释放通知时机控制器失败", e)
}
}
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@ -5,4 +5,14 @@
<string name="noti_restore_file_count">%s 个文件</string> <string name="noti_restore_file_count">%s 个文件</string>
<string name="noti_clean">清理</string> <string name="noti_clean">清理</string>
<string name="noti_recovery">恢复</string> <string name="noti_recovery">恢复</string>
<!-- new text for notify -->
<string name="title_bg_withdraw">Hey there!</string>
<string name="content_bg_withdraw">Don\'t miss your R$ %d, Tap to withdraw!</string>
</resources> </resources>

View File

@ -9,4 +9,12 @@
<string name="noti_resident_service_running">Service is running</string> <string name="noti_resident_service_running">Service is running</string>
<string name="vidi_go">GO</string> <string name="vidi_go">GO</string>
<!-- new text for notify -->
<string name="title_bg_withdraw">Olá!</string>
<string name="content_bg_withdraw">Não perca seus R$ %d. Toque para sacar!</string>
</resources> </resources>