1. 前置条件
- Android Studio:确保使用最新版本(2023.3.1+)
- 目标 API:最低 API 21,兼容 Android 8.0(渠道)和 13+(权限)
- 依赖库:使用
WorkManager
和NotificationCompat
2. 完整实现步骤
2.1 添加权限和依赖
AndroidManifest.xml
<!-- 通知权限 -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <!-- Android 13+ 必须 -->
<uses-permission android:name="android.permission.INTERNET" /> <!-- 若需网络请求 -->
<application>
<!-- 添加你的主 Activity -->
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
build.gradle (Module)
dependencies {
// WorkManager 用于后台任务
implementation "androidx.work:work-runtime-ktx:2.7.1"
// 通知兼容库
implementation "androidx.core:core-ktx:1.12.0"
}
2.2 创建通知渠道(Android 8.0+ 必需)
NotificationHelper.kt
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.os.Build
object NotificationHelper {
const val CHANNEL_ID = "dynamic_messages_channel"
const val NOTIFICATION_ID = 101 // 用于更新同一通知
fun createNotificationChannel(context: Context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// 避免重复创建渠道
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (notificationManager.getNotificationChannel(CHANNEL_ID) != null) return
// 配置渠道属性
val name = "动态消息"
val importance = NotificationManager.IMPORTANCE_HIGH
val channel = NotificationChannel(CHANNEL_ID, name, importance).apply {
description = "用于接收实时动态消息的推送"
enableLights(true)
lightColor = android.graphics.Color.RED
}
notificationManager.createNotificationChannel(channel)
}
}
}
2.3 构建动态通知
NotificationUtils.kt
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.example.myapp.R // 替换为你的包名
object NotificationUtils {
fun showDynamicNotification(
context: Context,
title: String,
message: String
) {
// 创建点击跳转逻辑(示例跳转到 MainActivity)
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
)
// 构建通知
val builder = NotificationCompat.Builder(context, NotificationHelper.CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification) // 必须的图标(需在 res/drawable 添加)
.setContentTitle(title)
.setContentText(message)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(pendingIntent)
.setAutoCancel(true) // 点击后自动消失
.setStyle(NotificationCompat.BigTextStyle().bigText(message)) // 长文本支持
// 发送通知
with(NotificationManagerCompat.from(context)) {
if (NotificationManagerCompat.from(context).areNotificationsEnabled()) {
notify(NotificationHelper.NOTIFICATION_ID, builder.build())
}
}
}
// 更新通知(使用相同 ID)
fun updateNotification(context: Context, newTitle: String, newMessage: String) {
val builder = NotificationCompat.Builder(context, NotificationHelper.CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(newTitle)
.setContentText(newMessage)
NotificationManagerCompat.from(context).notify(NotificationHelper.NOTIFICATION_ID, builder.build())
}
}
2.4 后台任务调度(WorkManager)
NotificationWorker.kt
import android.content.Context
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import kotlinx.coroutines.delay
class NotificationWorker(
context: Context,
params: WorkerParameters
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
// 模拟网络请求延迟
delay(3000)
// 获取动态数据(此处为模拟数据,实际需替换为真实逻辑)
val title = "您有新的消息!"
val content = "当前时间:${System.currentTimeMillis()}"
// 显示通知
NotificationUtils.showDynamicNotification(applicationContext, title, content)
return Result.success()
}
}
调度任务(在 MainActivity 中)
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import java.util.concurrent.TimeUnit
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 初始化通知渠道
NotificationHelper.createNotificationChannel(this)
// 请求通知权限(Android 13+)
requestNotificationPermission()
// 启动周期性后台任务(每15分钟一次)
val workRequest = PeriodicWorkRequestBuilder<NotificationWorker>(
15, TimeUnit.MINUTES // 注意:最短间隔为15分钟
).build()
WorkManager.getInstance(this).enqueue(workRequest)
}
private fun requestNotificationPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (checkSelfPermission(android.Manifest.permission.POST_NOTIFICATIONS) !=
PackageManager.PERMISSION_GRANTED
) {
requestPermissions(
arrayOf(android.Manifest.permission.POST_NOTIFICATIONS),
REQUEST_CODE_NOTIFICATION
)
}
}
}
companion object {
private const val REQUEST_CODE_NOTIFICATION = 1001
}
}
2.5 处理权限请求结果
在 MainActivity
中重写 onRequestPermissionsResult
:
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
REQUEST_CODE_NOTIFICATION -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 用户已授权
} else {
// 处理拒绝逻辑(例如显示提示)
}
}
}
}
3. 扩展优化建议
3.1 结合网络请求
使用 Retrofit + Kotlin Coroutines
获取真实数据:
// 在 NotificationWorker 中替换模拟数据
val response = apiService.fetchMessages()
if (response.isSuccessful) {
val message = response.body()?.latestMessage
message?.let {
NotificationUtils.showDynamicNotification(context, it.title, it.content)
}
}
3.2 通知分组(Android 7.0+)
val builder = NotificationCompat.Builder(...)
.setGroup("messages_group")
.setGroupSummary(true) // 分组摘要
3.3 通知操作按钮
// 添加“标记已读”操作
val readIntent = Intent(context, MarkReadReceiver::class.java)
val readPendingIntent = PendingIntent.getBroadcast(...)
builder.addAction(
NotificationCompat.Action.Builder(
R.drawable.ic_check,
"标记已读",
readPendingIntent
).build()
)
4. 常见问题解决
通知不显示
- 检查是否在 Android 13+ 设备上授予了权限
- 确保通知渠道已正确创建
- 验证
setSmallIcon
使用了有效的资源 ID
后台任务不触发
- 确保 WorkManager 依赖已添加
- 检查设备是否处于 Doze 模式(测试时可暂时禁用)
通知点击无响应
- 确认
PendingIntent
的FLAG_IMMUTABLE
正确使用 - 检查目标 Activity 是否在 Manifest 中注册
- 确认
可进一步结合 Firebase Cloud Messaging (FCM) 实现服务端消息推送,或添加更复杂的交互逻辑。