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

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

相关推荐
千里马学框架4 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台4 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone4 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc4 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo4 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077004 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
ai2work4 天前
ch23 综合复刻:从零做一个最小可用版本(capstone)
kotlin
其实防守也摸鱼4 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
ai2work4 天前
ch21 签名、校验与发版
kotlin
AFinalStone4 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui