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) 实现服务端消息推送,或添加更复杂的交互逻辑。

相关推荐
祖国的好青年11 小时前
VS Code 搭建 React Native 开发环境(Windows 实战指南)
android·windows·react native·react.js
黄林晴11 小时前
警惕!AGP 9.2 别只改版本号,R8 规则与构建链路全线收紧
android·gradle
小米渣的逆袭11 小时前
Android ADB 完全使用指南
android·adb
儿歌八万首12 小时前
Jetpack Compose Canvas 进阶:结合 animateFloatAsState 让自定义图形动起来
android·动画·compose
zhangphil12 小时前
Android Page 3 Flow读sql数据库媒体文件,Kotlin
android·kotlin
神探小白牙13 小时前
echarts,3d堆叠图
android·3d·echarts
李白的天不白13 小时前
如何项目发布到github上
android·vue.js
summerkissyou198713 小时前
Android-RTC、NTP 和 System Time(系统时间)
android
小书房13 小时前
Kotlin使用体验及理解1
android·开发语言·kotlin
撩得Android一次心动14 小时前
Android Navigation 组件全面讲解
android·jetpack·navigation