Android 中使用通知(Kotlin 版)

1. 前置条件

  • Android Studio:确保使用最新版本(2023.3.1+)
  • 目标 API:最低 API 21,兼容 Android 8.0(渠道)和 13+(权限)
  • 依赖库 :使用 WorkManagerNotificationCompat

2. 完整实现步骤

2.1 添加权限和依赖

AndroidManifest.xml
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)
groovy 复制代码
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
kotlin 复制代码
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
kotlin 复制代码
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
kotlin 复制代码
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 中)
kotlin 复制代码
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

kotlin 复制代码
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 获取真实数据:

kotlin 复制代码
// 在 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+)

kotlin 复制代码
val builder = NotificationCompat.Builder(...)
    .setGroup("messages_group")
    .setGroupSummary(true) // 分组摘要

3.3 通知操作按钮

kotlin 复制代码
// 添加"标记已读"操作
val readIntent = Intent(context, MarkReadReceiver::class.java)
val readPendingIntent = PendingIntent.getBroadcast(...)
builder.addAction(
    NotificationCompat.Action.Builder(
        R.drawable.ic_check,
        "标记已读",
        readPendingIntent
    ).build()
)

4. 常见问题解决

  1. 通知不显示

    • 检查是否在 Android 13+ 设备上授予了权限
    • 确保通知渠道已正确创建
    • 验证 setSmallIcon 使用了有效的资源 ID
  2. 后台任务不触发

    • 确保 WorkManager 依赖已添加
    • 检查设备是否处于 Doze 模式(测试时可暂时禁用)
  3. 通知点击无响应

    • 确认 PendingIntentFLAG_IMMUTABLE 正确使用
    • 检查目标 Activity 是否在 Manifest 中注册

可进一步结合 Firebase Cloud Messaging (FCM) 实现服务端消息推送,或添加更复杂的交互逻辑。

相关推荐
千里马-horse1 小时前
android vlc播放rtsp
android·media·rtsp·mediaplayer·vlc
難釋懷1 小时前
Android开发-文本输入
android·gitee
志存高远663 小时前
(面试)Android各版本新特性
android
IT从业者张某某3 小时前
信奥赛-刷题笔记-队列篇-T3-P3662Why Did the Cow Cross the Road II S
android·笔记
未来之窗软件服务3 小时前
Cacti 未经身份验证SQL注入漏洞
android·数据库·sql·服务器安全
BXCQ_xuan3 小时前
handsome主题美化及优化:10.1.0最新版 - 2
android
圈圈编码4 小时前
MVVM框架
android·学习·kotlin
橙子199110166 小时前
在 Kotlin 中,什么是解构,如何使用?
android·开发语言·kotlin
Digitally8 小时前
如何从 Android 设备打印短信(5 种方法)
android