targetVersion为Android 8.0及以上的版本,需要创建通知的渠道(channel),否则就不会显示通知。(注:渠道的创建不会影响低版本,低版本会忽略渠道)
private fun createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val name = getString(R.string.channel_name)
val descriptionText = getString(R.string.channel_description)
val importance = NotificationManager.IMPORTANCE_DEFAULT
val channel = NotificationChannel(CHANNEL_ID, name, importance).apply {
description = descriptionText
}
// Register the channel with the system
val notificationManager: NotificationManager =
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
}
在每次发送通知之前及在应用的Application的onCreate方法中调用上述方法。
有些同学可能会疑惑,每次都发通知都重新创建一次,会不会产生问题?
不会。官方文档里面已经明确的告诉了我们:creating an existing notification channel performs no operation。当然,你也可以声明一个boolean值,用于控制当已创建渠道,不再执行上述创建代码。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !isCreateApkDownloadChannel){
......
}
当然仅仅是调用上述方法还是不行的,通知的创建代码也需要修改一下:
val mBuilder = NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("My notification")
.setContentText("Hello World!")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
// Set the intent that will fire when the user taps the notification
.setContentIntent(pendingIntent)
.setAutoCancel(true)
可以看到,通知的创建主要变化的点是需要多传入一个ChannelId,这个ChannelId的值需要和创建渠道时传入的值保持一直,这样相同channelId的通知才会被归为一类。
效果(以头条App为例):
优先级的适配包含了高版本(8.0及以上)和低版本(7.0及以下),每个通知都有不同的优先级,优先级的高低与声音及展示方式密切相关。如下图:
为了适配全版本,我们必须为8.0及以上 && 7.0及以下,各自设置优先级。上述创建channel及notification的代码已经包含了如何设置各自优先级的地方了,此处就不再重复贴代码。即:渠道中的优先级 - 针对8.0及以上,创建通知 - setPriority - 针对的是7.0及以下版本。
具体设置成什么优先级取决于自己的业务需求。比如:普通通知和下载Apk进度通知。这两个通知的优先级肯定不能一样,因为你肯定不想自己的用户在下载Apk的时候,一直发出滴滴滴滴的声音,那样用户可能会手滑卸载你的App了。因此,可以为不同的类型的通知创建不同的渠道,进而设置不同的优先级。
比如vivo x20手机,默认情况下,新安装的App的“允许通知”选项被关闭了。这时候你的app发送的任何通知,用户手机都是收不到的。由于系统提供了相关的api可以检测到是否开启,因此做法还是比较简单的,检测&提示给用户即可。
public static boolean areNotificationsEnabled(Context context) {
return context == null || NotificationManagerCompat.from(context).areNotificationsEnabled();
}
如果上述函数返回false,提示用户开启,并在用户点击设置时跳转到app设置页面。
这个也是vivo手机的一个坑。如果你的app处于后台,且此时你需要如标题所述的场景,那么是无法调起的。为什么?vivo也是默认禁止了app“后台弹出界面”。目前,我还没发现相关的系统的api可以解决这个问题。麻烦看到的同学,知道的留言一下。如下是我们的解决方案:
虽然被禁止了“后台弹出界面”,但是还是会走调起activity的代码(launchApp),只是走完代码没任何毛效果而已。可以在这段调起的代码中设置一个计时器 && 一个布尔值(布尔值本地SP缓存一下),当指定的时间内成功跳转至调起页,则设置布尔值为true。如果指定的时间内,布尔值仍然为false,则说明用户手机禁止了“后台弹出界面”。
在用户下一次打开App的时候,提示用户。(目前只提示一次,因为不知道用户在app的设置页面有没有打开“后台弹出界面”开关)。