首页 / Android 入门教程 / 通知系统

Android 入门教程

通知系统

本教程共 100 篇 · 第 84 篇 · 更新于 2026-07-28 · 约 8 分钟阅读

AndroidAndroid 入门教程通知NotificationNotificationChannelAndroidX

84. 通知系统

本节目标:学会创建通知渠道、用 NotificationCompat.Builder 构建基本通知、设置点击跳转、添加操作按钮,理解 Android 13+ 的通知权限。

通知是应用在不在前台时给用户传递信息的渠道。新消息、闹钟、下载完成,都靠通知。这章讲基础,下一章讲进阶样式。

通知渠道(Channel)

Android 8.0(API 26)起,所有通知必须挂在一个「渠道」上。没有渠道的通知直接不显示。

打个比方,渠道像新闻订阅的分类—「新闻」「体育」「娱乐」各一个分类,用户能单独开关每个分类的通知,单独设铃声、震动。

创建渠道:

private const val CHANNEL_ID = "messages"

fun createChannel(context: Context) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val name = "消息通知"
        val description = "新消息到达时通知"
        val importance = NotificationManager.IMPORTANCE_DEFAULT
        val channel = NotificationChannel(CHANNEL_ID, name, importance).apply {
            this.description = description
        }
        val manager = context.getSystemService(NotificationManager::class.java)
        manager.createNotificationChannel(channel)
    }
}

要点:

  • CHANNEL_ID 是渠道唯一标识,发通知时用。
  • importance 决定打扰程度:MIN(不响)、LOW(小通知)、DEFAULT(响铃)、HIGH(弹出)、MAX(紧急)。
  • 渠道一旦创建,重要性就不能改了(用户能在设置里改)。
  • 应用启动时调用即可,重复创建无害。
Note

多个渠道按用途分:聊天、下载、营销等。用户能精细控制「我不想收到营销通知但保留聊天」。

通知权限(Android 13+)

Android 13(API 33)起,发通知要先申请运行时权限:

<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

请求时机:应用首次需要发通知时。一般是在主 Activity 启动时弹一次,但更推荐「用户主动触发」时弹。

val launcher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
    if (granted) {
        // 可以发通知
    }
}

// 请求
launcher.launch(Manifest.permission.POST_NOTIFICATIONS)
Warning

targetSdk >= 33 但没申请权限,所有通知都不显示。老应用升级时别漏。

构建基本通知

NotificationCompat.Builder

fun sendBasicNotification(context: Context) {
    val builder = NotificationCompat.Builder(context, CHANNEL_ID)
        .setSmallIcon(R.drawable.ic_notification)  // 必填
        .setContentTitle("新消息")
        .setContentText("你有一封来自张三的邮件")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)  // < API 26 用
        .setAutoCancel(true)  // 点击后自动消失

    NotificationManagerCompat.from(context).apply {
        if (ActivityCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS)
            == PackageManager.PERMISSION_GRANTED || Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
            notify(NOTIFICATION_ID, builder.build())
        }
    }
}

要点:

  • setSmallIcon 必填,没这个通知不显示。用单色透明 PNG,系统自动着色。
  • setContentTitle/setContentText 标题和正文。
  • setPriority 是 API 26 以下用的优先级,26 以上看渠道重要性。
  • setAutoCancel(true) 点击后自动消失。
  • notify(id, notification) 发出,id 用来后续更新或取消。

点击跳转

通知默认点击没反应。要让它打开 Activity,设置 PendingIntent

val intent = Intent(context, DetailActivity::class.java).apply {
    flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
    putExtra("message_id", 123)
}

val pendingIntent = PendingIntent.getActivity(
    context,
    0,
    intent,
    PendingIntent.FLAG_IMMUTABLE  // Android 12+ 必须指定
)

val builder = NotificationCompat.Builder(context, CHANNEL_ID)
    .setSmallIcon(R.drawable.ic_notification)
    .setContentTitle("新消息")
    .setContentText("点开查看")
    .setContentIntent(pendingIntent)  // 点击事件
    .setAutoCancel(true)
Warning

Android 12(API 31)起,PendingIntent 必须显式指定 FLAG_IMMUTABLEFLAG_MUTABLE,不写会崩。除非要往 PendingIntent 里塞数据(如直接回复),都用 FLAG_IMMUTABLE

操作按钮

通知能加最多 3 个操作按钮:

val replyIntent = Intent(context, ReplyReceiver::class.java).apply {
    action = "ACTION_REPLY"
    putExtra("message_id", 123)
}
val replyPendingIntent = PendingIntent.getBroadcast(
    context, 0, replyIntent, PendingIntent.FLAG_IMMUTABLE
)

val builder = NotificationCompat.Builder(context, CHANNEL_ID)
    .setSmallIcon(R.drawable.ic_notification)
    .setContentTitle("新消息")
    .setContentText("...")
    .addAction(R.drawable.ic_reply, "回复", replyPendingIntent)
    .addAction(R.drawable.ic_archive, "归档", archivePendingIntent)

addAction 第一个参数是图标,第二个是文字,第三个是 PendingIntent。点击后启动对应的 Intent(一般是 BroadcastReceiver)。

Note

操作按钮不要和点击主通知的动作重复。比如点通知本身打开详情页,按钮就放「回复」「归档」这种快捷操作。

更新通知

发新通知时用同一个 id,会更新原通知:

// 第一次
notify(100, builder.build())

// 更新进度
builder.setContentText("进度 50%")
notify(100, builder.build())

setOnlyAlertOnce(true),只在第一次响,更新时不响。

取消通知

NotificationManagerCompat.from(context).cancel(notificationId)  // 取消指定
NotificationManagerCompat.from(context).cancelAll()  // 取消所有

或者用 setTimeoutAfter(5000),5 秒后自动消失。

通知优先级

API 26 以下用 setPriority

  • PRIORITY_MIN:无打扰,状态栏一行。
  • PRIORITY_LOW:无声音,下拉才看到。
  • PRIORITY_DEFAULT:默认响铃。
  • PRIORITY_HIGH:弹出通知栏。
  • PRIORITY_MAX:全屏弹出。

API 26+ 用渠道重要性:

  • IMPORTANCE_MIN / IMPORTANCE_LOW / IMPORTANCE_DEFAULT / IMPORTANCE_HIGH
Tip

优先级只是建议,系统会根据用户行为调整。比如用户经常忽略某个高优先级通知,系统会降级。

锁屏可见性

控制锁屏时通知显示多少内容:

.setVisibility(NotificationCompat.VISIBILITY_PRIVATE)

三档:

  • VISIBILITY_PUBLIC:完整显示。
  • VISIBILITY_PRIVATE:只显示「应用名 - 1 条通知」。
  • VISIBILITY_SECRET:完全不显示。

VISIBILITY_PRIVATE 还能配一个备用通知:

val publicVersion = NotificationCompat.Builder(context, CHANNEL_ID)
    .setContentTitle("新消息")
    .setContentText("你有一条新消息")
    .build()

builder.setPublicVersion(publicVersion)

前台服务通知

前台服务必须挂通知,告诉用户「应用正在后台做事」:

class MusicService : Service() {
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        val notification = NotificationCompat.Builder(this, "music")
            .setContentTitle("正在播放")
            .setContentText("歌曲名")
            .setSmallIcon(R.drawable.ic_music)
            .build()

        startForeground(NOTIFICATION_ID, notification)
        return START_STICKY
    }
}
Warning

Android 14+ 前台服务要声明 foregroundServiceType(如 mediaPlayback),并申请对应权限。漏一个崩。

Compose 里发通知

Compose 里发通知和传统方式一样,因为通知是系统级的,和 UI 框架无关。在 Composable 里用 LocalContext 拿 Context:

@Composable
fun NotificationButton() {
    val context = LocalContext.current
    Button(onClick = {
        createChannel(context)
        sendBasicNotification(context)
    }) {
        Text("发通知")
    }
}

常见坑

  1. API 26+ 没建渠道:通知不显示。
  2. 小图标用彩色 PNG:状态栏显示一坨,用单色透明图。
  3. PendingIntent 没指定 MUTABLE/IMMUTABLE:Android 12+ 崩。
  4. targetSdk 33+ 没申请通知权限:通知全部不显示。
  5. 同 id 通知被覆盖:以为没发出去,其实是更新了。
  6. 渠道重要性创建后改不了:想升级得新建渠道(旧渠道让用户在设置里禁用)。

小结

通知系统三件套:渠道(API 26+)、Builder、notify。先建渠道,再 Builder 构建通知,最后 NotificationManagerCompat.notify() 发出。点击跳转用 setContentIntent + PendingIntent,操作按钮用 addAction。Android 13+ 要申请 POST_NOTIFICATIONS 权限。

下一章讲通知进阶,看大图、分组、进度这些样式。