From 11a091a725118f0d1b5d81640afdb5aa6107cc95 Mon Sep 17 00:00:00 2001 From: renhaoting <370797079@qq.com> Date: Mon, 29 Dec 2025 14:32:07 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20NotitifyUtil?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- notification/build.gradle.kts | 1 + .../notification/newUtil/NotificationUtil.kt | 359 ++++++++++++++++++ 2 files changed, 360 insertions(+) create mode 100644 notification/src/main/java/com/remax/notification/newUtil/NotificationUtil.kt diff --git a/notification/build.gradle.kts b/notification/build.gradle.kts index 7df8773..6a9989d 100644 --- a/notification/build.gradle.kts +++ b/notification/build.gradle.kts @@ -48,6 +48,7 @@ dependencies { implementation(libs.androidx.core.ktx) implementation(libs.appcompat) implementation(libs.material) + implementation(project(":core:architecture")) testImplementation(libs.junit) androidTestImplementation(libs.androidx.test.ext.junit) androidTestImplementation(libs.espresso.core) diff --git a/notification/src/main/java/com/remax/notification/newUtil/NotificationUtil.kt b/notification/src/main/java/com/remax/notification/newUtil/NotificationUtil.kt new file mode 100644 index 0000000..cbfaf75 --- /dev/null +++ b/notification/src/main/java/com/remax/notification/newUtil/NotificationUtil.kt @@ -0,0 +1,359 @@ +package com.remax.notification.newUtil + +import android.Manifest +import android.app.* +import android.content.Context +import android.content.Intent +import android.graphics.BitmapFactory +import android.graphics.Color +import android.os.Build +import android.widget.RemoteViews +import androidx.core.app.NotificationCompat +import androidx.core.app.NotificationManagerCompat +import com.ama.core.architecture.util.permission.PermissionUtil + +class NotificationUtil private constructor() { + + companion object { + private var instance: NotificationUtil? = null + + fun getInstance(): NotificationUtil { + return instance ?: synchronized(this) { + instance ?: NotificationUtil().also { instance = it } + } + } + } + + private lateinit var context: Context + private lateinit var notificationManager: NotificationManager + + /** + * 初始化工具类 + */ + fun init(context: Context) { + this.context = context.applicationContext + notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + } + + /** + * 创建通知渠道(Android 8.0+必需) + */ + fun createNotificationChannel(channelId: String, channelName: String, importance: Int) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val channel = NotificationChannel(channelId, channelName, importance).apply { + description = "Channel description" + enableLights(true) + lightColor = Color.RED + enableVibration(true) + } + notificationManager.createNotificationChannel(channel) + } + } + + /** + * 1. 基本通知 + */ + fun showBasicNotification( + channelId: String, + title: String, + content: String, + smallIcon: Int, + intent: Intent? = null, + notificationId: Int = System.currentTimeMillis().toInt() + ) { + val pendingIntent = intent?.let { + PendingIntent.getActivity(context, 0, it, PendingIntent.FLAG_IMMUTABLE) + } + + val notification = NotificationCompat.Builder(context, channelId) + .setContentTitle(title) + .setContentText(content) + .setSmallIcon(smallIcon) + .setContentIntent(pendingIntent) + .setAutoCancel(true) + .setPriority(NotificationCompat.PRIORITY_DEFAULT) + .build() + + showNotification(notificationId, notification) + } + + /** + * 2. 大文本样式通知 + */ + fun showBigTextNotification( + channelId: String, + title: String, + content: String, + bigText: String, + smallIcon: Int, + intent: Intent? = null, + notificationId: Int = System.currentTimeMillis().toInt() + ) { + val pendingIntent = intent?.let { + PendingIntent.getActivity(context, 0, it, PendingIntent.FLAG_IMMUTABLE) + } + + val bigTextStyle = NotificationCompat.BigTextStyle() + .bigText(bigText) + .setBigContentTitle(title) + .setSummaryText(content) + + val notification = NotificationCompat.Builder(context, channelId) + .setStyle(bigTextStyle) + .setContentTitle(title) + .setContentText(content) + .setSmallIcon(smallIcon) + .setContentIntent(pendingIntent) + .setAutoCancel(true) + .build() + + showNotification(notificationId, notification) + } + + /** + * 3. 大图片样式通知 + */ + fun showBigPictureNotification( + channelId: String, + title: String, + content: String, + bigPictureResId: Int, + smallIcon: Int, + intent: Intent? = null, + notificationId: Int = System.currentTimeMillis().toInt() + ) { + val pendingIntent = intent?.let { + PendingIntent.getActivity(context, 0, it, PendingIntent.FLAG_IMMUTABLE) + } + + val bigPicture = BitmapFactory.decodeResource(context.resources, bigPictureResId) + val bigPictureStyle = NotificationCompat.BigPictureStyle() + .bigPicture(bigPicture) + .setBigContentTitle(title) + .setSummaryText(content) + + val notification = NotificationCompat.Builder(context, channelId) + .setStyle(bigPictureStyle) + .setContentTitle(title) + .setContentText(content) + .setSmallIcon(smallIcon) + .setContentIntent(pendingIntent) + .setAutoCancel(true) + .build() + + showNotification(notificationId, notification) + } + + /** + * 4. 进度条通知 + */ + fun showProgressNotification( + channelId: String, + title: String, + content: String, + smallIcon: Int, + maxProgress: Int, + currentProgress: Int, + indeterminate: Boolean = false, + notificationId: Int = System.currentTimeMillis().toInt() + ) { + val notification = NotificationCompat.Builder(context, channelId) + .setContentTitle(title) + .setContentText(content) + .setSmallIcon(smallIcon) + .setProgress(maxProgress, currentProgress, indeterminate) + .setOngoing(!indeterminate) // 确定进度的通知持续显示 + .setAutoCancel(true) + .build() + + showNotification(notificationId, notification) + } + + /** + * 5. 带操作按钮的通知 + */ + fun showActionNotification( + channelId: String, + title: String, + content: String, + smallIcon: Int, + actions: List, + intent: Intent? = null, + notificationId: Int = System.currentTimeMillis().toInt() + ) { + val pendingIntent = intent?.let { + PendingIntent.getActivity(context, 0, it, PendingIntent.FLAG_IMMUTABLE) + } + + val builder = NotificationCompat.Builder(context, channelId) + .setContentTitle(title) + .setContentText(content) + .setSmallIcon(smallIcon) + .setContentIntent(pendingIntent) + .setAutoCancel(true) + + // 添加操作按钮(最多3个) + actions.take(3).forEach { action -> + val actionPendingIntent = PendingIntent.getActivity( + context, + action.requestCode, + action.intent, + PendingIntent.FLAG_IMMUTABLE + ) + builder.addAction(action.smallIcon, action.title, actionPendingIntent) + } + + showNotification(notificationId, builder.build()) + } + + /** + * 6. 收件箱样式通知(多行文本) + */ + fun showInboxNotification( + channelId: String, + title: String, + lines: List, + smallIcon: Int, + intent: Intent? = null, + notificationId: Int = System.currentTimeMillis().toInt() + ) { + val pendingIntent = intent?.let { + PendingIntent.getActivity(context, 0, it, PendingIntent.FLAG_IMMUTABLE) + } + + val inboxStyle = NotificationCompat.InboxStyle() + .setBigContentTitle(title) + .setSummaryText("${lines.size}条新消息") + + lines.take(7).forEach { line -> // 最多显示7行 + inboxStyle.addLine(line) + } + + val notification = NotificationCompat.Builder(context, channelId) + .setStyle(inboxStyle) + .setContentTitle(title) + .setContentText("您有${lines.size}条新消息") + .setSmallIcon(smallIcon) + .setContentIntent(pendingIntent) + .setAutoCancel(true) + .setNumber(lines.size) // 显示消息数量 + .build() + + showNotification(notificationId, notification) + } + + /** + * 7. 自定义布局通知 + */ + fun showCustomNotification( + channelId: String, + layoutResId: Int, + smallIcon: Int, + customViews: Map, // viewId to value + intent: Intent? = null, + notificationId: Int = System.currentTimeMillis().toInt() + ) { + val pendingIntent = intent?.let { + PendingIntent.getActivity(context, 0, it, PendingIntent.FLAG_IMMUTABLE) + } + + val remoteViews = RemoteViews(context.packageName, layoutResId) + + // 设置自定义视图内容 + customViews.forEach { (viewId, value) -> + when (value) { + is String -> remoteViews.setTextViewText(viewId, value) + is Int -> remoteViews.setImageViewResource(viewId, value) + // 可以扩展其他类型... + } + } + + val notification = NotificationCompat.Builder(context, channelId) + .setContent(remoteViews) + .setSmallIcon(smallIcon) + .setContentIntent(pendingIntent) + .setAutoCancel(true) + .setCustomContentView(remoteViews) // 设置自定义视图 + .build() + + showNotification(notificationId, notification) + } + + private fun showNotification(notificationId: Int = System.currentTimeMillis().toInt(), notification: Notification) { + + if (!isNotificationsEnabled()) { + PermissionUtil.checkPermission(Manifest.permission.POST_NOTIFICATIONS, object : PermissionUtil.ICallback() { + override fun onAllGranted() { + NotificationManagerCompat.from(context).notify(notificationId, notification) + } + + override fun onPartialGranted() { + } + + override fun onAllRejected() { + } + }) + } else { + NotificationManagerCompat.from(context).notify(notificationId, notification) + } + } + + + /** + * 检查通知权限 + */ + fun isNotificationsEnabled(): Boolean { + return NotificationManagerCompat.from(context).areNotificationsEnabled() + } + + /** + * 检查特定渠道是否启用(Android 8.0+) + */ + fun isNotificationChannelEnabled(channelId: String): Boolean { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val channel = notificationManager.getNotificationChannel(channelId) + return channel?.importance != NotificationManager.IMPORTANCE_NONE + } + return true + } + + /** + * 取消通知 + */ + fun cancelNotification(notificationId: Int) { + NotificationManagerCompat.from(context).cancel(notificationId) + } + + /** + * 取消所有通知 + */ + fun cancelAllNotifications() { + NotificationManagerCompat.from(context).cancelAll() + } + + /** + * 更新进度通知 + */ + fun updateProgress( + notificationId: Int, + channelId: String, + title: String, + content: String, + smallIcon: Int, + maxProgress: Int, + currentProgress: Int, + indeterminate: Boolean = false + ) { + showProgressNotification(channelId, title, content, smallIcon, maxProgress, currentProgress, indeterminate, notificationId) + } +} + +/** + * 操作按钮数据类 + */ +data class NotificationAction( + val title: String, + val intent: Intent, + val smallIcon: Int, + val requestCode: Int +) \ No newline at end of file