Android kotlin通知功能完整实现指南:从基础到高级功能

本文将详细介绍如何在Android应用中实现通知功能,包括基础通知、动作按钮和内联回复等高级特性。

一、基础通知实现

1. 基本通知发送方法

kotlin 复制代码
fun sendBasicNotification(context: Context, title: String, message: String) {
    // 1. 创建通知渠道(Android 8.0+必需)
    val channelId = "default_channel"
    val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) 
            as NotificationManager
    
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val channel = NotificationChannel(
            channelId,
            "默认通知",
            NotificationManager.IMPORTANCE_DEFAULT
        ).apply {
            description = "普通优先级通知"
        }
        notificationManager.createNotificationChannel(channel)
    }

    // 2. 创建点击Intent
    val intent = Intent(context, MainActivity::class.java).apply {
        flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
    }
    
    val pendingIntent = PendingIntent.getActivity(
        context,
        0,
        intent,
        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
    )

    // 3. 构建并发送通知
    val notification = NotificationCompat.Builder(context, channelId)
        .setSmallIcon(R.drawable.ic_notification)
        .setContentTitle(title)
        .setContentText(message)
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setContentIntent(pendingIntent)
        .setAutoCancel(true)
        .build()

    notificationManager.notify(System.currentTimeMillis().toInt(), notification)
}

2. 检查并请求通知权限(Android 13+)

kotlin 复制代码
fun checkAndRequestNotificationPermission(activity: Activity) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        when {
            ContextCompat.checkSelfPermission(
                activity,
                Manifest.permission.POST_NOTIFICATIONS
            ) == PackageManager.PERMISSION_GRANTED -> {
                // 已有权限
            }
            activity.shouldShowRequestPermissionRationale(
                Manifest.permission.POST_NOTIFICATIONS
            ) -> {
                // 解释为什么需要权限
                showPermissionRationaleDialog(activity)
            }
            else -> {
                // 直接请求权限
                ActivityCompat.requestPermissions(
                    activity,
                    arrayOf(Manifest.permission.POST_NOTIFICATIONS),
                    REQUEST_CODE_NOTIFICATION_PERMISSION
                )
            }
        }
    }
}

二、带动作按钮的通知

1. 完整实现代码

kotlin 复制代码
fun sendNotificationWithActions(
    context: Context,
    title: String,
    message: String,
    notificationId: Int = System.currentTimeMillis().toInt()
) {
    // 1. 创建通知渠道
    val channelId = "actions_channel"
    val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) 
            as NotificationManager

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val channel = NotificationChannel(
            channelId,
            "交互通知",
            NotificationManager.IMPORTANCE_HIGH
        ).apply {
            description = "包含操作按钮的通知"
            enableVibration(true)
            vibrationPattern = longArrayOf(0, 100, 200, 300)
        }
        notificationManager.createNotificationChannel(channel)
    }

    // 2. 创建主内容Intent
    val mainIntent = Intent(context, MainActivity::class.java).apply {
        flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
        putExtra("notification_id", notificationId)
    }
    
    val mainPendingIntent = PendingIntent.getActivity(
        context,
        0,
        mainIntent,
        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
    )

    // 3. 创建动作按钮
    val actions = listOf(
        createNotificationAction(
            context,
            "ACTION_REPLY",
            "回复",
            R.drawable.ic_reply,
            1,
            notificationId
        ),
        createNotificationAction(
            context,
            "ACTION_ARCHIVE",
            "归档",
            R.drawable.ic_archive,
            2,
            notificationId
        )
    )

    // 4. 构建通知
    val notification = NotificationCompat.Builder(context, channelId)
        .setSmallIcon(R.drawable.ic_notification)
        .setContentTitle(title)
        .setContentText(message)
        .setPriority(NotificationCompat.PRIORITY_HIGH)
        .setContentIntent(mainPendingIntent)
        .setAutoCancel(true)
        .apply {
            actions.forEach { addAction(it) }
        }
        .build()

    // 5. 发送通知
    notificationManager.notify(notificationId, notification)
}

private fun createNotificationAction(
    context: Context,
    action: String,
    title: String,
    iconRes: Int,
    requestCode: Int,
    notificationId: Int
): NotificationCompat.Action {
    val intent = Intent(context, NotificationActionReceiver::class.java).apply {
        this.action = action
        putExtra("notification_id", notificationId)
    }
    
    val pendingIntent = PendingIntent.getBroadcast(
        context,
        requestCode,
        intent,
        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
    )
    
    return NotificationCompat.Action.Builder(iconRes, title, pendingIntent).build()
}

2. 广播接收器实现

kotlin 复制代码
class NotificationActionReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent?) {
        val notificationId = intent?.getIntExtra("notification_id", -1) ?: return
        
        when(intent.action) {
            "ACTION_REPLY" -> handleReplyAction(context, notificationId)
            "ACTION_ARCHIVE" -> handleArchiveAction(context, notificationId)
            // 添加更多动作处理...
        }
    }

    private fun handleReplyAction(context: Context, notificationId: Int) {
        // 启动回复Activity
        val intent = Intent(context, ReplyActivity::class.java).apply {
            flags = Intent.FLAG_ACTIVITY_NEW_TASK
            putExtra("notification_id", notificationId)
        }
        context.startActivity(intent)
    }

    private fun handleArchiveAction(context: Context, notificationId: Int) {
        // 取消通知
        val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) 
                as NotificationManager
        notificationManager.cancel(notificationId)
        
        // 显示归档成功提示
        Toast.makeText(context, "通知已归档", Toast.LENGTH_SHORT).show()
        
        // 这里可以添加实际归档逻辑...
    }
}

三、高级功能实现

1. 内联回复功能

kotlin 复制代码
fun sendNotificationWithInlineReply(
    context: Context,
    title: String,
    message: String,
    conversationId: Int
) {
    // ...前面的渠道创建等代码与之前相同...

    // 1. 创建远程输入
    val remoteInput = RemoteInput.Builder("key_text_reply")
        .setLabel("输入回复内容")
        .build()

    // 2. 创建回复动作
    val replyIntent = Intent(context, NotificationActionReceiver::class.java).apply {
        action = "ACTION_REPLY"
        putExtra("conversation_id", conversationId)
    }
    
    val replyPendingIntent = PendingIntent.getBroadcast(
        context,
        conversationId,
        replyIntent,
        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
    )

    val replyAction = NotificationCompat.Action.Builder(
        R.drawable.ic_reply,
        "回复",
        replyPendingIntent
    ).addRemoteInput(remoteInput)
     .build()

    // 3. 构建消息样式通知
    val messagingStyle = NotificationCompat.MessagingStyle("Me")
        .addMessage(message, System.currentTimeMillis(), null)

    // 4. 构建完整通知
    val notification = NotificationCompat.Builder(context, channelId)
        .setSmallIcon(R.drawable.ic_notification)
        .setStyle(messagingStyle)
        .addAction(replyAction)
        .build()

    // 5. 发送通知
    notificationManager.notify(conversationId, notification)
}

2. 处理内联回复

kotlin 复制代码
private fun handleInlineReply(intent: Intent) {
    val remoteInput = RemoteInput.getResultsFromIntent(intent)
    val replyText = remoteInput?.getCharSequence("key_text_reply")
    
    replyText?.let {
        val conversationId = intent.getIntExtra("conversation_id", -1)
        // 处理回复文本,如保存到数据库
        saveReplyToDatabase(conversationId, it.toString())
        
        // 更新通知显示已回复
        updateNotificationAsReplied(conversationId)
    }
}

四、最佳实践与优化建议

  1. 通知分组

    kotlin 复制代码
    .setGroup("messages_group")
    .setGroupSummary(true)
  2. 大图标和样式

    kotlin 复制代码
    .setLargeIcon(bitmap)
    .setStyle(NotificationCompat.BigTextStyle().bigText(longText))
  3. 通知重要性分级

    • IMPORTANCE_MIN:只在通知栏显示,无声音或提示
    • IMPORTANCE_LOW:显示并可能发出声音
    • IMPORTANCE_DEFAULT:显示并发出声音
    • IMPORTANCE_HIGH:显示为弹出式通知
  4. 适配不同厂商

    kotlin 复制代码
    // 针对小米设备
    if (Build.MANUFACTURER.equals("xiaomi", ignoreCase = true)) {
        builder.setPriority(NotificationCompat.PRIORITY_MAX)
    }
  5. 测试建议

    • 测试不同Android版本的表现
    • 测试应用处于前台和后台时的行为
    • 测试设备锁定状态下的显示

五、常见问题解决方案

  1. 通知不显示

    • 检查Android 13+的通知权限
    • 验证通知渠道重要性设置
    • 确保提供了有效的小图标
  2. 动作按钮不工作

    • 检查PendingIntent的flag设置
    • 验证广播接收器是否正确注册
    • 确保没有重复使用相同的requestCode
  3. 内联回复问题

    • 使用FLAG_MUTABLE创建PendingIntent
    • 确保RemoteInput的key与处理时一致
    • 为Android 12+添加适当的PendingIntent flag

通过本文介绍的方法,您可以实现从基础到高级的各种通知功能,为用户提供丰富的交互体验。记得根据您的应用具体需求进行调整和优化。

相关推荐
EQ-雪梨蛋花汤14 分钟前
【Part 2安卓原生360°VR播放器开发实战】第二节|基于等距圆柱投影方式实现全景视频渲染
android·音视频·vr
Railshiqian18 分钟前
Framework.jar里的类无法通过Class.forName反射某个类的问题排查
android·反射·framework.jar
鸿蒙布道师1 小时前
鸿蒙NEXT开发正则工具类RegexUtil(ArkTs)
android·ios·华为·harmonyos·arkts·鸿蒙系统·huawei
云深不知云1 小时前
Kotlin协程(一)协程简析
kotlin
Anger重名了2 小时前
🌟 一篇文章搞懂Kotlin协程:比线程更轻量的并发神器
android
缘来的精彩2 小时前
adb常用的20个命令
android·adb·kotlin
Kapaseker2 小时前
Kotlin协程异常一文通
kotlin
KimLiu2 小时前
适合Android开发者的Flutter学习指南 : 一、搭建Flutter环境
android·前端·flutter