1. 程式人生 > >Android 桌面角標在各大品牌機型上的實現

Android 桌面角標在各大品牌機型上的實現

由於角標在Android原生的系統中沒有支援,所以各個Android手機廠商各自為政。

正如很多資料所說,這一功能完全是效仿IOS,Android本不存在的,對於不支援的廠商如魅族、中興、酷派,必須為他們不盲目跟風而點贊。

做起適配來,真的很麻煩,要針對各個廠商逐個去寫以及測試。

目前做到支援小米、華為、三星、LG、VIVO、ZUK、HTC、NOVA等廠商的Andorid系統

效果如下圖所示


特別說明一下小米自MIUI6.0以後,角標的顯示和通知欄Notification綁在一起。目前我發現的做法,就只有小米需要和Notification綁在一起才能生效。

不過我在這裡的例子因產品需求,全部機型的做法都把Notification綁上。

訊息通知ID

private int MQTT_IM_NOTIFICATION_ID=1007;


通知欄Notification的定義

        String content = 2 + "個聯絡人發了" + i + "條訊息";
        NotificationCompat.Builder builder = new NotificationCompat.Builder(getBaseContext());
        builder.setSmallIcon(R.drawable.chat_notify_icon);
        builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
        builder.setTicker("收到" + i + "條訊息");
        builder.setWhen(System.currentTimeMillis());
        Intent intent = new Intent(getBaseContext(), MainActivity.class);

        intent.setAction(getApplicationContext().getPackageName());
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        builder.setContentIntent(pi);
        builder.setContentTitle(getResources().getText(R.string.app_name));
        builder.setContentText(content);

        final Notification n = builder.build();
        int defaults = Notification.DEFAULT_LIGHTS;

        defaults |= Notification.DEFAULT_SOUND;

        defaults |= Notification.DEFAULT_VIBRATE;


        n.defaults = defaults;
        n.flags = Notification.FLAG_SHOW_LIGHTS | Notification.FLAG_AUTO_CANCEL;


廠商

    private static String SYSTEM_XIAOMI="XIAOMI";
    private static String SYSTEM_SAMSUNG="SAMSUNG";
    private static String SYSTEM_HUAWEI_HONOR="HONOR";
    private static String SYSTEM_HUAWEI="HUAWEI";
    private static String SYSTEM_NOVA="NOVA";
    private static String SYSTEM_SONY="SONY";
    private static String SYSTEM_VIVO="VIVO";
    private static String SYSTEM_OPPO="OPPO";
    private static String SYSTEM_LG="LG";
    private static String SYSTEM_ZUK="ZUK";
    private static String SYSTEM_HTC="HTC";


廠商獲取

        OSName=android.os.Build.BRAND.trim().toUpperCase();


類名的獲取

主要是得到Activity名字,得到完整的包名、類名

    //獲取類名
    public static String getLauncherClassName(Context context) {
        PackageManager packageManager = context.getPackageManager();
        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.setPackage(context.getPackageName());
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        ResolveInfo info = packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
        if (info == null) {
            info = packageManager.resolveActivity(intent, 0);
        }
        return info.activityInfo.name;
    }


廣播

    //廣播
    public static boolean canResolveBroadcast(Context context, Intent intent) {
        PackageManager packageManager = context.getPackageManager();
        List<ResolveInfo> receivers = packageManager.queryBroadcastReceivers(intent, 0);
        return receivers != null && receivers.size() > 0;
    }


小米

特別注意,小米的通知欄提示需要延時操作才會出現角標,但是偶爾還是沒法出現,暫時沒有特別好的解決辦法,不過目前能保證做到較高的成功率。

除了小米以外,其他實現基本沒什麼問題。

    //小米
    private static void setBadgeOfXiaomi(final Context context,final Notification notification,final int NOTIFI_ID,final int  num){


        new Handler().postDelayed(new Runnable() {

            @Override
            public void run() {


                try {

                    Field field = notification.getClass().getDeclaredField("extraNotification");

                    Object extraNotification = field.get(notification);

                    Method method = extraNotification.getClass().getDeclaredMethod("setMessageCount", int.class);

                    method.invoke(extraNotification, num);

                } catch (Exception e) {

                    e.printStackTrace();
                    Log.e("Xiaomi" + " Badge error", "set Badge failed");

                }

//                mNotificationManager.notify(0,notification);
                NotificationManager notifyMgr = (NotificationManager)(context.getSystemService(NOTIFICATION_SERVICE));
                if(num!=0)notifyMgr.notify(NOTIFI_ID, notification);else notifyMgr.cancel(NOTIFI_ID);


            }
        },550);

    }


三星 & LG

   //三星和LG
    private static void setBadgeOfSamsung(Context context,Notification notification, int NOTIFI_ID,int num) {
        // 獲取你當前的應用
        String launcherClassName = getLauncherClassName(context);
        if (launcherClassName == null) {
            return;
        }

        try {
            Intent intent = new Intent("android.intent.action.BADGE_COUNT_UPDATE");
            intent.putExtra("badge_count", num);
            intent.putExtra("badge_count_package_name", context.getPackageName());
            intent.putExtra("badge_count_class_name", launcherClassName);
            context.sendBroadcast(intent);

            NotificationManager notifyMgr = (NotificationManager)(context.getSystemService(NOTIFICATION_SERVICE));
            if(num!=0)notifyMgr.notify(NOTIFI_ID, notification);else notifyMgr.cancel(NOTIFI_ID);


        }catch (Exception e){
            e.printStackTrace();
            Log.e("SAMSUNG" + " Badge error", "set Badge failed");
        }
    }


華為

華為及其榮耀系列通用,不需要官網認證

    //華為 系列
    private static void setBadgeOfHuaWei(Context context, Notification notification,int NOTIFI_ID,int num) {


        try{
            Bundle localBundle = new Bundle();
            localBundle.putString("package", context.getPackageName());
            localBundle.putString("class", getLauncherClassName(context));
            localBundle.putInt("badgenumber", num);
            context.getContentResolver().call(Uri.parse("content://com.huawei.android.launcher.settings/badge/"), "change_badge", null, localBundle);

            NotificationManager notifyMgr = (NotificationManager)(context.getSystemService(NOTIFICATION_SERVICE));
            if(num!=0)notifyMgr.notify(NOTIFI_ID, notification);else notifyMgr.cancel(NOTIFI_ID);
        }catch(Exception e){
            e.printStackTrace();
            Log.e("HUAWEI" + " Badge error", "set Badge failed");
        }

}
索尼
    //索尼
    private static void setBadgeOfSony(Context context,Notification notification,int NOTIFI_ID, int num){
        String numString="";
        String activityName = getLauncherClassName(context);
        if (activityName == null){
            return;
        }
        Intent localIntent = new Intent();
//        int numInt = Integer.valueOf(num);
        boolean isShow = true;
        if (num < 1){
            numString = "";
            isShow = false;
        }else if (num > 99){
            numString = "99";
        }

        try {
            localIntent.putExtra("com.sonyericsson.home.intent.extra.badge.SHOW_MESSAGE", isShow);
            localIntent.setAction("com.sonyericsson.home.action.UPDATE_BADGE");
            localIntent.putExtra("com.sonyericsson.home.intent.extra.badge.ACTIVITY_NAME", activityName);
            localIntent.putExtra("com.sonyericsson.home.intent.extra.badge.MESSAGE", numString);
            localIntent.putExtra("com.sonyericsson.home.intent.extra.badge.PACKAGE_NAME", context.getPackageName());
            context.sendBroadcast(localIntent);

            NotificationManager notifyMgr = (NotificationManager)(context.getSystemService(NOTIFICATION_SERVICE));
            if(num!=0)notifyMgr.notify(NOTIFI_ID, notification);else notifyMgr.cancel(NOTIFI_ID);


        }catch (Exception e){
            e.printStackTrace();
            Log.e("SONY" + " Badge error", "set Badge failed");
        }
    }

VIVO

    //VIVO
    private static void setBadgeOfVIVO(Context context,Notification notification,int NOTIFI_ID,int num){
        try {
            Intent localIntent = new Intent("launcher.action.CHANGE_APPLICATION_NOTIFICATION_NUM");
            localIntent.putExtra("packageName", context.getPackageName());
            localIntent.putExtra("className", getLauncherClassName(context));
            localIntent.putExtra("notificationNum", num);
            context.sendBroadcast(localIntent);

            NotificationManager notifyMgr = (NotificationManager)(context.getSystemService(NOTIFICATION_SERVICE));
            if(num!=0)notifyMgr.notify(NOTIFI_ID, notification);else notifyMgr.cancel(NOTIFI_ID);

        }catch (Exception e){
            e.printStackTrace();
            Log.e("VIVO" + " Badge error", "set Badge failed");
        }
    }


OPPO

目前只支援部分機型

   //OPPO *只支援部分機型
    private static void setBadgeOfOPPO(Context context, Notification notification,int NOTIFI_ID,int num){
        try {

            if (num == 0) {
                num = -1;
            }

            Intent intent = new Intent("com.oppo.unsettledevent");
            intent.putExtra("pakeageName", context.getPackageName());
            intent.putExtra("number", num);
            intent.putExtra("upgradeNumber", num);
            if (canResolveBroadcast(context, intent)) {
                context.sendBroadcast(intent);
            } else {

                    try {
                        Bundle extras = new Bundle();
                        extras.putInt("app_badge_count", num);
                        context.getContentResolver().call(Uri.parse("content://com.android.badge/badge"), "setAppBadgeCount", null, extras);

                        NotificationManager notifyMgr = (NotificationManager)(context.getSystemService(NOTIFICATION_SERVICE));
                        if(num!=0)notifyMgr.notify(NOTIFI_ID, notification);else notifyMgr.cancel(NOTIFI_ID);


                    } catch (Throwable th) {
                        Log.e("OPPO" + " Badge error", "unable to resolve intent: " + intent.toString());
                    }
            }

        }catch (Exception e){
            e.printStackTrace();
            Log.e("OPPO" + " Badge error", "set Badge failed");
        }
    }


ZUK
   //ZUK
    private static void setBadgeOfZUK(Context context,Notification notification,int NOTIFI_ID, int num){
         final Uri CONTENT_URI = Uri.parse("content://com.android.badge/badge");
        try {
            Bundle extra = new Bundle();
            extra.putInt("app_badge_count", num);
            context.getContentResolver().call(CONTENT_URI, "setAppBadgeCount", null, extra);

            NotificationManager notifyMgr = (NotificationManager)(context.getSystemService(NOTIFICATION_SERVICE));
            if(num!=0)notifyMgr.notify(NOTIFI_ID, notification);else notifyMgr.cancel(NOTIFI_ID);


        }catch (Exception e){
            e.printStackTrace();
            Log.e("ZUK" + " Badge error", "set Badge failed");
        }

    }


HTC
    //HTC
    private static void setBadgeOfHTC(Context context,Notification notification,int NOTIFI_ID,int num){

        try {
            Intent intent1 = new Intent("com.htc.launcher.action.SET_NOTIFICATION");
            intent1.putExtra("com.htc.launcher.extra.COMPONENT", context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()).getComponent().flattenToShortString());
            intent1.putExtra("com.htc.launcher.extra.COUNT", num);

            Intent intent = new Intent("com.htc.launcher.action.UPDATE_SHORTCUT");
            intent.putExtra("packagename", context.getPackageName());
            intent.putExtra("count", num);

            if (canResolveBroadcast(context, intent1) || canResolveBroadcast(context, intent)) {
                context.sendBroadcast(intent1);
                context.sendBroadcast(intent);
            } else {
                Log.e("HTC" + " Badge error", "unable to resolve intent: " + intent.toString());
            }

            NotificationManager notifyMgr = (NotificationManager)(context.getSystemService(NOTIFICATION_SERVICE));
            if(num!=0)notifyMgr.notify(NOTIFI_ID, notification);else notifyMgr.cancel(NOTIFI_ID);


        }catch (Exception e){
            e.printStackTrace();
            Log.e("HTC" + " Badge error", "set Badge failed");
        }

    }


NOVA

    //NOVA
    private static void setBadgeOfNOVA(Context context,Notification notification,int NOTIFI_ID,int num){
        try{
            ContentValues contentValues = new ContentValues();
            contentValues.put("tag", context.getPackageName()+ "/" +getLauncherClassName(context));
            contentValues.put("count", num);
            context.getContentResolver().insert(Uri.parse("content://com.teslacoilsw.notifier/unread_count"), contentValues);

            NotificationManager notifyMgr = (NotificationManager)(context.getSystemService(NOTIFICATION_SERVICE));
            if(num!=0)notifyMgr.notify(NOTIFI_ID, notification);else notifyMgr.cancel(NOTIFI_ID);


        }catch (Exception e){
            e.printStackTrace();
            Log.e("NOVA" + " Badge error", "set Badge failed");
        }
    }


其他

做個備案吧,這個真不一定能生效,只能從大多數的做法裡摸規律

    //其他
    private static void setBadgeOfDefault(Context context,Notification notification,int NOTIFI_ID,int num){

        try {
            Intent intent = new Intent("android.intent.action.BADGE_COUNT_UPDATE");
            intent.putExtra("badge_count", num);
            intent.putExtra("badge_count_package_name", context.getPackageName());
            intent.putExtra("badge_count_class_name", getLauncherClassName(context));
            if (canResolveBroadcast(context, intent)) {
                context.sendBroadcast(intent);
            } else {
                Log.e("Default" + " Badge error", "unable to resolve intent: " + intent.toString());
            }

            NotificationManager notifyMgr = (NotificationManager)(context.getSystemService(NOTIFICATION_SERVICE));
            if(num!=0)notifyMgr.notify(NOTIFI_ID, notification);else notifyMgr.cancel(NOTIFI_ID);


        }catch (Exception e){
            e.printStackTrace();
                Log.e("Default" + " Badge error", "set Badge failed");
        }

    }

github :  https://github.com/Cedric-Xuan/SNSNotificationBadge