实现后的显示效果(由于角标功能由各个厂商自己实现的,所以各个厂商的实现方法不一样)
备注:小米系统在进入应用后会隐藏角标的显示,只有当退出到桌面时去设置角标才会显示
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();
}
}
}