隨著Google對Notification的不斷升級袄秩,所以必須考慮適配問題了跟衅。
在Android4.1之前(不包括Android4.1)
在高SDK版本中苗膝, setLatestEventInfo已被棄用止毕,并且現(xiàn)在九成九Android用戶的系統(tǒng)都在4.4以上了,所以這種情況就不需要考慮了吞滞。
后來在Android4.1以上(包括4.1)谷歌推出了Notification.Builder(建造者模式)方式創(chuàng)建通知佑菩,但這種方式不支持4.1之前的版本
Notification.Builder builder = new Notification.Builder(MainActivity.this);
Google后來推出了NotificationCompat.Builder方式,為各種配置做兼容性處理裁赠。
所以Notification.Builder已經(jīng)被NotificationCompat.Builder替代殿漠。
NotificationCompat.Builder builder = new NotificationCompat.Builder(MainActivity.this);
NotificationCompat.Builder的出現(xiàn)是為了
(1)setSmallIcon設(shè)置小圖標(biāo)
setSmallIcon必須設(shè)置,否則通知不會(huì)顯示佩捞,所以最簡單的通知如下
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);
}
它只設(shè)置了小圖绞幌,圖片效果如下
那么我們給他添加標(biāo)題和內(nèi)容
(2)setContentTitle和setContentText
builder.setSmallIcon(R.mipmap.shennvguo1)
.setContentTitle("我是通知的標(biāo)題")//設(shè)置通知標(biāo)題
.setContentText("我是一個(gè)通知");//設(shè)置通知內(nèi)容
效果如下
(3)setContentIntent
當(dāng)我們嘗試點(diǎn)擊這個(gè)通知的時(shí)候發(fā)現(xiàn)點(diǎn)擊是沒有效果的,要想點(diǎn)擊的時(shí)候讓通知消失那么還需要改進(jìn)下代碼
//準(zhǔn)備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("我是通知的標(biāo)題")//設(shè)置通知標(biāo)題
.setContentText("我是一個(gè)通知")//設(shè)置通知內(nèi)容
.setContentIntent(clickPI);// 設(shè)置pendingIntent,點(diǎn)擊通知時(shí)就會(huì)用到
setContentIntent(clickPI)就是讓通知的點(diǎn)擊效果生效一忱,代碼的意思是莲蜘,點(diǎn)擊通知時(shí)拘领,跳轉(zhuǎn)到另一個(gè)Activity挽霉。
效果如下:
(4)setAutoCancel
點(diǎn)擊通知之后發(fā)現(xiàn)通知沒有自動(dòng)消失浪汪,這不是我們想要的效果判没,我們需要的效果是仪吧,當(dāng)點(diǎn)擊通知時(shí)讓通知自動(dòng)消失
builder.setSmallIcon(android.R.drawable.stat_sys_download_done)
.setContentTitle("我是通知的標(biāo)題")//設(shè)置通知標(biāo)題
.setContentText("我是一個(gè)通知")//設(shè)置通知內(nèi)容
.setContentIntent(clickPI)// 設(shè)置pendingIntent,點(diǎn)擊通知時(shí)就會(huì)用到
.setAutoCancel(true);//設(shè)為true庄新,點(diǎn)擊通知欄移除通知
setAutoCancel(true)可以使點(diǎn)擊通知時(shí)自動(dòng)消失。
需要重點(diǎn)注意的是薯鼠,setAutoCancel需要和setContentIntent一起使用择诈,否則無效。
(5)setDeleteIntent
當(dāng)我們左滑或者右滑通知時(shí)出皇,發(fā)現(xiàn)通知會(huì)消失羞芍,也就是說,如果手機(jī)沒有經(jīng)過特殊定制處理的話郊艘,一般有兩種消失的行為荷科,第一種是點(diǎn)擊消失,第二種是滑動(dòng)消失纱注,有時(shí)候畏浆,如果有需要可以通過廣播監(jiān)聽這兩種事件:
NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
//準(zhǔn)備intent
Intent clickIntent = new Intent(this, NotificationBroadcastReceiver.class);
clickIntent.setAction("com.xxx.xxx.click");
// 構(gòu)建 PendingIntent
PendingIntent clickPI = PendingIntent.getBroadcast(this, 1, clickIntent, PendingIntent.FLAG_CANCEL_CURRENT);
//準(zhǔn)備intent
Intent cacelIntent = new Intent(this, NotificationBroadcastReceiver.class);
cacelIntent.setAction("com.xxx.xxx.cancel");
// 構(gòu)建 PendingIntent
PendingIntent cacelPI = PendingIntent.getBroadcast(this, 2, cacelIntent, PendingIntent.FLAG_CANCEL_CURRENT );
builder.setSmallIcon(android.R.drawable.stat_sys_download_done)
.setContentTitle("我是通知的標(biāo)題")//設(shè)置通知標(biāo)題
.setContentText("我是一個(gè)通知")//設(shè)置通知內(nèi)容
.setContentIntent(clickPI)// 設(shè)置pendingIntent,點(diǎn)擊通知時(shí)就會(huì)用到
.setAutoCancel(true)//設(shè)為true,點(diǎn)擊通知欄移除通知
.setDeleteIntent(cacelPI);//設(shè)置pendingIntent,左滑右滑通知時(shí)就會(huì)用到
setDeleteIntent就是設(shè)置滑動(dòng)消失行為的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")) {
//處理點(diǎn)擊事件
System.out.println("click");
}
if (action.equals("com.xxx.xxx.cancel")) {
//處理滑動(dòng)清除和點(diǎn)擊刪除事件
System.out.println("cancel");
}
}
}
靜態(tài)注冊
<receiver android:name=".notification.NotificationBroadcastReceiver">
<intent-filter>
<action android:name="com.xxx.xxx.click"/>
<action android:name="com.xxx.xxx.cancel"/>
</intent-filter>
</receiver>
發(fā)送廣播是PendingIntent處理的刻获,當(dāng)我們點(diǎn)擊通知或者滑動(dòng)通知,通知消失的時(shí)候PendingIntent就會(huì)發(fā)送廣播瞎嬉。
(6)setLargeIcon
setLargeIcon可以設(shè)置大圖標(biāo)蝎毡,如果沒有設(shè)置大圖標(biāo),大圖標(biāo)的位置的圖片將會(huì)是小圖標(biāo)的圖片氧枣。
小圖標(biāo):該圖需要做成透明背景圖
大圖標(biāo):該圖不需要做成透明背景圖
PS:個(gè)別定制機(jī)對通知做了很大的處理沐兵,有些廠商對setSmallIcon和setLargeIcon接口做了處理,不管我們代碼中設(shè)置什么圖片便监,他的通知圖標(biāo)在某定制手機(jī)上就是APP默認(rèn)圖標(biāo)痒筒。如果大家遇到這個(gè)問題請不要糾結(jié),直接找產(chǎn)商處理茬贵。
(7)setNumber
顯示在右邊的數(shù)字
(8)setOngoing
設(shè)置是否是正在進(jìn)行中的通知簿透,默認(rèn)是false
如果設(shè)置成true,左右滑動(dòng)的時(shí)候就不會(huì)被刪除了解藻,如果想刪除可以在之老充。
(9)setOnlyAlertOnce
設(shè)置是否只通知一次,這個(gè)效果主要體現(xiàn)在震動(dòng)螟左、提示音啡浊、懸掛通知上觅够。
默認(rèn)相同ID的Notification可以無限通知,如果有震動(dòng)巷嚣、閃燈喘先、提示音和懸掛通知的話可能會(huì)不斷的打擾用戶。
setOnlyAlertOnce的默認(rèn)值是false廷粒,如果設(shè)置成true窘拯,那么一旦狀態(tài)欄有ID為n的通知,再次調(diào)用notificationManager.notify(n, notification)時(shí)坝茎,將不會(huì)有震動(dòng)涤姊、閃燈、提示音以及懸掛通知的提醒嗤放。
懸掛通知
主要體現(xiàn)在5.0以上的手機(jī)上思喊,稍后會(huì)講解。
(10)setProgress
為通知設(shè)置設(shè)置一個(gè)進(jìn)度條
setProgress(int max, int progress, boolean indeterminate)
max:最大值
progress:當(dāng)前進(jìn)度
indeterminate:進(jìn)度是否確定
當(dāng)進(jìn)度確定的情況下
setProgress(100, 20, false);
當(dāng)進(jìn)度不確定的情況下
setProgress(100, 20, true);
(11)setStyle
為通知設(shè)置樣式
NotificationCompat的樣式主要有以下幾點(diǎn)
-
BigPictureStyle
NotificationCompat.BigPictureStyle bigPictureStyle = new NotificationCompat.BigPictureStyle(); bigPictureStyle.setBigContentTitle("一二三四五次酌,上山打老虎恨课!"); bigPictureStyle.setSummaryText("我就是一個(gè)標(biāo)題!"); bigPictureStyle.bigPicture(BitmapFactory.decodeResource(getResources(), R.drawable.che)); //bigPictureStyle.bigLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.che));
setStyle(bigPictureStyle);
-
BigTextStyle
String title = "我是通知的標(biāo)題"; String conttext = "我是一個(gè)通知"; 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);//設(shè)置懸掛通知和一般通知的布局
setCustomContentView可以用setCustomBigContentView和setCustomHeadsUpContentView替代
.setStyle(new NotificationCompat.DecoratedCustomViewStyle())
.setCustomBigContentView(remoteViews)//設(shè)置通知的布局
.setCustomHeadsUpContentView(remoteViews);//設(shè)置懸掛通知的布局
效果如下:
通知布局
懸掛通知布局(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
我們看一下代碼寫法
在現(xiàn)在高版本的SDK中贫母,MessagingStyle(@NonNull CharSequence userDisplayName)已經(jīng)過時(shí)了文兑,查看其構(gòu)造方法
/** @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;
}
}
我們發(fā)現(xiàn)剩下沒過時(shí)的方法已經(jīng)沒有什么研究價(jià)值了。
(12)setDefaults
向通知添加聲音腺劣、閃燈和震動(dòng)效果绿贞,最簡單、最一致的方式是使用當(dāng)前的用戶默認(rèn)設(shè)置橘原,使用defaults屬性籍铁,可以組合Notification.DEFAULT_ALL、Notification.DEFAULT_SOUND添加聲音趾断。
setDefaults(Notification.DEFAULT_ALL);
其中參數(shù)屬性分別為:
Notification.DEFAULT_VISIBLE //添加默認(rèn)震動(dòng)提醒 需要VIBRATE permission
Notification.DEFAULT_SOUND //添加默認(rèn)聲音提醒
Notification.DEFAULT_LIGHTS //添加默認(rèn)三色燈提醒
Notification.DEFAULT_ALL //添加默認(rèn)以上三種全部提醒
(13)setVibrate
設(shè)置使用震動(dòng)模式
setVibrate(new long[] {3000,1000,500,700,500,300})//延遲3秒拒名,然后震動(dòng)1000ms,再延遲500ms芋酌,接著震動(dòng)700ms,最后再延遲500ms增显,接著震動(dòng)300ms。
如果setDefaults的屬性設(shè)置的是Notification.DEFAULT_ALL或者Notification.DEFAULT_VISIBLE脐帝,setVibrate將無效同云,因?yàn)镹otification.DEFAULT_ALL或者Notification.DEFAULT_VISIBLE會(huì)替代setVibrate糖权。
如果想自定義震動(dòng)模式,有想有閃燈和提示音炸站,那么可以這樣做
.setVibrate(new long[] {3000,1000,500,700,500,300})//延遲3秒星澳,然后震動(dòng)1000ms,再延遲500ms旱易,接著震動(dòng)700ms,最后再延遲500ms禁偎,接著震動(dòng)300ms。
.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_LIGHTS);
(14)setSubText
在通知上新增一行文本咒唆,使原本兩行文本變成三行文本
setSubText("我是一個(gè)SubText");
(16)setTicker
設(shè)置通知在第一次到達(dá)時(shí)在狀態(tài)欄中顯示的文本
效果如下:
需要注意的是:一些手機(jī)是顯示不了的届垫,查了些資料都說5.0以上的手機(jī)顯示不了释液,但是我手上的測試機(jī)系統(tǒng)是5.0.2的全释,setTicker是可以生效的。
(17)setUsesChronometer
設(shè)置是否顯示時(shí)間計(jì)時(shí)误债,電話通知就會(huì)使用到浸船。
(18)setWhen
通知產(chǎn)生的時(shí)間,會(huì)在通知欄信息里顯示寝蹈,一般是系統(tǒng)獲取到的時(shí)間
setWhen(System.currentTimeMillis());
如果沒有設(shè)置也沒有影響李命,通知默認(rèn)是當(dāng)前時(shí)間戳。
當(dāng)然箫老,我們可以設(shè)置自己的時(shí)間封字,比如:
setWhen(System.currentTimeMillis() - 100);
這樣通知的時(shí)間就會(huì)變化了,非當(dāng)前時(shí)間耍鬓。
主要需要注意的是:
setWhen只是為通知設(shè)置時(shí)間戳阔籽,和是否顯示時(shí)間沒有任何關(guān)系,設(shè)置是否顯示時(shí)間的方法是setShowWhen牲蜀。
(19)setShowWhen
設(shè)置是否顯示當(dāng)前時(shí)間
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {//Android4.2以上
builder.setShowWhen(true);
}
setShowWhen只有在Android4.2以上的手機(jī)上才能生效笆制,另外當(dāng)已經(jīng)設(shè)置了setUsesChronometer(true),則當(dāng)前時(shí)間就顯示不了(除非定制手機(jī)處理)涣达,默認(rèn)情況下時(shí)間計(jì)時(shí)和時(shí)間戳的顯示是在通知的同一區(qū)域在辆。
(20)setExtras
為通知設(shè)置數(shù)據(jù),在Android4.4新增了設(shè)置數(shù)據(jù)的入口度苔。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {//Android4.4以上
Bundle bundle = new Bundle();
builder.setExtras(bundle);
}
(21)setGroup
設(shè)置該通知組的密鑰匆篓,即確認(rèn)為哪一組。
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");//捆綁通知
}
}
這個(gè)主要體現(xiàn)在Android7.0以上的手機(jī)上的捆綁通知
或者折疊通知
寇窑。文章后面有講解鸦概。
(22)setGroupSummary
設(shè)置是否為一組通知的第一個(gè)顯示,默認(rèn)是false疗认。
setGroup和setGroupSummary結(jié)合可以實(shí)現(xiàn)捆綁通知
或者折疊通知
完残,代碼如下:
if(index == 1){
builder.setGroupSummary(true);//設(shè)置是否為一組通知的第一個(gè)顯示
}
builder.setGroup("notification_test");//捆綁通知
目前只有在7.0以上的手機(jī)上才能看出效果
下面說明一下我針對setGroupSummary和setGroup的測試結(jié)果:
-
如果setGroupSummary和setGroup都不設(shè)置伏钠,Android7.0以上的時(shí)候會(huì)自動(dòng)分組
其中第一個(gè)通知也能看到。
-
如果只設(shè)置setGroup谨设,但是不設(shè)置setGroupSummary的情況熟掂。
builder.setGroup("notification_test");//捆綁通知
如果每個(gè)通知都設(shè)置了setGroupSummary(true),這樣每個(gè)通知都作為主通知了扎拣,毫無意義赴肚。
-
如果指定第一條通知為主通知
if(index == 1){ builder.setGroupSummary(true);//設(shè)置是否為一組通知的第一個(gè)顯示 } builder.setGroup("notification_test");//捆綁通知
那么,效果如下:
我們看到第一條通知的文本已經(jīng)看不到了二蓝,因?yàn)榈谝粭l通知已經(jīng)作為主通知了誉券。
(23)setLocalOnly
設(shè)置此通知是否僅與當(dāng)前設(shè)備相關(guān)。如果設(shè)置為true刊愚,通知就不能橋接到其他設(shè)備上進(jìn)行遠(yuǎn)程顯示踊跟。
(24)setSortKey
設(shè)置針對一個(gè)包內(nèi)的通知進(jìn)行排序的鍵值,鍵值是一個(gè)字符串鸥诽,通知會(huì)按照鍵值的順序排列商玫。
排序的效果看下圖
NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
NotificationCompat.Builder builder = new NotificationCompat.Builder(MainActivity.this);
builder.setSmallIcon(R.mipmap.shennvguo1);
(25)setColor
設(shè)置通知欄顏色(Android5.0新增)
builder.setColor(Color.RED);
目前測試大多測試機(jī)沒有效果,我的Android8.0的Oppo手機(jī)的效果如下:
圖片的效果可以看出牡借,應(yīng)用名稱以及進(jìn)度條都變成紅色了拳昌,目前因?yàn)槎ㄖ茩C(jī)的影響,setColor作用不是很大了钠龙。建議還是不要設(shè)置顏色值為好炬藤。
之后,在Android8.0之后碴里,新增了setColorized方法沈矿,官方的解釋是:啟用通知的背景顏色設(shè)置,目前不清楚它的作用并闲。
注意:
- 如果使用Notification.Builder
setColor只有在Android5.0之后有效细睡。
- 如果使用NotificationCompat.Builder
setColor在任何版本都有效,無需做兼容處理帝火。
(26)setCategory
設(shè)置通知類別
通知類別有
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);
}
效果如下:
我們可以看下通知右邊的數(shù)字溜徙,所有的奇數(shù)為一組,所有的偶數(shù)為一組犀填。
目前測試蠢壹,低于Android5.0的手機(jī)是無效的。
(27)setPublicVersion
設(shè)置安全鎖屏下的通知
builder.setPublicVersion(notification);
另外別忘了添加
builder.setVisibility(Notification.VISIBILITY_PUBLIC);
稍后會(huì)對setVisibility詳細(xì)講解九巡。
有些手機(jī)又類似于這樣的開關(guān)
我們需要手動(dòng)打開這個(gè)開關(guān)才能在鎖屏狀態(tài)下顯示通知图贸。
目前在在Android5.0以上的手機(jī)上測試通過,由于沒有Android4.X的設(shè)備并且模擬器也不支持鎖屏,所以就留個(gè)懸念吧疏日。
(28)setVisibility(橫幅)
設(shè)置通知的顯示等級
builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
在Android5.0之后新增了以下三種通知等級
VISIBILITY_PUBLIC 任何情況都會(huì)顯示通知
VISIBILITY_PRIVATE 只有在沒有鎖屏?xí)r會(huì)顯示通知
VISIBILITY_SECRET 在安全鎖和沒有鎖屏的情況下顯示通知
以上已經(jīng)演示了通知在鎖屏狀態(tài)下的顯示偿洁,那么這里再演示以下懸掛通知
懸掛通知,就是掛在屏幕頂端的通知沟优。
這里需要說明一下涕滋,不是只要設(shè)置setVisibility(NotificationCompat.VISIBILITY_PUBLIC)就一定能顯示懸掛通知,有些手機(jī)對通知做了很大的處理挠阁,就比如上面說到了宾肺,必須開啟頂端通知的開關(guān)才能顯示。
(29)setFullScreenIntent
響應(yīng)緊急狀態(tài)的全屏事件(例如來電事件)侵俗,也就是說通知來的時(shí)候锨用,跳過在通知區(qū)域點(diǎn)擊通知這一步,直接執(zhí)行fullScreenIntent代表的事件
setFullScreenIntent存在兼容問題隘谣。
(30)setActions
當(dāng)Notification.Builder builder被NotificationCompat.Builder取代后增拥,setActions被舍棄,NotificationCompat.Builder新增addAction方法洪橘。
addAction在文章后面講到跪者。
(31)setChronometerCountDown
當(dāng)Notification.Builder builder被NotificationCompat.Builder取代后棵帽,setChronometerCountDown被舍棄熄求。
(32)setChannelId
創(chuàng)建通知時(shí)指定channelID
Android8.0新增了通知渠道
這個(gè)概念,如果沒有設(shè)置逗概,則通知無法在Android8.0的機(jī)器上顯示弟晚。
代碼如下:
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);
//創(chuàng)建通知時(shí)指定channelID
builder.setChannelId(channelID);
}
NotificationChannel是通知渠道的意思,channelID為通知渠道ID逾苫,channelName為通知渠道名稱卿城,NotificationManager.IMPORTANCE_HIGH為通知渠道的優(yōu)先級。
通道相關(guān)的知識我們最后再講铅搓。
(33)addAction(只支持Android7.0以上的手機(jī))
添加內(nèi)聯(lián)回復(fù)的通知瑟押。
//準(zhǔn)備intent
Intent replyPendingIntent = new Intent(this, NotificationBroadcastReceiver.class);
replyPendingIntent.setAction("com.xxx.xxx.replypending");
replyPendingIntent.putExtra("messageId", index);
// 構(gòu)建 PendingIntent
PendingIntent replyPendingPI = PendingIntent.getBroadcast(this, 2, replyPendingIntent, PendingIntent.FLAG_UPDATE_CURRENT );
builder.setRemoteInputHistory(new String[]{"這條通知可以點(diǎn)擊下面按鈕直接回復(fù)..."});
//創(chuàng)建一個(gè)可添加到通知操作的 RemoteInput.Builder 實(shí)例。 該類的構(gòu)造函數(shù)接受系統(tǒng)用作文本輸入密鑰的字符串星掰。 之后多望,手持式設(shè)備應(yīng)用使用該密鑰檢索輸入的文本。
RemoteInput remoteInput = new RemoteInput.Builder("key_text_reply")
.setLabel("回復(fù)")
.build();
//使用 addRemoteInput() 向操作附加 RemoteInput 對象氢烘。
NotificationCompat.Action action = new NotificationCompat.Action.Builder(R.mipmap.shennvguo2, "點(diǎn)擊直接回復(fù)", replyPendingPI)
.addRemoteInput(remoteInput)
.build();
//對通知應(yīng)用操作怀偷。
builder.addAction(action);
在內(nèi)聯(lián)輸入框中輸入想要回復(fù)的文字,點(diǎn)擊發(fā)送之后會(huì)收到一個(gè)廣播播玖,廣播的處理如下:
//從內(nèi)聯(lián)回復(fù)檢索用戶輸入
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("內(nèi)聯(lián)回復(fù)")//設(shè)置通知標(biāo)題
.setContentText(message)//設(shè)置通知內(nèi)容
.setAutoCancel(true)//設(shè)為true椎工,點(diǎn)擊通知欄移除通知
.setOngoing(false)//設(shè)置是否是正在進(jìn)行中的通知,默認(rèn)是false
.setOnlyAlertOnce(false);//設(shè)置是否只通知一次
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);
//創(chuàng)建通知時(shí)指定channelID
builder.setChannelId(channelID);
}
Notification notification = builder.build();
notificationManager.notify(messageId, notification);
回復(fù)之后會(huì)發(fā)送一個(gè)通知,通知ID和回復(fù)前一致维蒙。
(34)setSettingsText
當(dāng)Notification.Builder被NotificationCompat.Builder替代之后掰吕,setSettingsText已被舍棄。
(35)setBadgeIconType
設(shè)置角標(biāo)Icon類型颅痊。
經(jīng)過測試畴栖,這個(gè)方法是無效的,現(xiàn)在好多國內(nèi)手機(jī)Launcher的角標(biāo)和setBadgeIconType無關(guān)八千。
有關(guān)角標(biāo)的適配方案文章后面會(huì)講到
(36)setShortcutId
setShortcutId字面上也和Launcher的角標(biāo)有關(guān)吗讶,但經(jīng)過測試沒有發(fā)現(xiàn)有什么用。
有關(guān)角標(biāo)的適配方案文章后面會(huì)講到
(37)setTimeoutAfter
設(shè)置超時(shí)時(shí)間恋捆,超時(shí)之后自動(dòng)取消照皆。
builder.setTimeoutAfter(5000);//設(shè)置超時(shí)時(shí)間,超時(shí)之后自動(dòng)取消(Android8.0有效)
經(jīng)過測試沸停,setTimeoutAfter目前只有在8.0以上的手機(jī)上有效膜毁。
(38)setGroupAlertBehavior(8.0新增)
設(shè)置群組提醒的行為;
NotificationCompat.GROUP_ALERT_ALL:這意味著在有聲音或振動(dòng)的組中愤钾,所有通知都應(yīng)該發(fā)出聲音或振動(dòng)瘟滨,因此當(dāng)該通知在組中時(shí),不會(huì)將其靜音
NotificationCompat.GROUP_ALERT_SUMMARY:即使將一個(gè)組中的摘要通知發(fā)布到具有聲音和/或振動(dòng)的通知通道中能颁,也應(yīng)使其靜音(無聲音或振動(dòng))
NotificationCompat.GROUP_ALERT_CHILDREN:一個(gè)組中的所有子通知都應(yīng)該被靜音(沒有聲音或振動(dòng))杂瘸,即使他們被發(fā)布到有聲音和/或振動(dòng)的通知頻道。如果此通知是子組級伙菊,則使用此常量將此通知靜音败玉。這必須應(yīng)用于所有要靜音的子通知。
(39)setSound
設(shè)置鈴聲镜硕。
setSound(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.publicnotify))
setDefaults(Notification.DEFAULT_SOUND) //獲取默認(rèn)鈴聲
setSound(Uri.parse("file:///sdcard/xx/xx.mp3")) //獲取自定義鈴聲
setSound(Uri.withAppendedPath(Audio.Media.INTERNAL_CONTENT_URI, "5")) //獲取Android多媒體庫內(nèi)的鈴聲
(40)setLights
設(shè)置呼吸燈运翼。
setLights(Color.RED,2000,Color.BLUE)
參數(shù)依次是:燈光顏色, 亮持續(xù)時(shí)間兴枯,暗的時(shí)間血淌,不是所有顏色都可以,這跟設(shè)備有關(guān)财剖,有些手機(jī)還不帶三色燈悠夯; 另外,還需要為Notification設(shè)置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);
//創(chuàng)建通知時(shí)指定channelID
builder.setChannelId(channelID);
//builder.setTimeoutAfter(5000);//設(shè)置超時(shí)時(shí)間策彤,超時(shí)之后自動(dòng)取消(Android8.0有效)
}
在Android8.0中栓袖,可以在通知中查看渠道信息。
(1)重要性
NotificationChannel channel = new NotificationChannel(channelID, channelName, NotificationManager.IMPORTANCE_MIN);
這里第三個(gè)參數(shù)傳入的參數(shù)是重要性店诗。
- IMPORTANCE_NONE 關(guān)閉通知
- IMPORTANCE_MIN 開啟通知裹刮,不會(huì)彈出,但沒有提示音庞瘸,狀態(tài)欄中無顯示
- IMPORTANCE_LOW 開啟通知捧弃,不會(huì)彈出,不發(fā)出提示音擦囊,狀態(tài)欄中顯示
- IMPORTANCE_DEFAULT 開啟通知违霞,不會(huì)彈出,發(fā)出提示音瞬场,狀態(tài)欄中顯示
- IMPORTANCE_HIGH 開啟通知买鸽,會(huì)彈出,發(fā)出提示音贯被,狀態(tài)欄中顯示
在平時(shí)用的比較多了還是IMPORTANCE_HIGH眼五,因?yàn)檫@個(gè)屬性同樣被定制機(jī)影響,這個(gè)只要了解就行彤灶,做系統(tǒng)級APP也許會(huì)深入的使用看幼,普通的APP只要使用IMPORTANCE_HIGH就可以了。
(2)setShowBadge
顯示通知角標(biāo)幌陕。
channel.setShowBadge(true);//顯示通知角標(biāo)
oppo手機(jī)的角標(biāo)分為兩種:
- 圓點(diǎn)角標(biāo)(不顯示數(shù)字)
當(dāng)有新的通知時(shí)诵姜,顯示圓點(diǎn)角標(biāo),但不顯示數(shù)字
- 數(shù)字角標(biāo)
當(dāng)有新的通知時(shí)苞轿,顯示數(shù)字角標(biāo)茅诱,顯示數(shù)字。
需要注意的是:該方法受到定制手機(jī)的影響搬卒。
(2)canShowBadge
應(yīng)該是檢查設(shè)備是否支持顯示角標(biāo)
(3)setBypassDnd
設(shè)置可以繞過請勿打擾模式。
channel.setBypassDnd(true);// 設(shè)置繞過請勿打擾模式
需要注意的是:該方法是無法生效的翎卓,只能被系統(tǒng)或者排序排序服務(wù)所更改契邀。
(4)canBypassDnd
判斷設(shè)備是否支持繞過免打擾。
(5)enableLights
設(shè)置通知出現(xiàn)時(shí)的閃燈(如果 android 設(shè)備支持的話)
channel.enableLights(true);//設(shè)置通知出現(xiàn)時(shí)的閃燈(如果 android 設(shè)備支持的話)
(6)enableVibration
設(shè)置通知出現(xiàn)時(shí)的震動(dòng)(如果 android 設(shè)備支持的話)
channel.enableVibration(true);// 設(shè)置通知出現(xiàn)時(shí)的震動(dòng)(如果 android 設(shè)備支持的話)
(7)setDescription
設(shè)置渠道的描述信息失暴。
channel.setDescription("AAAAAAAAAA");//設(shè)置渠道的描述信息
一些定制手機(jī)將這個(gè)信息去除了坯门。
(8)setImportance
設(shè)置重要性。(在前面說過了)
(9)setLightColor
設(shè)置呼吸燈的顏色逗扒。
需要設(shè)備的支持古戴,有些手機(jī)呼吸燈只支持一種顏色。
(10)setName
設(shè)置渠道名稱矩肩。
channel.setName("wweqw");
(11)setSound
設(shè)置提示鈴聲现恼。
channel.setSound(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.publicnotify), new AudioAttributes.Builder().build());
(12)setVibrationPattern
設(shè)置震動(dòng)模式。
channel.setVibrationPattern(new long[]{200, 200, 1000, 200, 1000, 200});
(13)setLockscreenVisibility
設(shè)置鎖屏的情況下是否顯示通知。
需要注意的是:該方法是無法生效的叉袍,只能被系統(tǒng)或者排序排序服務(wù)所更改始锚。
app只要使用
//鎖屏?xí)r顯示通知
builder.setPublicVersion(notification);
即可。
數(shù)字角標(biāo)
隨著國內(nèi)定制手機(jī)的大量出現(xiàn)喳逛,Launcher上的角標(biāo)問題越來越棘手瞧捌。
即使我們在代碼中添加了setBadgeIconType、setShortcutId润文、channel.setShowBadge之類的配置也沒有用姐呐。
在網(wǎng)上找了些框架,比如
https://github.com/leolin310148/ShortcutBadger典蝌,其實(shí)也有時(shí)問題的皮钠,并不能適配所有的機(jī)型,這也體現(xiàn)了國內(nèi)設(shè)備的惡心之處赠法。
大家先關(guān)注一下吧麦轰,目前好幾款手機(jī)都測試OK的。
這里有一篇文章:
[貝聊科技]有關(guān)Android應(yīng)用桌面角標(biāo)(BadgeNumber)實(shí)現(xiàn)的探討
這篇文章算是比較好的了砖织,大家可以去看看款侵,oppo手機(jī)的角標(biāo)我試了,有用侧纯。
由于缺少其他機(jī)型的手機(jī)新锈,所以就沒有嘗試了。
另外眶熬,有關(guān)角標(biāo)妹笆,有一點(diǎn)最最重要
,好多定制手機(jī)做了通知角標(biāo)白名單
娜氏,只有將你app的包名放入定制手機(jī)的 白名單
里面才可以顯示角標(biāo)拳缠,“com.xunmeng.pinduoduo”這個(gè)包名已被大部分定制手機(jī)假如白名單,大家可以將包名改成這個(gè)試試贸弥。實(shí)在不行大家就在網(wǎng)上搜搜QQ和微信的包名是什么窟坐,然后將自己app的包名改掉就行了。
最后附上通知適配的通用寫法:
int index = 0;
/**
* 彈出通知提醒
*/
private void tapNotification(){
index = index +1 ;
NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
//準(zhǔn)備intent
Intent clickIntent = new Intent(this, NotificationBroadcastReceiver.class);
clickIntent.setAction("com.xxx.xxx.click");
// 構(gòu)建 PendingIntent
PendingIntent clickPI = PendingIntent.getBroadcast(this, 1, clickIntent, PendingIntent.FLAG_CANCEL_CURRENT);
//準(zhǔn)備intent
Intent cacelIntent = new Intent(this, NotificationBroadcastReceiver.class);
cacelIntent.setAction("com.xxx.xxx.cancel");
// 構(gòu)建 PendingIntent
PendingIntent cacelPI = PendingIntent.getBroadcast(this, 2, cacelIntent, PendingIntent.FLAG_CANCEL_CURRENT );
//準(zhǔn)備intent
Intent fullscreenIntent = new Intent(this, NotificationBroadcastReceiver.class);
fullscreenIntent.setAction("com.xxx.xxx.fullscreen");
// 構(gòu)建 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 = "標(biāo)題"+index;
String conttext = "我是一個(gè)通知"+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)//設(shè)置通知標(biāo)題
.setContentText(conttext)//設(shè)置通知內(nèi)容
.setContentIntent(clickPI)// 設(shè)置pendingIntent,點(diǎn)擊通知時(shí)就會(huì)用到
.setAutoCancel(true)//設(shè)為true绵疲,點(diǎn)擊通知欄移除通知
.setDeleteIntent(cacelPI)//設(shè)置pendingIntent,左滑右滑通知時(shí)就會(huì)用到
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.shennvguo2))//設(shè)置大圖標(biāo)
.setNumber(index)//顯示在右邊的數(shù)字
.setOngoing(false)//設(shè)置是否是正在進(jìn)行中的通知哲鸳,默認(rèn)是false
.setOnlyAlertOnce(false)//設(shè)置是否只通知一次
.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秒,然后震動(dòng)1000ms盔憨,再延遲500ms徙菠,接著震動(dòng)700ms,最后再延遲500ms,接著震動(dòng)300ms郁岩。
.setLights(Color.RED,2000,Color.BLUE)
//.setDefaults(Notification.DEFAULT_LIGHTS)
.setSubText("我是一個(gè)SubText")
.setTicker("通知測試")//提示
.setUsesChronometer(true)
.setWhen(System.currentTimeMillis())
.setLocalOnly(true)//設(shè)置此通知是否僅與當(dāng)前設(shè)備相關(guān)婿奔。如果設(shè)置為true缺狠,通知就不能橋接到其他設(shè)備上進(jìn)行遠(yuǎn)程顯示。
.setShowWhen(true);
if(index % 5 == 0){
builder.setSortKey("A");//設(shè)置針對一個(gè)包內(nèi)的通知進(jìn)行排序的鍵值
}else if(index % 5 == 1){
builder.setSortKey("B");//設(shè)置針對一個(gè)包內(nèi)的通知進(jìn)行排序的鍵值
}else if(index % 5 == 2){
builder.setSortKey("C");//設(shè)置針對一個(gè)包內(nèi)的通知進(jìn)行排序的鍵值
}else if(index % 5 == 3){
builder.setSortKey("D");//設(shè)置針對一個(gè)包內(nèi)的通知進(jìn)行排序的鍵值
}else if(index % 5 == 4){
builder.setSortKey("E");//設(shè)置針對一個(gè)包內(nèi)的通知進(jìn)行排序的鍵值
}
//響應(yīng)緊急狀態(tài)的全屏事件(例如來電事件)脸秽,也就是說通知來的時(shí)候儒老,跳過在通知區(qū)域點(diǎn)擊通知這一步,直接執(zhí)行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)//設(shè)置通知的布局
.setCustomHeadsUpContentView(remoteViews)//設(shè)置懸掛通知的布局
.setCustomContentView(remoteViews);
//builder.setChronometerCountDown()//已舍棄
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {//Android7.0以上
// if(index == 1){
// builder.setGroupSummary(true);//設(shè)置是否為一組通知的第一個(gè)顯示
// }
// builder.setGroup("notification_test");//捆綁通知
//準(zhǔn)備intent
Intent replyPendingIntent = new Intent(this, NotificationBroadcastReceiver.class);
replyPendingIntent.setAction("com.xxx.xxx.replypending");
replyPendingIntent.putExtra("messageId", index);
// 構(gòu)建 PendingIntent
PendingIntent replyPendingPI = PendingIntent.getBroadcast(this, 2, replyPendingIntent, PendingIntent.FLAG_UPDATE_CURRENT );
builder.setRemoteInputHistory(new String[]{"這條通知可以點(diǎn)擊下面按鈕直接回復(fù)..."});
//創(chuàng)建一個(gè)可添加到通知操作的 RemoteInput.Builder 實(shí)例记餐。 該類的構(gòu)造函數(shù)接受系統(tǒng)用作文本輸入密鑰的字符串驮樊。 之后,手持式設(shè)備應(yīng)用使用該密鑰檢索輸入的文本片酝。
RemoteInput remoteInput = new RemoteInput.Builder("key_text_reply")
.setLabel("回復(fù)")
.build();
//使用 addRemoteInput() 向操作附加 RemoteInput 對象囚衔。
NotificationCompat.Action action = new NotificationCompat.Action.Builder(R.mipmap.shennvguo2, "點(diǎn)擊直接回復(fù)", replyPendingPI)
.addRemoteInput(remoteInput)
.build();
//對通知應(yīng)用操作。
builder.addAction(action);
}
//builder.setBadgeIconType(NotificationCompat.BADGE_ICON_NONE);//設(shè)置角標(biāo)類型(無效)
//builder.setSettingsText();已舍棄
//builder.setShortcutId("100");
//builder.setColorized(true);//啟用通知的背景顏色設(shè)置
//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);//顯示通知角標(biāo)
//boolean aa = channel.canShowBadge();
//channel.setBypassDnd(true);// 設(shè)置繞過請勿打擾模式
//boolean ca = channel.canBypassDnd();
channel.enableLights(true);//設(shè)置通知出現(xiàn)時(shí)的閃燈(如果 android 設(shè)備支持的話)
channel.enableVibration(true);// 設(shè)置通知出現(xiàn)時(shí)的震動(dòng)(如果 android 設(shè)備支持的話)
channel.setDescription("AAAAAAAAAA");//設(shè)置渠道的描述信息
//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);
//創(chuàng)建通知時(shí)指定channelID
builder.setChannelId(channelID);
//builder.setTimeoutAfter(5000);//設(shè)置超時(shí)時(shí)間雕沿,超時(shí)之后自動(dòng)取消(Android8.0有效)
}
Notification notification = builder.build();
//鎖屏?xí)r顯示通知
builder.setPublicVersion(notification);
notificationManager.notify(index, notification);
}
PS:
如果使用Notification.Builder练湿,那么會(huì)遇到好多兼容性問題,以上代碼的適配方案肯定行不通审轮。
后來Google為了解決兼容性問題肥哎,將NotificationCompat.Builder替代Notification.Builder, 使用NotificationCompat.Builder不需要過多考慮適配問題疾渣,直接使用以上適配方案即可篡诽。