一文了解 Android 通知

640 阅读5分钟

通知是指 Android 在应用界面之外显示的消息,目的是向用户提供提醒、来自他人的通信信息或应用中的其他实时信息。

显示通知

  • 通知权限

应用通知是一个运行时权限,需要用户主动赋予。首先,你需要在 AndroidManifest.xml 文件中声明权限,代码如下所示:

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

然后再动态申请权限,代码示例如下:

private const val REQUEST_CODE_POST_NOTIFICATIONS_PERMISSION = "android.permission.POST_NOTIFICATIONS"


// 检查是否有通知栏权限
if (ContextCompat.checkSelfPermission(context, REQUEST_CODE_POST_NOTIFICATIONS_PERMISSION) == PackageManager.PERMISSION_GRANTED) {
    handleConnectMessage(context, messageContent)
} else {
    requestNotificationPermission(context)
}

private fun requestNotificationPermission(context: Context) {
    ActivityCompat.requestPermissions(
            activity,
            arrayOf(REQUEST_CODE_POST_NOTIFICATIONS_PERMISSION),
            REQUEST_CODE_POST_NOTIFICATIONS_PERMISSION_CODE
        )
}
  • 显示通知

显示通知的代码如下:

private const val CHANNEL_ID = "notification_channel"
private const val CHANNEL_NAME = "消息通知"

val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// 从 Android 8.0(API 级别 26)开始,我们需要创建通知渠道
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    // 设置渠道的名字、id和优先级
    val channel = NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH)
    // 设置是否可以震动
    channel.enableVibration(true) 
    // 创建渠道
    notificationManager.createNotificationChannel(channel)
}

// 创建通知
val notification = NotificationCompat.Builder(context, CHANNEL_ID)
    .setSmallIcon(R.drawable.logo) // 设置通知的 logo,这是必填的,如果没有会crash
    .setPriority(NotificationCompat.PRIORITY_MAX) // 设置通知优先级
    .setContentTitle("通知标题")
    .setContentText("通知内容")
    .setAutoCancel(true) // 设置点击自动取消
    .setVibrate(longArrayOf(100, 200, 300, 400, 500)) // 设置震动的参数
    .build()

// 显示通知
notificationManager.notify(notificationId, notification)
  • 通知的优先级

在上面的代码示例中,我们设置了两次通知的优先级。它们的区别是:在 Android 7.1(API 级别 25)及更低版本上,通知的优先级由 priority 决定。而在 Android 8.0(API 级别 26)及更高版本的设备上,通知的优先级由渠道的 importance 决定。

通知优先级会影响通知的行为,其相关通知行为如下所示:

  • 紧急:发出提示音,并以提醒式通知的形式显示。
  • 高:发出提示音。
  • 中:不发出提示音。
  • 低:不发出提示音,且不会在状态栏中显示。

需要注意,NotificationManager.IMPORTANCE_MAX 是无效的。通知渠道的最大优先级是 NotificationManager.IMPORTANCE_HIGH

通知的种类

  • 普通通知
NotificationCompat.Builder(context, CHANNEL_ID)
    .setSmallIcon(R.drawable.logo) // 设置通知的 logo,这是必填的,如果没有会crash
    .setPriority(NotificationCompat.PRIORITY_MAX) // 设置通知优先级
    .setContentTitle("通知标题")
    .setContentText("通知内容")
    .setAutoCancel(true) // 设置点击自动取消
    .setVibrate(longArrayOf(100, 200, 300, 400, 500)) // 设置震动的参数
    .build()
  • 大文本通知
val content = "大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知大文本通知"

NotificationCompat.Builder(context, CHANNEL_ID)
    .setSmallIcon(R.drawable.logo) // 设置通知的 logo,这是必填的,如果没有会crash
    .setPriority(NotificationCompat.PRIORITY_MAX) // 设置通知优先级
    .setContentTitle("通知标题")
    .setContentText("通知内容")
    .setAutoCancel(true) // 设置点击自动取消
    .setVibrate(longArrayOf(100, 200, 300, 400, 500)) // 设置震动的参数
    .setStyle(NotificationCompat.BigTextStyle().bigText(content)) // 设置大文本内容
    .build()

需要注意,一些设备比如 miui 会有自己的通知样式,需要设置成原生的样式。

0502001baaa811704ed5d4de6623a76.jpg

还有通知相关的权限,比如说悬浮通知、锁屏通知等。如果没有效果,可以看看是否有对应的权限

d88d24938e33b6dc12bf5a1adc3894d.jpg

  • 大图通知
val bigPicture = BitmapFactory.decodeResource(context.resources, R.drawable.big_picture)

NotificationCompat.Builder(context, CHANNEL_ID)
    .setSmallIcon(R.drawable.logo) // 设置通知的 logo,这是必填的,如果没有会crash
    .setPriority(NotificationCompat.PRIORITY_MAX) // 设置通知优先级
    .setContentTitle("通知标题")
    .setContentText("通知内容")
    .setAutoCancel(true) // 设置点击自动取消
    .setVibrate(longArrayOf(100, 200, 300, 400, 500)) // 设置震动的参数
    .setStyle(NotificationCompat.BigPictureStyle().bigPicture(bigPicture)) // 设置大图的内容
    .build()
  • 进度通知
NotificationCompat.Builder(context, CHANNEL_ID)
    .setSmallIcon(R.drawable.logo) // 设置通知的 logo,这是必填的,如果没有会crash
    .setPriority(NotificationCompat.PRIORITY_MAX) // 设置通知优先级
    .setContentTitle("通知标题")
    .setContentText("通知内容")
    .setAutoCancel(true) // 设置点击自动取消
    .setVibrate(longArrayOf(100, 200, 300, 400, 500)) // 设置震动的参数
    .setProgress(100, process, false)
    .build()
  • 对话通知
val avatar = BitmapFactory.decodeResource(context.resources, R.drawable.avatar)
val user = Person.Builder()
    .setIcon(IconCompat.createWithBitmap(avatar))
    .setName("用户A")
    .build()
val user1 = Person.Builder()
    .setIcon(IconCompat.createWithBitmap(avatar))
    .setName("用户B")
    .build()
val messagingStyle = NotificationCompat.MessagingStyle(user)
    .setConversationTitle(notificationMessage.title)
    .addMessage(notificationMessage.content, System.currentTimeMillis(), user)
    .addMessage("回复内容", System.currentTimeMillis(), user1)
NotificationCompat.Builder(context, CHANNEL_ID)
    .setSmallIcon(R.drawable.logo) // 设置通知的 logo,这是必填的,如果没有会crash
    .setPriority(NotificationCompat.PRIORITY_MAX) // 设置通知优先级
    .setContentTitle("通知标题")
    .setContentText("通知内容")
    .setAutoCancel(true) // 设置点击自动取消
    .setVibrate(longArrayOf(100, 200, 300, 400, 500)) // 设置震动的参数
    .setStyle(messagingStyle)
    .build()

通知的动作

如果你需要实现点击通知时,会跳转到指定界面的效果,需要使用 PendingIntent。PendingIntent 代表延迟执行的 Intent,这里的作用是点击通知后,执行设置的 Intent 的作用。代码示例如下:

val intent = Intent(context, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)

// 创建通知
NotificationCompat.Builder(context, CHANNEL_ID)
    .setSmallIcon(R.drawable.logo) // 设置通知的 logo,这是必填的,如果没有会crash
    .setPriority(NotificationCompat.PRIORITY_MAX) // 设置通知优先级
    .setContentTitle("通知标题")
    .setContentText("通知内容")
    .setAutoCancel(true) // 设置点击自动取消
    .setVibrate(longArrayOf(100, 200, 300, 400, 500)) // 设置震动的参数
    .setContentIntent(pendingIntent) // 设置 PendingIntent
    .build()

参考