随着Google对Notification的不断升级,所以必须考虑适配问题了。
在Android4.1之前(不包括Android4.1)
在高SDK版本中, setLatestEventInfo已被弃用,并且现在九成九Android用户的系统都在4.4以上了,所以这种情况就不需要考虑了。
后来在Android4.1以上(包括4.1)谷歌推出了Notification.Builder(建造者模式)方式创建通知,但这种方式不支持4.1之前的版本
Notification.Builder builder = new Notification.Builder(MainActivity.this);
Google后来推出了NotificationCompat.Builder方式,为各种配置做兼容性处理。
所以Notification.Builder已经被NotificationCompat.Builder替代。
NotificationCompat.Builder builder = new NotificationCompat.Builder(MainActivity.this);
NotificationCompat.Builder的出现是为了
(1)setSmallIcon设置小图标
setSmallIcon必须设置,否则通知不会显示,所以最简单的通知如下
NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
NotificationCompat.Builder builder = new NotificationCompat.Builder(MainActivity.this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {//Android4.1以上
builder.setSmallIcon(R.mipmap.shennvguo1);
}
它只设置了小图,图片效果如下
那么我们给他添加标题和内容
(2)setContentTitle和setContentText
builder.setSmallIcon(R.mipmap.shennvguo1)
.setContentTitle("我是通知的标题")//设置通知标题
.setContentText("我是一个通知");//设置通知内容
效果如下
(3)setContentIntent
当我们尝试点击这个通知的时候发现点击是没有效果的,要想点击的时候让通知消失那么还需要改进下代码
//准备intent
Intent clickIntent = new Intent(this, DemoActivity.class);
PendingIntent clickPI = PendingIntent.getActivity(this, 1, clickIntent, PendingIntent.FLAG_CANCEL_CURRENT);
builder.setSmallIcon(android.R.drawable.stat_sys_download_done)
.setContentTitle("我是通知的标题")//设置通知标题
.setContentText("我是一个通知")//设置通知内容
.setContentIntent(clickPI);// 设置pendingIntent,点击通知时就会用到
setContentIntent(clickPI)就是让通知的点击效果生效,代码的意思是,点击通知时,跳转到另一个Activity。
效果如下:
(4)setAutoCancel
点击通知之后发现通知没有自动消失,这不是我们想要的效果,我们需要的效果是,当点击通知时让通知自动消失
builder.setSmallIcon(android.R.drawable.stat_sys_download_done)
.setContentTitle("我是通知的标题")//设置通知标题
.setContentText("我是一个通知")//设置通知内容
.setContentIntent(clickPI)// 设置pendingIntent,点击通知时就会用到
.setAutoCancel(true);//设为true,点击通知栏移除通知
setAutoCancel(true)可以使点击通知时自动消失。
需要重点注意的是,setAutoCancel需要和setContentIntent一起使用,否则无效。
(5)setDeleteIntent
当我们左滑或者右滑通知时,发现通知会消失,也就是说,如果手机没有经过特殊定制处理的话,一般有两种消失的行为,第一种是点击消失,第二种是滑动消失,有时候,如果有需要可以通过广播监听这两种事件:
NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
//准备intent
Intent clickIntent = new Intent(this, NotificationBroadcastReceiver.class);
clickIntent.setAction("com.xxx.xxx.click");
// 构建 PendingIntent
PendingIntent clickPI = PendingIntent.getBroadcast(this, 1, clickIntent, PendingIntent.FLAG_CANCEL_CURRENT);
//准备intent
Intent cacelIntent = new Intent(this, NotificationBroadcastReceiver.class);
cacelIntent.setAction("com.xxx.xxx.cancel");
// 构建 PendingIntent
PendingIntent cacelPI = PendingIntent.getBroadcast(this, 2, cacelIntent, PendingIntent.FLAG_CANCEL_CURRENT );
builder.setSmallIcon(android.R.drawable.stat_sys_download_done)
.setContentTitle("我是通知的标题")//设置通知标题
.setContentText("我是一个通知")//设置通知内容
.setContentIntent(clickPI)// 设置pendingIntent,点击通知时就会用到
.setAutoCancel(true)//设为true,点击通知栏移除通知
.setDeleteIntent(cacelPI);//设置pendingIntent,左滑右滑通知时就会用到
setDeleteIntent就是设置滑动消失行为的Intent。
public class NotificationBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals("com.xxx.xxx.click")) {
//处理点击事件
System.out.println("click");
}
if (action.equals("com.xxx.xxx.cancel")) {
//处理滑动清除和点击删除事件
System.out.println("cancel");
}
}
}
静态注册
<receiver android:name=".notification.NotificationBroadcastReceiver">
<intent-filter>
<action android:name="com.xxx.xxx.click"/>
<action android:name="com.xxx.xxx.cancel"/>
</intent-filter>
</receiver>
发送广播是PendingIntent处理的,当我们点击通知或者滑动通知,通知消失的时候PendingIntent就会发送广播。
(6)setLargeIcon
setLargeIcon可以设置大图标,如果没有设置大图标,大图标的位置的图片将会是小图标的图片。
小图标:该图需要做成透明背景图
大图标:该图不需要做成透明背景图
PS:个别定制机对通知做了很大的处理,有些厂商对setSmallIcon和setLargeIcon接口做了处理,不管我们代码中设置什么图片,他的通知图标在某定制手机上就是APP默认图标。如果大家遇到这个问题请不要纠结,直接找产商处理。
(7)setNumber
显示在右边的数字
(8)setOngoing
设置是否是正在进行中的通知,默认是false
如果设置成true,左右滑动的时候就不会被删除了,如果想删除可以在之。
(9)setOnlyAlertOnce
设置是否只通知一次,这个效果主要体现在震动、提示音、悬挂通知上。
默认相同ID的Notification可以无限通知,如果有震动、闪灯、提示音和悬挂通知的话可能会不断的打扰用户。
setOnlyAlertOnce的默认值是false,如果设置成true,那么一旦状态栏有ID为n的通知,再次调用notificationManager.notify(n, notification)时,将不会有震动、闪灯、提示音以及悬挂通知的提醒。
悬挂通知
主要体现在5.0以上的手机上,稍后会讲解。
(10)setProgress
为通知设置设置一个进度条
setProgress(int max, int progress, boolean indeterminate)
max:最大值
progress:当前进度
indeterminate:进度是否确定
当进度确定的情况下
setProgress(100, 20, false);
当进度不确定的情况下
setProgress(100, 20, true);
(11)setStyle
为通知设置样式
NotificationCompat的样式主要有以下几点
-
BigPictureStyle
NotificationCompat.BigPictureStyle bigPictureStyle = new NotificationCompat.BigPictureStyle(); bigPictureStyle.setBigContentTitle("一二三四五,上山打老虎!"); bigPictureStyle.setSummaryText("我就是一个标题!"); bigPictureStyle.bigPicture(BitmapFactory.decodeResource(getResources(), R.drawable.che)); //bigPictureStyle.bigLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.che));
setStyle(bigPictureStyle);
-
BigTextStyle
String title = "我是通知的标题"; String conttext = "我是一个通知"; NotificationCompat.BigTextStyle bigTextStyle = new NotificationCompat.BigTextStyle(); bigTextStyle.setBigContentTitle(title); bigTextStyle.setSummaryText(conttext); bigTextStyle.bigText("一二三四五,上山打老虎!");
setStyle(bigTextStyle);
- DecoratedCustomViewStyle
功能是自定义通知布局
RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.activity_main);
.setStyle(new NotificationCompat.DecoratedCustomViewStyle())
.setCustomContentView(remoteViews);//设置悬挂通知和一般通知的布局
setCustomContentView可以用setCustomBigContentView和setCustomHeadsUpContentView替代
.setStyle(new NotificationCompat.DecoratedCustomViewStyle())
.setCustomBigContentView(remoteViews)//设置通知的布局
.setCustomHeadsUpContentView(remoteViews);//设置悬挂通知的布局
效果如下:
通知布局
悬挂通知布局(Android5.0以上显示)
注意:
- 如果使用Notification.Builder
setCustomBigContentView、setCustomHeadsUpContentView和setCustomContentView只能在Android7.0以后可以生效,7.0之前无效。 - 如果使用NotificationCompat.Builder
setCustomBigContentView、setCustomHeadsUpContentView和setCustomContentView在任何版本都有效
- InboxStyle
添加行
NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle();
inboxStyle.addLine("第一行");
inboxStyle.addLine("第二行");
inboxStyle.addLine("第三行");
inboxStyle.addLine("第四行");
inboxStyle.addLine("第五行");
inboxStyle.addLine("第六行");
inboxStyle.addLine("第七行");
inboxStyle.addLine("第八行");
inboxStyle.addLine("第九行");
inboxStyle.setBigContentTitle(title);
inboxStyle.setSummaryText(conttext);
setStyle(inboxStyle);
- MessagingStyle
我们看一下代码写法
在现在高版本的SDK中,MessagingStyle(@NonNull CharSequence userDisplayName)已经过时了,查看其构造方法
/** @deprecated */
@Deprecated
public MessagingStyle(@NonNull CharSequence userDisplayName) {
this.mUser = (new android.support.v4.app.Person.Builder()).setName(userDisplayName).build();
}
public MessagingStyle(@NonNull Person user) {
if (TextUtils.isEmpty(user.getName())) {
throw new IllegalArgumentException("User's name must not be empty.");
} else {
this.mUser = user;
}
}
我们发现剩下没过时的方法已经没有什么研究价值了。
(12)setDefaults
向通知添加声音、闪灯和震动效果,最简单、最一致的方式是使用当前的用户默认设置,使用defaults属性,可以组合Notification.DEFAULT_ALL、Notification.DEFAULT_SOUND添加声音。
setDefaults(Notification.DEFAULT_ALL);
其中参数属性分别为:
Notification.DEFAULT_VISIBLE //添加默认震动提醒 需要VIBRATE permission
Notification.DEFAULT_SOUND //添加默认声音提醒
Notification.DEFAULT_LIGHTS //添加默认三色灯提醒
Notification.DEFAULT_ALL //添加默认以上三种全部提醒
(13)setVibrate
设置使用震动模式
setVibrate(new long[] {3000,1000,500,700,500,300})//延迟3秒,然后震动1000ms,再延迟500ms,接着震动700ms,最后再延迟500ms,接着震动300ms。
如果setDefaults的属性设置的是Notification.DEFAULT_ALL或者Notification.DEFAULT_VISIBLE,setVibrate将无效,因为Notification.DEFAULT_ALL或者Notification.DEFAULT_VISIBLE会替代setVibrate。
如果想自定义震动模式,有想有闪灯和提示音,那么可以这样做
.setVibrate(new long[] {3000,1000,500,700,500,300})//延迟3秒,然后震动1000ms,再延迟500ms,接着震动700ms,最后再延迟500ms,接着震动300ms。
.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_LIGHTS);
(14)setSubText
在通知上新增一行文本,使原本两行文本变成三行文本
setSubText("我是一个SubText");
(16)setTicker
设置通知在第一次到达时在状态栏中显示的文本
效果如下:
需要注意的是:一些手机是显示不了的,查了些资料都说5.0以上的手机显示不了,但是我手上的测试机系统是5.0.2的,setTicker是可以生效的。
(17)setUsesChronometer
设置是否显示时间计时,电话通知就会使用到。
(18)setWhen
通知产生的时间,会在通知栏信息里显示,一般是系统获取到的时间
setWhen(System.currentTimeMillis());
如果没有设置也没有影响,通知默认是当前时间戳。
当然,我们可以设置自己的时间,比如:
setWhen(System.currentTimeMillis() - 100);
这样通知的时间就会变化了,非当前时间。
主要需要注意的是:
setWhen只是为通知设置时间戳,和是否显示时间没有任何关系,设置是否显示时间的方法是setShowWhen。
(19)setShowWhen
设置是否显示当前时间
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {//Android4.2以上
builder.setShowWhen(true);
}
setShowWhen只有在Android4.2以上的手机上才能生效,另外当已经设置了setUsesChronometer(true),则当前时间就显示不了(除非定制手机处理),默认情况下时间计时和时间戳的显示是在通知的同一区域。
(20)setExtras
为通知设置数据,在Android4.4新增了设置数据的入口。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {//Android4.4以上
Bundle bundle = new Bundle();
builder.setExtras(bundle);
}
(21)setGroup
设置该通知组的密钥,即确认为哪一组。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {//Android4.4W以上
if(index>=0 && index<=10){
builder.setGroup("notification_test");//捆绑通知
}else if(index>10 && index<=15){
builder.setGroup("notification_ceshi");//捆绑通知
}
}
这个主要体现在Android7.0以上的手机上的捆绑通知
或者折叠通知
。文章后面有讲解。
(22)setGroupSummary
设置是否为一组通知的第一个显示,默认是false。
setGroup和setGroupSummary结合可以实现捆绑通知
或者折叠通知
,代码如下:
if(index == 1){
builder.setGroupSummary(true);//设置是否为一组通知的第一个显示
}
builder.setGroup("notification_test");//捆绑通知
目前只有在7.0以上的手机上才能看出效果
下面说明一下我针对setGroupSummary和setGroup的测试结果:
-
如果setGroupSummary和setGroup都不设置,Android7.0以上的时候会自动分组
其中第一个通知也能看到。
-
如果只设置setGroup,但是不设置setGroupSummary的情况。
builder.setGroup("notification_test");//捆绑通知
如果每个通知都设置了setGroupSummary(true),这样每个通知都作为主通知了,毫无意义。
-
如果指定第一条通知为主通知
if(index == 1){ builder.setGroupSummary(true);//设置是否为一组通知的第一个显示 } builder.setGroup("notification_test");//捆绑通知
那么,效果如下:
我们看到第一条通知的文本已经看不到了,因为第一条通知已经作为主通知了。
(23)setLocalOnly
设置此通知是否仅与当前设备相关。如果设置为true,通知就不能桥接到其他设备上进行远程显示。
(24)setSortKey
设置针对一个包内的通知进行排序的键值,键值是一个字符串,通知会按照键值的顺序排列。
排序的效果看下图
NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
NotificationCompat.Builder builder = new NotificationCompat.Builder(MainActivity.this);
builder.setSmallIcon(R.mipmap.shennvguo1);
(25)setColor
设置通知栏颜色(Android5.0新增)
builder.setColor(Color.RED);
目前测试大多测试机没有效果,我的Android8.0的Oppo手机的效果如下:
图片的效果可以看出,应用名称以及进度条都变成红色了,目前因为定制机的影响,setColor作用不是很大了。建议还是不要设置颜色值为好。
之后,在Android8.0之后,新增了setColorized方法,官方的解释是:启用通知的背景颜色设置,目前不清楚它的作用。
注意:
- 如果使用Notification.Builder
setColor只有在Android5.0之后有效。
- 如果使用NotificationCompat.Builder
setColor在任何版本都有效,无需做兼容处理。
(26)setCategory
设置通知类别
通知类别有
public static final String CATEGORY_CALL = "call";
public static final String CATEGORY_MESSAGE = "msg";
public static final String CATEGORY_EMAIL = "email";
public static final String CATEGORY_EVENT = "event";
public static final String CATEGORY_PROMO = "promo";
public static final String CATEGORY_ALARM = "alarm";
public static final String CATEGORY_PROGRESS = "progress";
public static final String CATEGORY_SOCIAL = "social";
public static final String CATEGORY_ERROR = "err";
public static final String CATEGORY_TRANSPORT = "transport";
public static final String CATEGORY_SYSTEM = "sys";
public static final String CATEGORY_SERVICE = "service";
public static final String CATEGORY_REMINDER = "reminder";
public static final String CATEGORY_RECOMMENDATION = "recommendation";
public static final String CATEGORY_STATUS = "status";
代码如下:
if(index % 2 == 0){
builder.setCategory(NotificationCompat.CATEGORY_CALL);
}else if(index % 2 == 1){
builder.setCategory(NotificationCompat.CATEGORY_EMAIL);
}
效果如下:
我们可以看下通知右边的数字,所有的奇数为一组,所有的偶数为一组。
目前测试,低于Android5.0的手机是无效的。
(27)setPublicVersion
设置安全锁屏下的通知
builder.setPublicVersion(notification);
另外别忘了添加
builder.setVisibility(Notification.VISIBILITY_PUBLIC);
稍后会对setVisibility详细讲解。
有些手机又类似于这样的开关
我们需要手动打开这个开关才能在锁屏状态下显示通知。
目前在在Android5.0以上的手机上测试通过,由于没有Android4.X的设备并且模拟器也不支持锁屏,所以就留个悬念吧。
(28)setVisibility(横幅)
设置通知的显示等级
builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
在Android5.0之后新增了以下三种通知等级
VISIBILITY_PUBLIC 任何情况都会显示通知
VISIBILITY_PRIVATE 只有在没有锁屏时会显示通知
VISIBILITY_SECRET 在安全锁和没有锁屏的情况下显示通知
以上已经演示了通知在锁屏状态下的显示,那么这里再演示以下悬挂通知
悬挂通知,就是挂在屏幕顶端的通知。
这里需要说明一下,不是只要设置setVisibility(NotificationCompat.VISIBILITY_PUBLIC)就一定能显示悬挂通知,有些手机对通知做了很大的处理,就比如上面说到了,必须开启顶端通知的开关才能显示。
(29)setFullScreenIntent
响应紧急状态的全屏事件(例如来电事件),也就是说通知来的时候,跳过在通知区域点击通知这一步,直接执行fullScreenIntent代表的事件
setFullScreenIntent存在兼容问题。
(30)setActions
当Notification.Builder builder被NotificationCompat.Builder取代后,setActions被舍弃,NotificationCompat.Builder新增addAction方法。
addAction在文章后面讲到。
(31)setChronometerCountDown
当Notification.Builder builder被NotificationCompat.Builder取代后,setChronometerCountDown被舍弃。
(32)setChannelId
创建通知时指定channelID
Android8.0新增了通知渠道
这个概念,如果没有设置,则通知无法在Android8.0的机器上显示。
代码如下:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {//Android 8.0以上
String channelID = "1";
String channelName = "通知测试";
NotificationChannel channel = new NotificationChannel(channelID, channelName, NotificationManager.IMPORTANCE_HIGH);
notificationManager.createNotificationChannel(channel);
//创建通知时指定channelID
builder.setChannelId(channelID);
}
NotificationChannel是通知渠道的意思,channelID为通知渠道ID,channelName为通知渠道名称,NotificationManager.IMPORTANCE_HIGH为通知渠道的优先级。
通道相关的知识我们最后再讲。
(33)addAction(只支持Android7.0以上的手机)
添加内联回复的通知。
//准备intent
Intent replyPendingIntent = new Intent(this, NotificationBroadcastReceiver.class);
replyPendingIntent.setAction("com.xxx.xxx.replypending");
replyPendingIntent.putExtra("messageId", index);
// 构建 PendingIntent
PendingIntent replyPendingPI = PendingIntent.getBroadcast(this, 2, replyPendingIntent, PendingIntent.FLAG_UPDATE_CURRENT );
builder.setRemoteInputHistory(new String[]{"这条通知可以点击下面按钮直接回复..."});
//创建一个可添加到通知操作的 RemoteInput.Builder 实例。 该类的构造函数接受系统用作文本输入密钥的字符串。 之后,手持式设备应用使用该密钥检索输入的文本。
RemoteInput remoteInput = new RemoteInput.Builder("key_text_reply")
.setLabel("回复")
.build();
//使用 addRemoteInput() 向操作附加 RemoteInput 对象。
NotificationCompat.Action action = new NotificationCompat.Action.Builder(R.mipmap.shennvguo2, "点击直接回复", replyPendingPI)
.addRemoteInput(remoteInput)
.build();
//对通知应用操作。
builder.addAction(action);
在内联输入框中输入想要回复的文字,点击发送之后会收到一个广播,广播的处理如下:
//从内联回复检索用户输入
int messageId = intent.getIntExtra("messageId", 0);
Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
if (remoteInput != null) {
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
CharSequence message = remoteInput.getCharSequence("key_text_reply");
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "1");
builder.setSmallIcon(R.mipmap.shennvguo1)
.setContentTitle("内联回复")//设置通知标题
.setContentText(message)//设置通知内容
.setAutoCancel(true)//设为true,点击通知栏移除通知
.setOngoing(false)//设置是否是正在进行中的通知,默认是false
.setOnlyAlertOnce(false);//设置是否只通知一次
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {//Android 8.0以上
String channelID = "1";
String channelName = "通知测试";
NotificationChannel channel = new NotificationChannel(channelID, channelName, NotificationManager.IMPORTANCE_DEFAULT );
notificationManager.createNotificationChannel(channel);
//创建通知时指定channelID
builder.setChannelId(channelID);
}
Notification notification = builder.build();
notificationManager.notify(messageId, notification);
回复之后会发送一个通知,通知ID和回复前一致。
(34)setSettingsText
当Notification.Builder被NotificationCompat.Builder替代之后,setSettingsText已被舍弃。
(35)setBadgeIconType
设置角标Icon类型。
经过测试,这个方法是无效的,现在好多国内手机Launcher的角标和setBadgeIconType无关。
有关角标的适配方案文章后面会讲到
(36)setShortcutId
setShortcutId字面上也和Launcher的角标有关,但经过测试没有发现有什么用。
有关角标的适配方案文章后面会讲到
(37)setTimeoutAfter
设置超时时间,超时之后自动取消。
builder.setTimeoutAfter(5000);//设置超时时间,超时之后自动取消(Android8.0有效)
经过测试,setTimeoutAfter目前只有在8.0以上的手机上有效。
(38)setGroupAlertBehavior(8.0新增)
设置群组提醒的行为;
NotificationCompat.GROUP_ALERT_ALL:这意味着在有声音或振动的组中,所有通知都应该发出声音或振动,因此当该通知在组中时,不会将其静音
NotificationCompat.GROUP_ALERT_SUMMARY:即使将一个组中的摘要通知发布到具有声音和/或振动的通知通道中,也应使其静音(无声音或振动)
NotificationCompat.GROUP_ALERT_CHILDREN:一个组中的所有子通知都应该被静音(没有声音或振动),即使他们被发布到有声音和/或振动的通知频道。如果此通知是子组级,则使用此常量将此通知静音。这必须应用于所有要静音的子通知。
(39)setSound
设置铃声。
setSound(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.publicnotify))
setDefaults(Notification.DEFAULT_SOUND) //获取默认铃声
setSound(Uri.parse("file:///sdcard/xx/xx.mp3")) //获取自定义铃声
setSound(Uri.withAppendedPath(Audio.Media.INTERNAL_CONTENT_URI, "5")) //获取Android多媒体库内的铃声
(40)setLights
设置呼吸灯。
setLights(Color.RED,2000,Color.BLUE)
参数依次是:灯光颜色, 亮持续时间,暗的时间,不是所有颜色都可以,这跟设备有关,有些手机还不带三色灯; 另外,还需要为Notification设置flags为Notification.FLAG_SHOW_LIGHTS才支持三色灯提醒!
Notification Channels
在Android8.0之后,引入了通知渠道。
简单的写法如下
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {//Android 8.0以上
String channelID = "1";
String channelName = "我是通知渠道";
NotificationChannel channel = new NotificationChannel(channelID, channelName, NotificationManager.IMPORTANCE_HIGH);
//channel.setShowBadge(true);
notificationManager.createNotificationChannel(channel);
//创建通知时指定channelID
builder.setChannelId(channelID);
//builder.setTimeoutAfter(5000);//设置超时时间,超时之后自动取消(Android8.0有效)
}
在Android8.0中,可以在通知中查看渠道信息。
(1)重要性
NotificationChannel channel = new NotificationChannel(channelID, channelName, NotificationManager.IMPORTANCE_MIN);
这里第三个参数传入的参数是重要性。
- IMPORTANCE_NONE 关闭通知
- IMPORTANCE_MIN 开启通知,不会弹出,但没有提示音,状态栏中无显示
- IMPORTANCE_LOW 开启通知,不会弹出,不发出提示音,状态栏中显示
- IMPORTANCE_DEFAULT 开启通知,不会弹出,发出提示音,状态栏中显示
- IMPORTANCE_HIGH 开启通知,会弹出,发出提示音,状态栏中显示
在平时用的比较多了还是IMPORTANCE_HIGH,因为这个属性同样被定制机影响,这个只要了解就行,做系统级APP也许会深入的使用,普通的APP只要使用IMPORTANCE_HIGH就可以了。
(2)setShowBadge
显示通知角标。
channel.setShowBadge(true);//显示通知角标
oppo手机的角标分为两种:
- 圆点角标(不显示数字)
当有新的通知时,显示圆点角标,但不显示数字
- 数字角标
当有新的通知时,显示数字角标,显示数字。
需要注意的是:该方法受到定制手机的影响。
(2)canShowBadge
应该是检查设备是否支持显示角标
(3)setBypassDnd
设置可以绕过请勿打扰模式。
channel.setBypassDnd(true);// 设置绕过请勿打扰模式
需要注意的是:该方法是无法生效的,只能被系统或者排序排序服务所更改。
(4)canBypassDnd
判断设备是否支持绕过免打扰。
(5)enableLights
设置通知出现时的闪灯(如果 android 设备支持的话)
channel.enableLights(true);//设置通知出现时的闪灯(如果 android 设备支持的话)
(6)enableVibration
设置通知出现时的震动(如果 android 设备支持的话)
channel.enableVibration(true);// 设置通知出现时的震动(如果 android 设备支持的话)
(7)setDescription
设置渠道的描述信息。
channel.setDescription("AAAAAAAAAA");//设置渠道的描述信息
一些定制手机将这个信息去除了。
(8)setImportance
设置重要性。(在前面说过了)
(9)setLightColor
设置呼吸灯的颜色。
需要设备的支持,有些手机呼吸灯只支持一种颜色。
(10)setName
设置渠道名称。
channel.setName("wweqw");
(11)setSound
设置提示铃声。
channel.setSound(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.publicnotify), new AudioAttributes.Builder().build());
(12)setVibrationPattern
设置震动模式。
channel.setVibrationPattern(new long[]{200, 200, 1000, 200, 1000, 200});
(13)setLockscreenVisibility
设置锁屏的情况下是否显示通知。
需要注意的是:该方法是无法生效的,只能被系统或者排序排序服务所更改。
app只要使用
//锁屏时显示通知
builder.setPublicVersion(notification);
即可。
数字角标
随着国内定制手机的大量出现,Launcher上的角标问题越来越棘手。
即使我们在代码中添加了setBadgeIconType、setShortcutId、channel.setShowBadge之类的配置也没有用。
在网上找了些框架,比如
https://github.com/leolin310148/ShortcutBadger,其实也有时问题的,并不能适配所有的机型,这也体现了国内设备的恶心之处。
大家先关注一下吧,目前好几款手机都测试OK的。
这里有一篇文章:
[贝聊科技]有关Android应用桌面角标(BadgeNumber)实现的探讨
这篇文章算是比较好的了,大家可以去看看,oppo手机的角标我试了,有用。
由于缺少其他机型的手机,所以就没有尝试了。
另外,有关角标,有一点最最重要
,好多定制手机做了通知角标白名单
,只有将你app的包名放入定制手机的 白名单
里面才可以显示角标,“com.xunmeng.pinduoduo”这个包名已被大部分定制手机假如白名单,大家可以将包名改成这个试试。实在不行大家就在网上搜搜QQ和微信的包名是什么,然后将自己app的包名改掉就行了。
最后附上通知适配的通用写法:
int index = 0;
/**
* 弹出通知提醒
*/
private void tapNotification(){
index = index +1 ;
NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
//准备intent
Intent clickIntent = new Intent(this, NotificationBroadcastReceiver.class);
clickIntent.setAction("com.xxx.xxx.click");
// 构建 PendingIntent
PendingIntent clickPI = PendingIntent.getBroadcast(this, 1, clickIntent, PendingIntent.FLAG_CANCEL_CURRENT);
//准备intent
Intent cacelIntent = new Intent(this, NotificationBroadcastReceiver.class);
cacelIntent.setAction("com.xxx.xxx.cancel");
// 构建 PendingIntent
PendingIntent cacelPI = PendingIntent.getBroadcast(this, 2, cacelIntent, PendingIntent.FLAG_CANCEL_CURRENT );
//准备intent
Intent fullscreenIntent = new Intent(this, NotificationBroadcastReceiver.class);
fullscreenIntent.setAction("com.xxx.xxx.fullscreen");
// 构建 PendingIntent
PendingIntent fullscreenPI = PendingIntent.getBroadcast(this, 2, fullscreenIntent, PendingIntent.FLAG_UPDATE_CURRENT );
String channelID = "1";
//Notification.Builder builder = new Notification.Builder(MainActivity.this);
NotificationCompat.Builder builder = new NotificationCompat.Builder(MainActivity.this, channelID);
String title = "标题"+index;
String conttext = "我是一个通知"+index;
//NotificationCompat.BigTextStyle bigTextStyle = new NotificationCompat.BigTextStyle();
//bigTextStyle.setBigContentTitle(title);
//bigTextStyle.setSummaryText(conttext);
//bigTextStyle.bigText("一二三西思思");
//builder.setStyle(bigTextStyle);
//NotificationCompat.MessagingStyle messagingStyle = new NotificationCompat.MessagingStyle("UserName");
//messagingStyle.addMessage("message",System.currentTimeMillis(),"JulyYu");
//messagingStyle.setConversationTitle("Messgae Title");
//builder.setStyle(messagingStyle);
//NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle();
//inboxStyle.setBigContentTitle(title);
//inboxStyle.setSummaryText(conttext);
//inboxStyle.addLine("A");
//inboxStyle.addLine("B");
RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.activity_main);
builder.setSmallIcon(R.mipmap.shennvguo1)
.setContentTitle(title)//设置通知标题
.setContentText(conttext)//设置通知内容
.setContentIntent(clickPI)// 设置pendingIntent,点击通知时就会用到
.setAutoCancel(true)//设为true,点击通知栏移除通知
.setDeleteIntent(cacelPI)//设置pendingIntent,左滑右滑通知时就会用到
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.shennvguo2))//设置大图标
.setNumber(index)//显示在右边的数字
.setOngoing(false)//设置是否是正在进行中的通知,默认是false
.setOnlyAlertOnce(false)//设置是否只通知一次
.setProgress(100, 20, false)
//.setStyle(messagingStyle)
.setSound(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.publicnotify))
.setVibrate(new long[] {3000,1000,500,700,500,300})//延迟3秒,然后震动1000ms,再延迟500ms,接着震动700ms,最后再延迟500ms,接着震动300ms。
.setLights(Color.RED,2000,Color.BLUE)
//.setDefaults(Notification.DEFAULT_LIGHTS)
.setSubText("我是一个SubText")
.setTicker("通知测试")//提示
.setUsesChronometer(true)
.setWhen(System.currentTimeMillis())
.setLocalOnly(true)//设置此通知是否仅与当前设备相关。如果设置为true,通知就不能桥接到其他设备上进行远程显示。
.setShowWhen(true);
if(index % 5 == 0){
builder.setSortKey("A");//设置针对一个包内的通知进行排序的键值
}else if(index % 5 == 1){
builder.setSortKey("B");//设置针对一个包内的通知进行排序的键值
}else if(index % 5 == 2){
builder.setSortKey("C");//设置针对一个包内的通知进行排序的键值
}else if(index % 5 == 3){
builder.setSortKey("D");//设置针对一个包内的通知进行排序的键值
}else if(index % 5 == 4){
builder.setSortKey("E");//设置针对一个包内的通知进行排序的键值
}
//响应紧急状态的全屏事件(例如来电事件),也就是说通知来的时候,跳过在通知区域点击通知这一步,直接执行fullScreenIntent代表的事件
//builder.setFullScreenIntent(fullscreenPI, true);
//Bundle bundle = new Bundle();
//builder.setExtras(bundle);
// if(index % 2 == 0){
// builder.setCategory(NotificationCompat.CATEGORY_CALL);
// }else if(index % 2 == 1){
// builder.setCategory(NotificationCompat.CATEGORY_EMAIL);
// }
builder.setVisibility(Notification.VISIBILITY_PUBLIC);//悬挂通知(横幅)
builder.setCustomBigContentView(remoteViews)//设置通知的布局
.setCustomHeadsUpContentView(remoteViews)//设置悬挂通知的布局
.setCustomContentView(remoteViews);
//builder.setChronometerCountDown()//已舍弃
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {//Android7.0以上
// if(index == 1){
// builder.setGroupSummary(true);//设置是否为一组通知的第一个显示
// }
// builder.setGroup("notification_test");//捆绑通知
//准备intent
Intent replyPendingIntent = new Intent(this, NotificationBroadcastReceiver.class);
replyPendingIntent.setAction("com.xxx.xxx.replypending");
replyPendingIntent.putExtra("messageId", index);
// 构建 PendingIntent
PendingIntent replyPendingPI = PendingIntent.getBroadcast(this, 2, replyPendingIntent, PendingIntent.FLAG_UPDATE_CURRENT );
builder.setRemoteInputHistory(new String[]{"这条通知可以点击下面按钮直接回复..."});
//创建一个可添加到通知操作的 RemoteInput.Builder 实例。 该类的构造函数接受系统用作文本输入密钥的字符串。 之后,手持式设备应用使用该密钥检索输入的文本。
RemoteInput remoteInput = new RemoteInput.Builder("key_text_reply")
.setLabel("回复")
.build();
//使用 addRemoteInput() 向操作附加 RemoteInput 对象。
NotificationCompat.Action action = new NotificationCompat.Action.Builder(R.mipmap.shennvguo2, "点击直接回复", replyPendingPI)
.addRemoteInput(remoteInput)
.build();
//对通知应用操作。
builder.addAction(action);
}
//builder.setBadgeIconType(NotificationCompat.BADGE_ICON_NONE);//设置角标类型(无效)
//builder.setSettingsText();已舍弃
//builder.setShortcutId("100");
//builder.setColorized(true);//启用通知的背景颜色设置
//builder.setColor(Color.RED);
//builder.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {//Android 8.0以上
String channelName = "我是通知渠道";
NotificationChannel channel = new NotificationChannel(channelID, channelName, NotificationManager.IMPORTANCE_HIGH);
//channel.setShowBadge(true);//显示通知角标
//boolean aa = channel.canShowBadge();
//channel.setBypassDnd(true);// 设置绕过请勿打扰模式
//boolean ca = channel.canBypassDnd();
channel.enableLights(true);//设置通知出现时的闪灯(如果 android 设备支持的话)
channel.enableVibration(true);// 设置通知出现时的震动(如果 android 设备支持的话)
channel.setDescription("AAAAAAAAAA");//设置渠道的描述信息
//channel.setGroup("AAAA");
channel.setImportance(NotificationManager.IMPORTANCE_HIGH);
channel.setLightColor(Color.YELLOW);
//channel.setLockscreenVisibility();
channel.setName("wweqw");
channel.setSound(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.publicnotify), new AudioAttributes.Builder().build());
channel.setVibrationPattern(new long[]{200, 200, 1000, 200, 1000, 200});
notificationManager.createNotificationChannel(channel);
//创建通知时指定channelID
builder.setChannelId(channelID);
//builder.setTimeoutAfter(5000);//设置超时时间,超时之后自动取消(Android8.0有效)
}
Notification notification = builder.build();
//锁屏时显示通知
builder.setPublicVersion(notification);
notificationManager.notify(index, notification);
}
PS:
如果使用Notification.Builder,那么会遇到好多兼容性问题,以上代码的适配方案肯定行不通。
后来Google为了解决兼容性问题,将NotificationCompat.Builder替代Notification.Builder, 使用NotificationCompat.Builder不需要过多考虑适配问题,直接使用以上适配方案即可。