對於通知欄,大家都不陌生,應該算是設備的基礎功能組件了吧,像推送消息,任務提醒,鬧鐘提示等等都需要藉助設備的通知欄展現給用戶,所以說一個醒目且友好的通知是很重要的,但是在這個android生態比較混亂的環境下,很多亂七八糟的通知,我明明不想接收,卻見天兒的被各種app推送轟炸。
在Android 8.0 之前,有些做得好的廠商會針對每一個app提供一個通知的開關,但是這個權限被關了以後,就再也沒法接收到通知了,以致於後面app的任何通知都無法展現給用戶,除非用戶再次開啓app的通知開關。
也許Google意識到了這個問題,所以在Android 8.0上,NotificationChannel 應運而生。針對 targetSdkVersion在26以及上的設備,如果想要顯示app通知,必須要註冊對應通知的channel,一個app可以註冊多個channel,而用戶則可以自行設置某一個channel的開關狀態,如果某一個channel的通知被關閉,那麼該channel的任何通知都不會展現給用戶,而其他channel的通知則不受影響
一圖瞭解通知的基本組成
在Android 8.0之前,如果想將消息顯示在通知欄上面,基本上是先創建一個 Notification ,然後由NotificationManager直接show() 是沒有任何問題的
public void notify(int id) {
Notification notification = new NotificationCompat.Builder(this)
.setAutoCancel(true)
.setSmallIcon(getSmallIcon())
.setLargeIcon(getLargeIcon())
.setContentTitle(title)
.setContentText(body)
.setContentIntent(pendingIntent)
.build();
getManager().notify(id, notification);
}
但是如果在Android 8.0上執行這段代碼是不會顯示通知的,需要設置NotificationChannel纔可以 ,而且設置channel之前,必須先註冊channel
NotificationChannel channel = new NotificationChannel(
“DEFAULT_CHANNEL_ID”,
"推送通知",
NotificationManager.IMPORTANCE_HIGH
);
getManager().createNotificationChannel(channel);
可以看到,NotificationChannel構造方法有三個參數,NotificationChannel(String id, CharSequence name,int importance),
id:channel的唯一標示,同一app的不同channel ,id不能重複
name:channel的描述信息
importance:該channel通知的重要程度
最後通過NotificationManager註冊該channel, 注意: 必須在notify() 之前創建channel, 重複創建已有的channel不會有任何影響
現在,我們已經創建了一個channel,同樣的,android 8.0及以上和7.0及以下 創建Notification的方式也有區別
private NotificationCompat.Builder getNotificationBuilderByChannel(String channelId) {
NotificationCompat.Builder builder;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder = new NotificationCompat.Builder(getApplicationContext(), channelId);
} else {
builder = new NotificationCompat.Builder(this).setSound(soundUri);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {//8.0以下 && 7.0及以上 設置優先級
builder.setPriority(NotificationManager.IMPORTANCE_HIGH);
} else {
builder.setPriority(NotificationCompat.PRIORITY_HIGH);
}
}
return builder;
}
由於8.0以後,NotificationCompat.Builder(Context context) 已經被廢棄,所以創建方式還是採用最新的API比較好,雖然8.0以下並沒有channel之說,但你如果看下源碼,會發現其實NotificationCompat.Builder(Context context) 內部調用了NotificationCompat.Builder(Context context,String channelId) ,只不過channelId 傳入的是個null而已 , 所以現在來看NotificationCompat.Builder的創建方式是一樣的 。
/** @deprecated */
@Deprecated
public Builder(Context context) {
this(context, (String)null);
}
另外需要注意的是,各版本設置通知的優先級的方式也有所不同,8.0及以上通知的優先級是在channel中設置的,8.0以下優先級是在NotificationCompat.Builder中設置的
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(DEFAULT_CHANNEL,
"我的通知Channel", NotificationManager.IMPORTANCE_HIGH);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {//8.0以下 && 7.0及以上 設置優先級
builder.setPriority(NotificationManager.IMPORTANCE_HIGH);
} else {
builder.setPriority(NotificationCompat.PRIORITY_HIGH);
}
至於優先級中各個屬性的具體介紹,請參考Android官方文檔 android developers (不需要翻牆)
可能你也注意到了,爲什麼我只在8.0以下設置了.setSound(soundUri); 那麼 8.0+ 怎麼設置通知的聲音?
這是因爲8.0+ 是在創建channel的時候設置通知音效的
AudioAttributes att = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_NOTIFICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
.build();
NotificationChannel channel = new NotificationChannel(DEFAULT_CHANNEL,"我的通知
Channel", NotificationManager.IMPORTANCE_HIGH);
channel.setSound(soundUri, att);
getManager().createNotificationChannel(channel);
channel.setSound(soundUri, att); 除了設置音效的uri以外,還需要設置音頻屬性 ,這種方式有一種好處就是你可以給不同的channel設置不同的通知音效,如果沒有設置自定義的uri,則將使用手機默認的通知鈴聲
現在,我們的通知欄已經適配了各個版本的api ,但是在某些手機上(oppo。。。),在應用安裝完成以後,其通知默認是關閉狀態,此時我們可以通過api判斷通知開關是否開啓,以此引導用戶手動去設置中開啓通知
NotificationManagerCompat.from(context).areNotificationsEnabled();
你應該也注意到了,我這裏創建一個Notification使用的是NotificationCompat.Builder ,其實可以通過另一種方式 Notification.Builder 來創建 ,注意,這裏選擇前者的原因是NotificationCompat是兼容低版本的,而且內部幫我們做了一些api版本相關的封裝,這裏引用官網的一段文檔看下解釋
各版本的通知欄創建方式已經介紹完了,另外,自android8.0開始,支持在app啓動圖標上面顯示通知紅點,用戶可以長按應用程序圖標來查看該應用程序的通知。然後,用戶可以通過左右滑動來關閉或處理來自該菜單的通知。下面簡單介紹下如何在通知欄顯示大文本和大圖
通知欄顯示文本默認只能顯示一行,如果我們的文本太長了,將導致文本顯示不全(以...結尾),此時我們可以在創建Notification時設置通知顯示的樣式,以此來實現大文本的顯示
builder.setStyle(new NotificationCompat
.BigTextStyle()//大文本樣式
.setBigContentTitle(title)//通知展開時顯示的title
.bigText(body)//通知展開時顯示的全部文本
);
Android通知欄支持顯示大圖 ,但是隻能接收Bitmap類型的參數,所以如果你想要顯示網絡圖片的話,需要自行將圖片轉換爲Bitmap
builder.setStyle(new NotificationCompat
.BigPictureStyle()//大圖模式
.setBigContentTitle(title)
.bigLargeIcon(imgBitmap)////通知展開時顯示的縮略圖
.bigPicture(imgBitmap)//通知展開時顯示的大圖
);
最後來看下實現的效果吧