一、版本变更
使用 NotificationCompat 来确保各版本API和体验统一。
Android 5 targetSdkVersion ≥ 21 | 图标颜色。 |
Android 8 targetSdkVersion ≥ 26 | 渠道通知。 桌面图标角标(默认开启)。 |
Android 13 | 运行时权限。 |
二 、通知图标(Android 5)
第三方魔改ROM不会遵守,例如MIUI直接使用APP的icon。通知栏图标应该只使用alpha图层来进行绘制(图标不要带颜色,只存在透明度)而不应该包括RGB图层(ARGB只有A)。否则状态栏的图标是个白圈,下拉后通知栏图标右下角也是白圈。
//通知栏的图标无法改色,状态栏大图右下角的图标可以
builder.setColor(Color.parseColor("#EAA935"))
三、渠道通知、桌面图标角标(Android 8)
- 为了对私信、广告、订阅...进行区分,用户可以选择性对分类进行关闭或更改重要程度,避免消息过多导致用户反感全部屏蔽或者卸载。
- 桌面图标角标只有一个点,长按才显示数字。
渠道的重要性用户可以随时在系统设置中手动变更,APP无法后期修改。 | 通知栏显示效果 | 锁屏 | 提示音 | 横幅 |
IMPORTANCE_MAX | 展开 | 有 | 有 | 有 |
IMPORTANCE_HIGH | 展开 | 有 | 有 | 有 |
IMPORTANCE_DEFAULT | 展开 | 有 | 有 | - |
IMPORTANCE_LOW | 展开 | 有 | - | - |
IMPORTANCE_MIN | 折叠 | - | - | - |
IMPORTANCE_NONE | - | - | - | - |
3.2.1 创建
不做版本判断会崩溃。Channel会覆盖Builder中相同的配置(做版本适配的话那就都要写)。
private val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager //获取通知管理器
private val channelId = "渠道ID" //唯一值
private val notificationId = 123456 //唯一值
//构建通知
val notification = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
createNotificationChannel(notificationManager, channelId) //创建通知渠道
NotificationCompat.Builder(this, channelId) //8开始通知必须分配渠道
} else {
NotificationCompat.Builder(this)
}.setContentTitle("通知标题")
.setContentText("通知内容")
//设置图标角标显示数字(未读消息数)
.setNumber(2)
//状态栏显示的小图标
.setSmallIcon(R.drawable.ic_launcher_foreground)
//通知栏显示的大图标
.setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.ic_launcher_foreground))
//点击通知后的跳转
//Intent一般new出来就开启,而PendingIntent不一定会开启,需要满足某些条件(getActivity()打开一个界面,getService()开起一个服务,getBroadcast()发送一个广播)。
.setContentIntent(PendingIntent.getActivity(this, 1, Intent(), PendingIntent.FLAG_IMMUTABLE))
//点击通知后是否清除该通知
.setAutoCancel(true)
//提醒方式
.setDefaults(NotificationCompat.DEFAULT_ALL)
//提示音
.setSound(Uri.fromFile(File("/system/media/audio/ringtones/Luna.ogg")))
//震动效果
.setVibrate(longArrayOf(0, 1000, 1000, 1000)) //索引单数为静止时长,双数为震动时长
//呼吸灯效果
.setLights(Color.GREEN,1000,1000) //颜色,亮起时长,熄灭时长
//通知栏显示长文本内容
.setStyle(NotificationCompat.BigTextStyle().bigText("长文本通知内容"))
//通知栏显示大图片
.setStyle(NotificationCompat.BigPictureStyle().bigPicture(BitmapFactory.decodeResource(resources, R.drawable.ic_launcher_foreground)))
//优先级(max>high>default>low>min)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.build()
// notification.flags = NotificationCompat.FLAG_AUTO_CANCEL //点击通知后清除该通知
// notification.flags = NotificationCompat.FLAG_NO_CLEAR //不允许清除该通知(常驻)
//使用
notificationManager.notify(notificationId, notification) //开启通知
//notificationManager.cancel(notificationId) //取消通知(也可以取消常驻)
//构建渠道
@TargetApi(Build.VERSION_CODES.O)
fun createNotificationChannel(notificationManager: NotificationManager, channelId: String){
if (notificationManager.getNotificationChannel(channelId) == null){ //不存在该渠道才创建
val channelName = "渠道名称" //系统设置中用户看的
val importance = NotificationManager.IMPORTANCE_DEFAULT //优先级, max>high>default>low>min
val channel = NotificationChannel(channelId, channelName, importance).apply {
//Channel会覆盖Builder中相同的配置。
description = "渠道描述" //系统设置中用户看的
lightColor = Color.GREEN //呼吸灯颜色
enableLights(true) //启用呼吸灯闪烁
vibrationPattern = longArrayOf(0, 1000, 0, 1000) //索引单数为静止时长,双数为震动时长
enableVibration(true) //启用震动
setShowBadge(true) //启用桌面图标角标(默认开启)
lockscreenVisibility = NotificationCompat.VISIBILITY_PUBLIC //锁屏显示:public显示标题+内容,private只显示标题,secret不显示
}
notificationManager.createNotificationChannel(channel) //注册到系统中
}
}
3.2.2 管理
由于APP无法后期修改渠道的重要性,像用户关闭了微信通知无法接收消息推送,可以通过判断后跳转到设置界面引导用户开启。
//在发送通知的地方调用
@TargetApi(Build.VERSION_CODES.O)
fun checkIfTurnedOff(notificationManager: NotificationManager, channelId: String) {
val channel = notificationManager.getNotificationChannel(channelId)
if (channel.importance == NotificationManager.IMPORTANCE_NONE) {
Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS).let {
it.putExtra(Settings.EXTRA_APP_PACKAGE, packageName)
it.putExtra(Settings.EXTRA_CHANNEL_ID, channel.id)
startActivity(it)
}
Toast.makeText(this, "请手动将通知打开", Toast.LENGTH_SHORT).show()
}
}
3.2.3 删除
虽然能删除,为了防止恶意APP随意创建删除(你屏蔽我这个渠道我就删了再创建),在该APP的系统通知管理界面会显示被删除渠道的数量。
四、运行时权限(Android 13)
13之前系统默认APP有通知权限可以随时发,13之后发的时候需要申请,也不能像之前那样检测被关闭后跳转引导开启。分别适配很繁琐,这里使用PermissionX。
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
add(Manifest.permission.POST_NOTIFICATIONS)
}
//或者使用这个就不用手动判断了
add(PermissionX.permission.POST_NOTIFICATIONS)