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

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

相关推荐
儿歌八万首2 小时前
Jetpack Compose 实战:实现一个动态平滑折线图
android·折线图·compose
李艺为6 小时前
Fake Device Test作假屏幕分辨率分析
android·java
zh_xuan6 小时前
github远程library仓库升级
android·github
峥嵘life6 小时前
Android蓝牙停用绝对音量原理
android
小书房7 小时前
Kotlin的内联函数
java·开发语言·kotlin·inline·内联函数
czlczl200209258 小时前
IN和BETWEEN在索引效能的区别
android·adb
Volunteer Technology8 小时前
ES高级搜索功能
android·大数据·elasticsearch
北京自在科技8 小时前
Find Hub App 小更新
android·ios·安卓·findmy·airtag
lbb 小魔仙8 小时前
2026远程办公软件夏季深度横测:ToDesk、向日葵、网易UU远程全面对比,远控白皮书
android·服务器·网络协议·tcp/ip·postgresql
coding_fei9 小时前
AudioServer初始化过程
android