发现把Android通知渠道的重要性设置为最高时,当发送通知时,通知能直接弹出来显示,以前一直搞不明白为什么别的app的通知可以弹出来,我的不行,搞了半天原来是这个属性在作怪,示例如下:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
registerForActivityResult(ActivityResultContracts.RequestPermission()) {
}.launch(Manifest.permission.POST_NOTIFICATIONS)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val importance = NotificationManager.IMPORTANCE_HIGH
val channel = NotificationChannel("channel_id", "MyChannel", importance)
channel.description = "This is my notification channel"
NotificationManagerCompat.from(this).createNotificationChannel(channel)
}
val builder = NotificationCompat.Builder(this, "channel_id")
.setSmallIcon(R.drawable.icon)
.setContentTitle("这是通知标题")
.setContentText("这是通知内容")
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED) {
NotificationManagerCompat.from(this).notify(1, builder.build())
}
}
}
最主要的是使用了NotificationManager.IMPORTANCE_HIGH
常量,其它的随便怎么设置都不重要。运行效果如下:
如果手机有这个设置需要打开,如下:
这个选项默认是打开的。如果是关的话通知就不会弹出来。点击通知渠道名称还有一个 “允许打扰” 的选项,如下:
这个开关默认是关的,但是通知还是能弹出来,而且也有通知声音,振动没试过。在一台不知名的手机上,我试了设置免打扰模式,通知还是能弹出来,只是通知的声音没有了,打开 “允许打扰” 就可以听到通知声音了,这台手机是Android 11版本,可能做的不太规范。
在我的小米手机11pro(Android 13)上,通知设置的主页是这样的:
这个开关默认也是开的,点击通道名称(MyChannel)之后也有一个一样的权限,默认也是开的,如下:
当我把主页上的 “悬浮通知权限” 关闭后,通道里的这个开关就不见了,所以,通知主页上的所有开关都是app通知的总开关,对所有频道都生效,所以如果有多个通道频道的话可以针对不同的频道单独设置是否可以弹出通知,比如有一个Linphone应用,我查看它的通知是创建了4个频道的,如下:
- Linphone 来电通知:用于显示来电。通过自定义通知的UI,可以在通知上显示接收听电话按钮。如果是平时我们自己做的话估计会使用Dialog来弹窗显示,原来用通知也能实现啊!那如何保持通知弹出来一直显示呢?直到用户点击接听或者挂断按钮。
- Linphone 即时通讯通知:用于显示消息通知
- Linphone 未接来电通知:用于显示未接来电
- Linphone 服务通知:用于在保持应用长期在后台,所以这个服务是以前台服务开启的,这样就必须显示一个常驻消息栏的通知,通知的消息内容为:“若要在后台可接听电话这是必要的”。这个理由很不错,学习了,充分的理由让用户知道这个前台服务的功能,要不然用户可能会关闭掉这个服务(不知道是不是把通知一关服务就关掉了呢?待实验)。
为不同的使用场景创建不同的频道是个比较好的做法,以方便用户有更细的选择,比如,我觉得电话比较重要,我就可以打开 “Linphone 来电通知” 这个渠道中的悬浮窗权限,其它频道的全都关闭。
再来看看微信app的通知渠道:
可以看到,微信app创建了3个通知频道,一个用于接收新消息,一个用于下载,一个用于音视频通话,在微信app中,我们可以设置消息免打扰,如果我想把所有的微信群都设置为免打扰,无需在app内部设置,最快捷的办法就是在 “新消息通知” 这个通知频道中设置就可以了,比如把这个频道中的所有开关全部关掉,如下:
“允许通知” 是一个总开关,关掉这个,下面的所有功能都不可用,所以,我们也可以单独设置,比如设置震动,但是不允许声音,如下:
我发现微信的3个频道中,有两个频道的 “悬浮通知权限” 是开的,有一个是关闭的,这是什么API控制的呢?其实就是创建通知频道时的importance
参数控制的,设置为NotificationManager.IMPORTANCE_DEFAULT
它默认就是关的,设置为NotificationManager.IMPORTANCE_HIGH
它默认就会是开的。所有的常量如下:
public static final int IMPORTANCE_NONE = 0;
public static final int IMPORTANCE_MIN = 1;
public static final int IMPORTANCE_LOW = 2;
public static final int IMPORTANCE_DEFAULT = 3;
public static final int IMPORTANCE_HIGH = 4;
public static final int IMPORTANCE_MAX = 5;
可以看到,DEFAULT 跟 HIGH 就差一个级别。MAX 目前是不可用的,我在代码中使用时IDE直接报错,它的源码注释为:Unused. 使用 MIN 和 LOW 又会有什么不同呢?待实验。
在观看Linphone的源代码时,发现它在发送通知时会先判断一下importance,通过通知频道的ID可以再次获取importance属性,代码如下:
val importance = notificationManager.getNotificationChannel(channelId)
?.importance ?: NotificationManagerCompat.IMPORTANCE_NONE
通过判断 importance
是 IMPORTANCE_NONE
则认为用户关闭了该通知频道。然后我看到,它设置的前台服务的通知频道使用IMPORTANCE_LOW
,来电话时,它默认是使用这个对应的频道来发送通知的,然后判断如果这个频道被用户关闭了的话再用来电通知的那个频道来发消息,而且有提到,如果用户关闭了服务通知频道,然后再打开的话,则这个频道原先是IMPORTANCE_LOW
,这样操作后就不是IMPORTANCE_LOW
了,这也是一个细节点。我奇怪的是这个频道使用IMPORTANCE_LOW
的话,它是如何让通知弹出来的,而且这个通知会一直显示,直到用户按接听或挂断按钮,通知对象中有个方法:setCategory(NotificationCompat.CATEGORY_CALL)
,不知道是否跟这个有关,有时间再去研究了。这个Linphone的关于通知的源码值得好好去研究,它还有兼容性处理,针对不同的版本有不同的处理。
因为低版本是没有通知频道说法的,所以可以想到在通知渠道的一些方法,比如设置通知声音、通知灯颜色、通知振动等的一些方法在NotificationCompat.Builder中也会有。
有时间真的可以好好研究Linphone的源码,人家还是用Kotlin写的,好多东西值得学习。