1. 程式人生 > >史上最全Android應用角標適配方法

史上最全Android應用角標適配方法

Android 8.0之前原生是不支援應用角標的,是各個手機廠商自己在系統中實現的應用角標,並且部分廠商提供了設定的方式,所以需要對各個廠商的系統進行適配。

GitHub地址https://github.com/jimmysuncpt/AppBadge

下面是針對各個手機廠商的系統進行適配的原理。

目錄

0 公用方法

1 小米(支援)

2 華為(支援)

3 OPPO(不支援)

4 vivo(不支援)

5 三星(支援)

6 魅族(不支援)

7 360(不支援)

8 錘子(不支援)

9 努比亞(不支援)

10 金立(不支援)

11 樂視(支援,無法自定義數目)

12 聯想ZUK(支援)

13 中興(不支援)

14 HTC(支援)

15 諾基亞(支援)

16 索尼(支援)

17 原生Android(部分支援,無法直接顯示數目)


0 公用方法

在下面的實現程式碼中,有很多公用的程式碼,我們提取出來一些公用方法,程式碼如下:

    private static String getLauncherClassName(Context context) {
        ComponentName launchComponent = getLauncherComponentName(context);
        if (launchComponent == null) {
            return "";
        } else {
            return launchComponent.getClassName();
        }
    }
 
    private static ComponentName getLauncherComponentName(Context context) {
        Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(context
                .getPackageName());
        if (launchIntent != null) {
            return launchIntent.getComponent();
        } else {
            return null;
        }
    }

1 小米(支援)

小米在MIUI6及以上版本中是通過傳送通知來設定角標的。當APP向通知欄傳送了一條通知 (通知不帶進度條並且使用者可以刪除的),那麼桌面APP icon角標就會顯示1。此時app顯示的角標數是和通知欄裡app傳送的通知數對應的,即向通知欄傳送了多少通知就會顯示多少角標。

可以通過反射機制來定義每次通知的訊息個數,應用的角標數為每條通知定義的通知個數的總和,如下圖所示:

我們傳送了兩條通知,一條通知為5個訊息,一條為10個訊息,應用角標顯示為15個。此時,如果使用者點選或移除掉5條訊息的那個通知,應用角標會變成10。

另外,僅在APP在後臺時收到通知會顯示角標,而APP在前臺時不會顯示,APP被殺掉後通知及角標消失。

實現程式碼

    public static boolean setNotificationBadge(int count, Context context) {
        NotificationManager notificationManager = (NotificationManager) context.getSystemService
                (Context.NOTIFICATION_SERVICE);
        if (notificationManager == null) {
            return false;
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            // 8.0之後新增角標需要NotificationChannel
            NotificationChannel channel = new NotificationChannel("badge", "badge",
                    NotificationManager.IMPORTANCE_DEFAULT);
            channel.setShowBadge(true);
            notificationManager.createNotificationChannel(channel);
        }
        Intent intent = new Intent(context, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
        Notification notification = new NotificationCompat.Builder(context, "badge")
                .setContentTitle("應用角標")
                .setContentText("您有" + count + "條未讀訊息")
                .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap
                        .ic_launcher))
                .setSmallIcon(R.mipmap.ic_launcher_round)
                .setAutoCancel(true)
                .setContentIntent(pendingIntent)
                .setChannelId("badge")
                .setNumber(count)
                .setBadgeIconType(NotificationCompat.BADGE_ICON_SMALL).build();
        // 小米
        try {
            Field field = notification.getClass().getDeclaredField("extraNotification");
            Object extraNotification = field.get(notification);
            Method method = extraNotification.getClass().getDeclaredMethod("setMessageCount", int
                    .class);
            method.invoke(extraNotification, count);
        } catch (Exception e) {
            e.printStackTrace();
        }
        notificationManager.notify(notificationId++, notification);
        return true;
    }

參考連結

https://dev.mi.com/docs/appsmarket/technical_docs/badge/

https://dev.mi.com/console/doc/detail?pId=939

測試結果

小米6、小米5S、小米MIX、小米5X、小米4、紅米Note 4X、小米2S均可通過通知的方式設定角標。

2 華為(支援)

可以通過ContentResolver方法直接設定應用角標,且應用在前臺和被殺掉後仍可顯示。

實現程式碼

    private static boolean setHuaweiBadge(int count, Context context) {
        try {
            String launchClassName = getLauncherClassName(context);
            if (TextUtils.isEmpty(launchClassName)) {
                return false;
            }
            Bundle bundle = new Bundle();
            bundle.putString("package", context.getPackageName());
            bundle.putString("class", launchClassName);
            bundle.putInt("badgenumber", count);
            context.getContentResolver().call(Uri.parse("content://com.huawei.android.launcher" +
                    ".settings/badge/"), "change_badge", null, bundle);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

參考連結

https://developer.huawei.com/consumer/cn/devservice/doc/30802

測試結果

榮耀8、華為P10、華為Mate10、華為麥芒(MLA-AL00)均可直接設定。

3 OPPO(不支援)

舊款的OPPO手機有兩種方法設定,沒有測試機測試,不知道是否可行,實現程式碼如下:

    private static boolean setOPPOBadge(int count, Context context) {
        try {
            Bundle extras = new Bundle();
            extras.putInt("app_badge_count", count);
            context.getContentResolver().call(Uri.parse("content://com.android.badge/badge"),
                    "setAppBadgeCount", String.valueOf(count), extras);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    private static boolean setOPPOBadge2(int count, Context context) {
        try {
            Intent intent = new Intent("com.oppo.unsettledevent");
            intent.putExtra("packageName", context.getPackageName());
            intent.putExtra("number", count);
            intent.putExtra("upgradeNumber", count);
            PackageManager packageManager = context.getPackageManager();
            List<ResolveInfo> receivers = packageManager.queryBroadcastReceivers(intent, 0);
            if (receivers != null && receivers.size() > 0) {
                context.sendBroadcast(intent);
            } else {
                Bundle extras = new Bundle();
                extras.putInt("app_badge_count", count);
                context.getContentResolver().call(Uri.parse("content://com.android.badge/badge"),
                        "setAppBadgeCount", null, extras);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

新款的OPPO僅支援內建應用、微信和QQ顯示角標,若要使用角標功能,必須提交申請,稽核通過了才能開放,官方給的具體稽核標準如下:

申請角標接入規則(應用必須適配OPPO手機,保證角標功能測試通過)

a) 系統應用;

b) 國內外各區域使用者量排名Top5的三方即時通訊類應用,且只允許顯示即時通訊訊息類通知(如QQ、微信、facebook、line);

c) OPPO公司內部費商業化及運營性質的辦公型別即時通訊應用(如Teamtalk);

d) 國內外郵件類應用(各區域各屬於使用者量第一梯隊的應用)。

4 vivo(不支援)

舊款的vivo手機實現程式碼:

    private static boolean setVivoBadge(int count, Context context) {
        try {
            String launcherClassName = getLauncherClassName(context);
            if (TextUtils.isEmpty(launcherClassName)) {
                return false;
            }
            Intent intent = new Intent("launcher.action.CHANGE_APPLICATION_NOTIFICATION_NUM");
            intent.putExtra("packageName", context.getPackageName());
            intent.putExtra("className", launcherClassName);
            intent.putExtra("notificationNum", count);
            context.sendBroadcast(intent);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

新款的手機也不可行了,如下圖:

5 三星(支援)

可以通過廣播機制直接設定應用角標,且應用在前臺和被殺掉後仍可顯示。

實現程式碼

    private static boolean setSamsungBadge(int count, Context context) {
        try {
            String launcherClassName = getLauncherClassName(context);
            if (TextUtils.isEmpty(launcherClassName)) {
                return false;
            }
            Intent intent = new Intent("android.intent.action.BADGE_COUNT_UPDATE");
            intent.putExtra("badge_count", count);
            intent.putExtra("badge_count_package_name", context.getPackageName());
            intent.putExtra("badge_count_class_name", launcherClassName);
            context.sendBroadcast(intent);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

測試結果

三星S9+:需和通知的方式結合才能顯示角標。

三星 Galaxy S6 edge:可直接設定。

6 魅族(不支援)

官方不支援。

7 360(不支援)

目前可能僅支援系統應用、微信和QQ,不支援支付寶,未找到設定角標相關文件。

8 錘子(不支援)

目前僅支援系統應用和微信,甚至不支援QQ。

9 努比亞(不支援)

目前僅支援系統應用。

10 金立(不支援)

找不到相關文件。

11 樂視(支援,無法自定義數目)

僅支援通過通知設定角標,且角標數字為收到通知的條數,無法自定義角標數目。

測試結果

樂2 Pro:可通過通知方式設定。

12 聯想ZUK(支援)

實現程式碼

    private static boolean setZukBadge(int count, Context context) {
        try {
            Bundle extra = new Bundle();
            ArrayList<String> ids = new ArrayList<>();
            // 以列表形式傳遞快捷方式id,可以新增多個快捷方式id
//        ids.add("custom_id_1");
//        ids.add("custom_id_2");
            extra.putStringArrayList("app_shortcut_custom_id", ids);
            extra.putInt("app_badge_count", count);
            Uri contentUri = Uri.parse("content://com.android.badge/badge");
            Bundle bundle = context.getContentResolver().call(contentUri, "setAppBadgeCount", null,
                    extra);
            return bundle != null;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

參考連結

http://developer.zuk.com/detail/12

暫無測試機測試

13 中興(不支援)

目前僅支援系統應用和微信,甚至不支援QQ。

14 HTC(支援)

可通過廣播機制直接設定角標。

實現程式碼

    private static boolean setHTCBadge(int count, Context context) {
        try {
            ComponentName launcherComponentName = getLauncherComponentName(context);
            if (launcherComponentName == null) {
                return false;
            }
 
            Intent intent1 = new Intent("com.htc.launcher.action.SET_NOTIFICATION");
            intent1.putExtra("com.htc.launcher.extra.COMPONENT", launcherComponentName
                    .flattenToShortString());
            intent1.putExtra("com.htc.launcher.extra.COUNT", count);
            context.sendBroadcast(intent1);
 
            Intent intent2 = new Intent("com.htc.launcher.action.UPDATE_SHORTCUT");
            intent2.putExtra("packagename", launcherComponentName.getPackageName());
            intent2.putExtra("count", count);
            context.sendBroadcast(intent2);
 
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

測試結果

HTC D820u、HTC M8St可直接設定

15 諾基亞(支援)

可通過通知設定角標數量,和小米類似,不同之處是隻要通知欄的通知一直存在,數字就一直存在,且應用在前臺仍可通過通知設定。

實現程式碼

與小米實現程式碼相同。

測試結果

諾基亞7:可通過通知設定。

16 索尼(支援)

實現程式碼

    private static boolean setSonyBadge(int count, Context context) {
        String launcherClassName = getLauncherClassName(context);
        if (TextUtils.isEmpty(launcherClassName)) {
            return false;
        }
        try {
            //官方給出方法
            ContentValues contentValues = new ContentValues();
            contentValues.put("badge_count", count);
            contentValues.put("package_name", context.getPackageName());
            contentValues.put("activity_name", launcherClassName);
            SonyAsyncQueryHandler asyncQueryHandler = new SonyAsyncQueryHandler(context
                    .getContentResolver());
            asyncQueryHandler.startInsert(0, null, Uri.parse("content://com.sonymobile.home" +
                    ".resourceprovider/badge"), contentValues);
            return true;
        } catch (Exception e) {
            try {
                //網上大部分使用方法
                Intent intent = new Intent("com.sonyericsson.home.action.UPDATE_BADGE");
                intent.putExtra("com.sonyericsson.home.intent.extra.badge.SHOW_MESSAGE", count > 0);
                intent.putExtra("com.sonyericsson.home.intent.extra.badge.ACTIVITY_NAME",
                        launcherClassName);
                intent.putExtra("com.sonyericsson.home.intent.extra.badge.MESSAGE", String
                        .valueOf(count));
                intent.putExtra("com.sonyericsson.home.intent.extra.badge.PACKAGE_NAME", context
                        .getPackageName());
                context.sendBroadcast(intent);
                return true;
            } catch (Exception e1) {
                e1.printStackTrace();
                return false;
            }
        }
    }
 
    static class SonyAsyncQueryHandler extends AsyncQueryHandler {
        SonyAsyncQueryHandler(ContentResolver cr) {
            super(cr);
        }
    }

參考連結

https://github.com/sonyxperiadev/home-badge

暫無測試機測試

17 原生Android(部分支援,無法直接顯示數目)

Android 8.0及之後的版本Google官方API支援通過傳送系統通知的方式設定應用角標,但是不支援顯示數量,而是一個小點兒,如下圖所示。

在傳送通知時可以設定訊息數量,部分手機在長按圖示時會顯示所有通知設定的數量的總和。如上圖所示,該示例中我們傳送了兩條通知,一條設定訊息數量為88,一條為12,所以總和顯示為100。

實現程式碼

與小米實現程式碼相同。

參考連結

https://developer.android.com/training/notify-user/badges

測試結果

Pixel 2 XL(Android 9.0):支援通知設定。

Nexus 6P(Android 8.1.0)、Nexus 5X(Android 8.1.0):不支援。

一加OnePlus3(Android 8.0.0):支援通知設定,但是長按圖示不會顯示數量。