Android 8.0+(一) 通知欄適配

    對於通知欄,大家都不陌生,應該算是設備的基礎功能組件了吧,像推送消息,任務提醒,鬧鐘提示等等都需要藉助設備的通知欄展現給用戶,所以說一個醒目且友好的通知是很重要的,但是在這個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)//通知展開時顯示的大圖
);

最後來看下實現的效果吧

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章