本文将详细介绍如何在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)
}
}
四、最佳实践与优化建议
-
通知分组:
kotlin.setGroup("messages_group") .setGroupSummary(true)
-
大图标和样式:
kotlin.setLargeIcon(bitmap) .setStyle(NotificationCompat.BigTextStyle().bigText(longText))
-
通知重要性分级:
- IMPORTANCE_MIN:只在通知栏显示,无声音或提示
- IMPORTANCE_LOW:显示并可能发出声音
- IMPORTANCE_DEFAULT:显示并发出声音
- IMPORTANCE_HIGH:显示为弹出式通知
-
适配不同厂商:
kotlin// 针对小米设备 if (Build.MANUFACTURER.equals("xiaomi", ignoreCase = true)) { builder.setPriority(NotificationCompat.PRIORITY_MAX) }
-
测试建议:
- 测试不同Android版本的表现
- 测试应用处于前台和后台时的行为
- 测试设备锁定状态下的显示
五、常见问题解决方案
-
通知不显示:
- 检查Android 13+的通知权限
- 验证通知渠道重要性设置
- 确保提供了有效的小图标
-
动作按钮不工作:
- 检查PendingIntent的flag设置
- 验证广播接收器是否正确注册
- 确保没有重复使用相同的requestCode
-
内联回复问题:
- 使用FLAG_MUTABLE创建PendingIntent
- 确保RemoteInput的key与处理时一致
- 为Android 12+添加适当的PendingIntent flag
通过本文介绍的方法,您可以实现从基础到高级的各种通知功能,为用户提供丰富的交互体验。记得根据您的应用具体需求进行调整和优化。