Android应用角标显示 android桌面角标_开发语言

 实现后的显示效果(由于角标功能由各个厂商自己实现的,所以各个厂商的实现方法不一样)

备注:小米系统在进入应用后会隐藏角标的显示,只有当退出到桌面时去设置角标才会显示

git项目地址badgeNumber: Android 通知栏提醒和桌面角标适配 (gitee.com)

1、先判断通知权限是否开启

private void initNoticePermission() {
        if (!NotifyManagerUtils.isNotifyEnabled(this)) {
            AlertDialog dialog = new AlertDialog.Builder(this)
                    .setMessage("当前通知权限未开启,是否前往打开")
                    .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {
                            NotifyManagerUtils.openNotificationSettingsForApp(MainActivity.this);
                        }
                    })
                    .setNegativeButton("取消", null)
                    .create();
            dialog.show();
        }
    }

上面用到的工具类


NotifyManagerUtils


import android.annotation.SuppressLint;
import android.app.AppOpsManager;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.os.Build;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 判断通知权限并跳转的工具类
 */
public class NotifyManagerUtils {
    private static final String CHECK_OP_NO_THROW = "checkOpNoThrow";
    private static final String OP_POST_NOTIFICATION = "OP_POST_NOTIFICATION";

    //调用该方法获取是否开启通知栏权限
    public static boolean isNotifyEnabled(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            return isEnableV26(context);
        } else {
            return isEnabledV19(context);
        }
    }

    /**
     * 8.0以下判断
     *
     * @param context api19  4.4及以上判断
     * @return
     */
    private static boolean isEnabledV19(Context context) {
        AppOpsManager mAppOps =
                (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
        ApplicationInfo appInfo = context.getApplicationInfo();
        String pkg = context.getApplicationContext().getPackageName();
        int uid = appInfo.uid;
        Class appOpsClass;
        try {
            appOpsClass = Class.forName(AppOpsManager.class.getName());
            Method checkOpNoThrowMethod =
                    appOpsClass.getMethod(CHECK_OP_NO_THROW,
                            Integer.TYPE, Integer.TYPE, String.class);
            Field opPostNotificationValue = appOpsClass.getDeclaredField(OP_POST_NOTIFICATION);
            int value = (Integer) opPostNotificationValue.get(Integer.class);
            return ((Integer) checkOpNoThrowMethod.invoke(mAppOps, value, uid, pkg) ==
                    AppOpsManager.MODE_ALLOWED);
        } catch (Exception e) {
            e.printStackTrace();
            return true;
        }
    }


    /**
     * 8.0及以上通知权限判断
     *
     * @param context
     * @return
     */
    private static boolean isEnableV26(Context context) {
        ApplicationInfo appInfo = context.getApplicationInfo();
        String pkg = context.getApplicationContext().getPackageName();
        int uid = appInfo.uid;
        try {
            NotificationManager notificationManager = (NotificationManager)
                    context.getSystemService(Context.NOTIFICATION_SERVICE);
            @SuppressLint("DiscouragedPrivateApi")
            Method sServiceField = notificationManager.getClass().getDeclaredMethod("getService");
            sServiceField.setAccessible(true);
            Object sService = sServiceField.invoke(notificationManager);
            Method method = null;
            if (sService != null) {
                method = sService.getClass().getDeclaredMethod("areNotificationsEnabledForPackage"
                        , String.class, Integer.TYPE);
                method.setAccessible(true);
            }
            return (boolean) method.invoke(sService, pkg, uid);
        } catch (Exception e) {
            return true;
        }
    }

    /**
     * 打开通知权限
     *
     * @param context
     */
    public static void openNotificationSettingsForApp(Context context) {
        // Links to this app's notification settings.
        if (isNotifyEnabled(context))
            return;
        Intent intent = new Intent();
        intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
        intent.putExtra("app_package", context.getPackageName());
        intent.putExtra("app_uid", context.getApplicationInfo().uid);
        // for Android 8 and above
        intent.putExtra("android.provider.extra.APP_PACKAGE", context.getPackageName());
        context.startActivity(intent);
    }
}

2、开启通知栏和显示角标的方法

/**
 * 参数context,count:角标数字,“title”:通知栏的标题,“info”:通知栏的内容
 * 不需要通知栏的话可以后面两个参数不加
 */
BadgeNumberManager.getInstance().setBadgeNumber(MainActivity.this, count, "title", "info");

上面用到的工具类


BadgeNumberManager


import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;

import androidx.core.app.NotificationCompat;

import org.ismarter.zxyq.R;
import org.ismarter.zxyq.activity.MainActivity;

/**
 * 应用桌面角标设置的管理类
 * Created by zlq on 2017 17/8/23 14:50.
 */

public class BadgeNumberManager {

    private final static int NOTICI_ID = 1;
    private static BadgeNumberManager manager;
    private NotificationManager notificationManager;
    private Notification notification;

    private BadgeNumberManager() {}

    public static BadgeNumberManager getInstance() {
        if (manager == null) {
            synchronized (BadgeNumberManager.class) {
                if (manager == null) {
                    manager = new BadgeNumberManager();
                }
            }
        }
        return manager;
    }

    private static final BadgeNumberManager.Impl IMPL;


    /**
     * 设置应用在桌面上显示的角标数字
     *
     * @param number 显示的数字
     */
    public void setBadgeNumber(Context context, int number) {
        IMPL.setBadgeNumber(context, number);
    }

    /**
     * 设置应用在桌面上显示的角标数字
     *
     * @param number 显示的数字
     */
    public void setBadgeNumber(Context context, int number, String title, String desc) {
        setNotification(context, number, title, desc);
        if (IMPL instanceof ImplXiaoMi || IMPL instanceof ImplBase) {
            IMPL.setBadgeNumber(notification, number);
        } else {
            IMPL.setBadgeNumber(context, number);
        }
    }

    public void setNotification(Context context, int number, String title, String desc) {
        notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            String channelId = "approval_message_id";
            String channelName = "新增待审批消息通知";
            NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH);
            channel.setShowBadge(true);
            channel.setDescription("收到新的待审批消息时使用的通知类别");
            notificationManager.createNotificationChannel(channel);
        }

        Intent intent = new Intent(context, MainActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);

        Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

        notification = new NotificationCompat.Builder(context, "approval_message_id")
                .setContentTitle(title)
                .setContentText(desc)
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.drawable.icon)
                .setAutoCancel(true)
                .setChannelId("approval_message_id")
                .setNumber(number)
                .setBadgeIconType(NotificationCompat.BADGE_ICON_SMALL)
                .setContentIntent(pendingIntent)//通知栏点击进入的页面
                .setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE)//设置将从系统默认值继承哪些通知属性 基本就是用来设置是否通知音效或者震动
                .setSound(alarmSound)
                .setVibrate(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400}) //自定义震动的频率
                .setTicker(desc)//收到通知后从顶部弹出精简版通知
                .build();

        //取消掉上一条通知消息
        notificationManager.cancel(NOTICI_ID);
        notificationManager.notify(NOTICI_ID, notification);
    }

    public void cancleNotification() {
        if (notificationManager != null) {
            notificationManager.cancel(NOTICI_ID);
        }
    }

    interface Impl {

        void setBadgeNumber(Context context, int number);

        void setBadgeNumber(Notification notification, int number);
    }

    static class ImplHuaWei implements Impl {

        @Override
        public void setBadgeNumber(Context context, int number) {
            BadgeNumberManagerHuaWei.setBadgeNumber(context, number);
        }

        @Override
        public void setBadgeNumber(Notification notification, int number) {

        }
    }

    static class ImplXiaoMi implements Impl {

        @Override
        public void setBadgeNumber(Context context, int number) {

        }

        @Override
        public void setBadgeNumber(Notification notification, int number) {
            //小米机型的桌面应用角标API跟通知绑定在一起了,所以单独做处理
            BadgeNumberManagerXiaoMi.setBadgeNumber(notification, number);
        }
    }

    static class ImplVIVO implements Impl {

        @Override
        public void setBadgeNumber(Context context, int number) {
            BadgeNumberManagerVIVO.setBadgeNumber(context, number);
        }

        @Override
        public void setBadgeNumber(Notification notification, int number) {

        }
    }

    static class ImplOPPO implements Impl {

        @Override
        public void setBadgeNumber(Context context, int number) {
            BadgeNumberManagerOPPO.setBadgeNumber(context, number);
        }

        @Override
        public void setBadgeNumber(Notification notification, int number) {

        }
    }

    static class ImplSAMSUNG implements Impl {

        @Override
        public void setBadgeNumber(Context context, int number) {
            BadgeNumberManagerSAMSUNG.setBadgeNumber(context, number);
        }

        @Override
        public void setBadgeNumber(Notification notification, int number) {

        }
    }

    static class ImplSONY implements Impl {

        @Override
        public void setBadgeNumber(Context context, int number) {
            BadgeNumberManagerSONY.setBadgeNumber(context, number);
        }

        @Override
        public void setBadgeNumber(Notification notification, int number) {

        }
    }

    static class ImplLENOVO implements Impl {

        @Override
        public void setBadgeNumber(Context context, int number) {
            BadgeNumberManagerLENOVO.setBadgeNumber(context, number);
        }

        @Override
        public void setBadgeNumber(Notification notification, int number) {

        }
    }

    static class ImplBase implements Impl {

        @Override
        public void setBadgeNumber(Context context, int number) {

        }

        @Override
        public void setBadgeNumber(Notification notification, int number) {
            BadgeNumberManagerXiaoMi.setBadgeNumber(notification, number);
        }
    }

    static {
        String manufacturer = Build.MANUFACTURER;
        if (manufacturer.equalsIgnoreCase(MobileBrand.HUAWEI)) {
            IMPL = new ImplHuaWei();//华为
        } else if (manufacturer.equalsIgnoreCase(MobileBrand.XIAOMI)) {
            IMPL = new ImplXiaoMi();//小米
        } else if (manufacturer.equalsIgnoreCase(MobileBrand.VIVO)) {
            IMPL = new ImplVIVO();//vivo
        } else if (manufacturer.equalsIgnoreCase(MobileBrand.OPPO)) {
            IMPL = new ImplOPPO();//oppo
        } else if (manufacturer.equalsIgnoreCase(MobileBrand.SAMSUNG)) {
            IMPL = new ImplSAMSUNG();//三星
        } else if (manufacturer.equalsIgnoreCase(MobileBrand.SONY)) {
            IMPL = new ImplSONY();//索尼
        } else if (manufacturer.equalsIgnoreCase(MobileBrand.LENOVO)) {
            IMPL = new ImplLENOVO();//联想
        } else {
            IMPL = new ImplBase();
        }
    }

    public static String getLauncherClassName(Context context) {
        ComponentName launchComponent = getLauncherComponentName(context);
        if (launchComponent == null) {
            return "";
        } else {
            return launchComponent.getClassName();
        }
    }

    public static ComponentName getLauncherComponentName(Context context) {
        Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(context
                .getPackageName());
        if (launchIntent != null) {
            return launchIntent.getComponent();
        } else {
            return null;
        }
    }
}


MobileBrand


/**
 * 手机的 Build.MANUFACTURER 常量
 * Created by zlq on 2017 17/8/22 18:08.
 */

public class MobileBrand {

    public final static String HUAWEI = "Huawei";   //华为
    public final static String MEIZU = "Meizu";     //魅族
    public final static String XIAOMI = "Xiaomi";   //小米
    public final static String SONY = "Sony";       //索尼
    public final static String OPPO = "OPPO";       //OPPO
    public final static String VIVO = "vivo";       //VIVO
    public final static String SAMSUNG = "samsung"; //三星
    public final static String LG = "LG";           //LG
    public final static String LETV = "Letv";       //乐视
    public final static String ZTE = "ZTE";         //中兴
    public final static String YULONG = "YuLong";   //酷派
    public final static String LENOVO = "LENOVO";   //联想

}


BadgeNumberManagerHuaWei


import android.content.Context;
import android.net.Uri;
import android.os.Bundle;

/**
 * 华为机型的桌面角标设置管理类
 * Created by zlq on 2017 17/8/23 16:35.
 */

public class BadgeNumberManagerHuaWei {

    /**
     * 设置应用的桌面角标,已在一些华为手机上测试通过,但是无法保证在所有华为手机上都生效
     *
     * @param context context
     * @param number  角标显示的数字
     */
    public static void setBadgeNumber(Context context, int number) {
        try {
            if (number < 0) number = 0;
            Bundle bundle = new Bundle();
            bundle.putString("package", context.getPackageName());
            String launchClassName = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()).getComponent().getClassName();
            bundle.putString("class", launchClassName);
            bundle.putInt("badgenumber", number);
            context.getContentResolver().call(Uri.parse("content://com.huawei.android.launcher.settings/badge/"), "change_badge", null, bundle);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


BadgeNumberManagerLENOVO


import android.content.Context;
import android.net.Uri;
import android.os.Bundle;

import java.util.ArrayList;

/**
 * 联想机型的桌面角标设置管理类
 * Created by zlq on 2017 17/8/23 16:35.
 */

public class BadgeNumberManagerLENOVO {

    public static boolean setBadgeNumber(Context context, int count) {
        try {
            Bundle extra = new Bundle();
            ArrayList<String> ids = new ArrayList<>();
            // 以列表形式传递快捷方式id,可以添加多个快捷方式id
            // ids这个参数可以为空或者“null”表示对主图标进行角标标记
//        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;
        }
    }
}


BadgeNumberManagerOPPO


import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;

import java.util.List;

/**
 * OPPO机型的桌面角标设置管理类
 * Created by zlq on 2017 17/8/23 16:35.
 */

public class BadgeNumberManagerOPPO {


    public static void setBadgeNumber(Context context, int number) {
        try {
            if (number == 0) {
                number = -1;
            }
            Intent intent = new Intent("com.oppo.unsettledevent");
            intent.putExtra("pakeageName", context.getPackageName());
            intent.putExtra("number", number);
            intent.putExtra("upgradeNumber", number);
            if (canResolveBroadcast(context, intent)) {
                context.sendBroadcast(intent);
            } else {
                try {
                    Bundle extras = new Bundle();
                    extras.putInt("app_badge_count", number);
                    context.getContentResolver().call(Uri.parse("content://com.android.badge/badge"), "setAppBadgeCount", null, extras);
                } 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");
        }
    }

    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;
    }
}


BadgeNumberManagerSAMSUNG


import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;

/**
 * 三星机型的桌面角标设置管理类
 * Created by zlq on 2017 17/8/23 16:35.
 */

public class BadgeNumberManagerSAMSUNG {

    public static void setBadgeNumber(Context context, int count) {
        String launcherClassName = BadgeNumberManager.getLauncherClassName(context);
        if (TextUtils.isEmpty(launcherClassName)) {
            return;
        }
        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);
    }
}


BadgeNumberManagerSONY


import android.content.AsyncQueryHandler;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.text.TextUtils;

/**
 * 索尼机型的桌面角标设置管理类
 * Created by zlq on 2017 17/8/23 16:35.
 */

public class BadgeNumberManagerSONY {

    public static void setBadgeNumber(Context context, int count) {
        String launcherClassName = BadgeNumberManager.getLauncherClassName(context);
        if (TextUtils.isEmpty(launcherClassName)) {
            return;
        }
        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);
        } 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);
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        }
    }

    static class SonyAsyncQueryHandler extends AsyncQueryHandler {
        SonyAsyncQueryHandler(ContentResolver cr) {
            super(cr);
        }
    }
}


BadgeNumberManagerVIVO


import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.os.Build;

/**
 * vivo机型的桌面角标设置管理类
 * Created by zlq on 2017 17/8/23 16:35.
 */

public class BadgeNumberManagerVIVO {
    public static final int FLAG_RECEIVER_INCLUDE_BACKGROUND = 0x01000000;

    @SuppressLint("WrongConstant")
    public static void setBadgeNumber(Context context, int number) {
        try {
            Intent intent = new Intent("launcher.action.CHANGE_APPLICATION_NOTIFICATION_NUM");
            intent.putExtra("packageName", context.getPackageName());
            String launchClassName = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()).getComponent().getClassName();
            intent.putExtra("className", launchClassName);
            intent.putExtra("notificationNum", number);
            if ((Build.VERSION.SDK_INT >= 26)) {
                intent.addFlags(FLAG_RECEIVER_INCLUDE_BACKGROUND);
            }
            context.sendBroadcast(intent);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


BadgeNumberManagerXiaoMi


import android.app.Notification;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 小米机型的桌面角标设置管理类
 * Created by zlq on 2017 17/8/23 16:35.
 */

public class BadgeNumberManagerXiaoMi {

    public static void setBadgeNumber(Notification notification, int number) {
        try {
            Field field = notification.getClass().getDeclaredField("extraNotification");
            Object extraNotification = field.get(notification);
            Method method = extraNotification.getClass().getDeclaredMethod("setMessageCount", int.class);
            method.invoke(extraNotification, number);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}