Android開發筆記(一百六十八)爲應用綁定通知渠道並展示消息角標

爲了分清消息通知的輕重緩急,從Android8開始新增了通知渠道,並且必須指定通知渠道才能正常推送消息。一個應用允許擁有多個通知渠道,每個渠道的重要性各不相同,有的渠道消息在通知欄被摺疊成小行,有的渠道消息在通知欄展示完整的大行,有的渠道消息甚至會短暫懸浮於屏幕頂部,有的渠道消息在推送時會震動手機,有的渠道消息在推送時會發出鈴聲,有的渠道消息則完全靜默推送,這些提示差別都有賴於通知渠道的特徵管理。如果不考慮定製渠道特性,僅僅弄個默認渠道好推送消息,那麼只需以下三行代碼即可創建默認的通知渠道:

        // 從系統服務中獲取通知管理器
        NotificationManager notifyMgr = (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);
        // 創建指定編號、指定名稱、指定級別的通知渠道
        NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_DEFAULT);
        // 創建指定的通知渠道
        notifyMgr.createNotificationChannel(channel);

有了通知渠道之後,在推送消息之前使用該渠道創建對應的通知構造器,接着就能按照原方式推送消息了。使用通知渠道創建通知構造器的代碼示例如下:

        // 創建一個通知消息的構造器
        Notification.Builder builder = new Notification.Builder(this);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            // Android 8.0開始必須給每個通知分配對應的渠道
            builder = new Notification.Builder(this, channelId);
        }

當然以上代碼沒有指定通知渠道的具體特徵,消息通知的展示情況與提示方式完全按照系統默認的。若要個性化定製不同渠道的詳細特徵,就得單獨設置渠道對象的各特徵屬性。下面便是NotificationChannel提供的屬性設置方法說明:
setSound:設置推送通知之時的鈴聲,若設爲null表示靜音推送。
enableLights:推送消息時是否讓呼吸燈閃爍。
enableVibration:推送消息時是否讓手機震動。
setShowBadge:是否在應用圖標的右上角展示小紅點。
setLockscreenVisibility:設置鎖屏時候的可見性,可見性的取值說明有:VISIBILITY_PUBLIC顯示所有通知內容,Notification.VISIBILITY_PRIVATE只顯示標題,Notification.VISIBILITY_SECRET不顯示任何內容。
setImportance:設置通知渠道的重要性,其實NotificationChannel的構造方法已經傳入了重要性,所以該方法只在變更重要性時調用。重要性的取值說明包括:IMPORTANCE_MIN最小級別,IMPORTANCE_LOW低重要性,IMPORTANCE_DEFAULT默認重要性,IMPORTANCE_HIGH高重要性。

值得注意的是,每個通知渠道一經創建,就不可重複創建,即使創建也是做無用功。因此在創建渠道之前,最好先調用通知管理器的getNotificationChannel方法,判斷是否存在該編號的通知渠道,只有不存在的情況纔要創建通知渠道。下面是通知渠道的創建代碼例子:

    // 創建通知渠道。Android 8.0開始必須給每個通知分配對應的渠道
    public static void createNotifyChannel(Context ctx, String channelId, String channelName, int importance) {
        // 從系統服務中獲取通知管理器
        NotificationManager notifyMgr = (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);
        if (notifyMgr.getNotificationChannel(channelId) == null) { // 已經存在指定編號的通知渠道
            // 創建指定編號、指定名稱、指定級別的通知渠道
            NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);
            channel.setSound(null, null); // 設置推送通知之時的鈴聲。null表示靜音推送
            channel.enableLights(true); // 通知渠道是否讓呼吸燈閃爍
            channel.enableVibration(true); // 通知渠道是否讓手機震動
            channel.setShowBadge(true); // 通知渠道是否在應用圖標的右上角展示小紅點
            // VISIBILITY_PUBLIC顯示所有通知內容,Notification.VISIBILITY_PRIVATE只顯示標題,Notification.VISIBILITY_SECRET不顯示任何內容
            channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE); // 設置鎖屏時候的可見性
            channel.setImportance(importance); // 設置通知渠道的重要性級別
            // 創建指定的通知渠道
            notifyMgr.createNotificationChannel(channel);
        }
    }


儘管通知渠道提供了多種屬性設置方法,但真正常用的莫過於重要性這個特徵,各重要性對應的消息外觀從左到右分別如下圖所示,其中左圖爲IMPORTANCE_MIN最小級別時候的通知欄,中圖爲IMPORTANCE_DEFAULT默認重要性時候的通知欄,右圖爲IMPORTANCE_HIGH高重要性時候的頂部懸浮窗。


自從有了通知渠道,許多應用紛紛申請了多個渠道,每個渠道又有好幾條消息,加起來便是許多消息。這麼多的未讀消息,空間有限的通知欄已然不夠容納,於是各應用又希望向用戶提示未讀消息的數量,好讓用戶知曉有沒有未讀消息,還有幾條未讀消息。
原本通知渠道提供了setShowBadge方法,可設置是否在應用圖標的右上角展示小紅點(此紅點又稱消息角標),調用該方法設置true之後,有未讀消息時就顯示紅點,無未讀消息則不顯示紅點。然而setShowBadge方法在國產手機上並不奏效,原因有二:其一,該方法只顯示紅點未顯示數量;其二,該方法遲至Android8.0之後纔跟着通知渠道一起推出,衆多國內廠商等來不及故而早早推出了自己的紅點方案。時至今日,國產手機的四大廠商包括華爲、小米、OPPO、VIVO均推出了自己的消息角標方案,完全把Android官方的setShowBadge方法晾在一旁。國產手機的紅點方案參考了蘋果手機的紅點樣式,同樣把消息紅點放在桌面應用的右上角,並且紅點內部顯示當前未讀消息的數量(如下面左圖所示),而安卓官方的紅點內部不展示數字(如下面右圖所示)。

          
由於各廠商對消息角標的實現方案不盡相同,因此只能給他們的手機分別適配處理了。下面就以華爲和小米兩家的紅點方案爲例,依次介紹華爲系手機(含華爲與榮耀品牌)和小米系手機(含小米和紅米品牌)的適配編碼。
華爲的消息角標不依賴通知推送,允許單獨設置紅點的展示情況,主要通過內容解析器調用華爲內核的消息角標服務,詳細的角標顯示代碼示例如下:

    // 華爲的消息角標需要事先聲明兩個權限:INTERNET和CHANGE_BADGE
    private static void showBadgeOfEMUI(Context ctx, int count) {
        try {
            Bundle extra = new Bundle(); // 創建一個包裹對象
            extra.putString("package", BuildConfig.APPLICATION_ID); // 應用的包名
            extra.putString("class", BuildConfig.APPLICATION_ID+".MainActivity"); // 應用的首屏頁面路徑
            extra.putInt("badgenumber", count); // 應用的消息數量
            Uri uri = Uri.parse("content://com.huawei.android.launcher.settings/badge/");
            // 通過內容解析器調用華爲內核的消息角標服務
            ctx.getContentResolver().call(uri, "change_badge", null, extra);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

爲了合理使用魔改後的消息角標服務,華爲規定要在AndroidManifest.xml中聲明兩個權限配置,包括互聯網權限INTERNET,以及徽章修改權限CHANGE_BADGE,具體的權限配置代碼如下所示:

    <!-- 允許訪問互聯網 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <!-- 允許修改徽章(角標數字) -->
    <uses-permission android:name="com.huawei.android.launcher.permission.CHANGE_BADGE" />

至於小米的消息角標方案,則依賴於通知推送,必須在發送通知之時一起傳送消息數量參數。爲此小米給Notification類添加了一個新字段extraNotification,還添加了新方法setMessageCount,前者用於管理桌面上的消息角標,而後者能夠設置角標紅點的消息數量。下面是在小米手機上顯示消息角標的代碼例子:

    // 小米的消息角標需要在發送通知的時候一塊調用
    private static void showBadgeOfMIUI(int count, Notification notify) {
        try {
            // 利用反射技術獲得額外的新增字段extraNotification
            Field field = notify.getClass().getDeclaredField("extraNotification");
            // 該字段爲Notification類型,下面獲取它的實例對象
            Object extraNotification = field.get(notify);
            // 利用反射技術獲得額外的新增方法setMessageCount
            Method method = extraNotification.getClass().getDeclaredMethod("setMessageCount", int.class);
            // 利用反射技術調用實例對象的setMessageCount方法,設置角標紅點的消息數量
            method.invoke(extraNotification, count);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

綜合上述的兩種角標實現方案,形成以下的顯示角標代碼,可同時兼容華爲系手機和小米系手機:

    // 在桌面上的應用圖標右上角顯示數字角標
    public static void showMarkerCount(Context ctx, int count, Notification notify) {
        showBadgeOfEMUI(ctx, count); // 華爲手機EMUI系統的消息角標
        // 小米手機還要進入設置裏面的應用管理,開啓當前App的“顯示桌面圖標角標”
        showBadgeOfMIUI(count, notify); // 小米手機MIUI系統的消息角標
    }


不管是華爲方案還是小米方案,若想清除桌面上的應用紅線,只要調用上面方法設置消息數量爲0即可。兩種方案的角標效果如下圖所示,其中下面左圖爲華爲手機上的消息角標,下面右圖爲小米手機上的消息角標。

      



點此查看Android開發筆記的完整目錄

 

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