1. Android 实现应用桌面角标
Android 8.0之前原生是不支持应用角标的,是各个手机厂商自己在系统中实现的应用角标,并且部分厂商提供了设置的方式,所以需要对各个厂商的系统进行适配。
1.1. 各机型适配
1.1.1. 小米手机
官方文档:文档中心 小米在MIUI6及以上版本中是通过发送通知来设置角标的。当APP向通知栏发送了一条通知 (通知不带进度条并且用户可以删除的),那么桌面APP icon角标就会显示1。此时app显示的角标数是和通知栏里app发送的通知数对应的,即向通知栏发送了多少通知就会显示多少角标。
可以通过反射机制来定义每次通知的消息个数,应用的角标数为每条通知定义的通知个数的总和。
我们发送了两条通知,一条通知为5个消息,一条为10个消息,应用角标显示为15个。此时,如果用户点击或移除掉5条消息的那个通知,应用角标会变成10。
另外,仅在APP在后台时收到通知会显示角标,而APP在前台时不会显示,APP被杀掉后通知及角标消失。
/**
* 小米手机创建通知信息并创建角标
*
* @param context
* @param num
*/
public static void setXiaoMiBadgeNum(Context context, int num) {
Log.e(TAG, "--------setXiaoMiBadgeNum----------");
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
String title = "消息提示";
String desc = "您有" + num + "条未读消息";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
String channelId = "default";
String channelName = "默认通知";
NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH);
channel.setShowBadge(true);
notificationManager.createNotificationChannel(channel);
}
Notification notification = new NotificationCompat.Builder(context, "default")
.setContentTitle(title)
.setContentText(desc)
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)
.setAutoCancel(true)
.setChannelId("default")
.setNumber(num)//桌面角标数量
.setBadgeIconType(NotificationCompat.BADGE_ICON_SMALL)
.build();
//取消掉上一条通知消息
notificationManager.cancel(notificationId);
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();
}
notificationManager.notify(notificationId, notification);
}
需要注意以下几点:
(1)发送通知必须当app处于后台才会生成桌面角标,否则只会生成一次。
(2)该方法目前支持到miui12.
1.1.2. 三星手机
已在三星s7dege+上,Android8.0上通过
public static void setSamSungBadgeNum(Context context,int num){
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context)
.setSmallIcon(R.mipmap.ic_launcher)
.setWhen(System.currentTimeMillis())
.setAutoCancel(true);
mBuilder.setContentTitle("test");
mBuilder.setTicker("test");
mBuilder.setContentText("test");
//点击set 后,app退到桌面等待3s看效果(有的launcher当app在前台设置未读数量无效)
final Notification notification = mBuilder.build();
sendBadgeNotification(notification, notificationId, context, num, num);
}
/**
* 重置、清除Badge未读显示数<br/>
*
* @param context
*/
public static void resetBadgeCount(Context context) {
sendBadgeNotification(null, 0, context, 0, 0);
}
public static void sendBadgeNotification(Notification notification, int notifyID, Context context, int thisNotifyCount, int count) {
if (count <= 0) {
count = 0;
} else {
count = Math.max(0, Math.min(count, 99));
}
executeBadge(context, notification, notifyID, thisNotifyCount, count);
}
public static void executeBadge(Context context, Notification notification, int notificationId, int thisNotificationCount, int count) {
setNotification(notification, notificationId, context);
String launcherClassName = getLauncherClassName(context);
if (launcherClassName == null) {
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);
}
protected static void setNotification(Notification notification, int notificationId, Context context) {
if (notification != null) {
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(notificationId, notification);
}
}
protected static String getLauncherClassName(Context context) {
PackageManager packageManager = context.getPackageManager();
Intent intent = new Intent(Intent.ACTION_MAIN);
// To limit the components this Intent will resolve to, by setting an
// explicit package name.
intent.setPackage(context.getPackageName());
intent.addCategory(Intent.CATEGORY_LAUNCHER);
// All Application must have 1 Activity at least.
// Launcher activity must be found!
ResolveInfo info = packageManager
.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
// get a ResolveInfo containing ACTION_MAIN, CATEGORY_LAUNCHER
// if there is no Activity which has filtered by CATEGORY_DEFAULT
if (info == null) {
info = packageManager.resolveActivity(intent, 0);
}
return info.activityInfo.name;
}
1.1.3. 华为
可以通过ContentResolver方法直接设置应用角标,且应用在前台和被杀掉后仍可显示。
<!--华为手机更新应用桌面角标需要的权限-->
<uses-permission android:name="com.huawei.android.launcher.permission.CHANGE_BADGE"/>
private void setHUAWEIIconBadgeNum(Context context,int count) {
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context)
.setSmallIcon(R.mipmap.ic_launcher)
.setWhen(System.currentTimeMillis())
.setAutoCancel(true);
mBuilder.setContentTitle("test");
mBuilder.setTicker("test");
mBuilder.setContentText("test");
//点击set 后,app退到桌面等待3s看效果(有的launcher当app在前台设置未读数量无效)
final Notification notification = mBuilder.build();
setNotification(notification, notificationId, context);
Bundle bunlde = new Bundle();
bunlde.putString("package", context.getPackageName());
bunlde.putString("class", getLauncherClassName(context));
bunlde.putInt("badgenumber", count);
context.getContentResolver().call(Uri.parse("content://com.huawei.android.launcher.settings/badge/"), "change_badge", null, bunlde);
}
1.1.4. OPPO
首先,官方客服和我说他们可以支持,但需要申请。
而抱歉的是截止目前我还没有得到具体的方法,因为我们还在它的申请流程中。。
具体申请流程请去OPPO开放平台找他们的人工客服获取申请方法。
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 t) {
t.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
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;
}
1.1.5. VIVO
官方文档:vivo开放平台
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);
context.sendBroadcast(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
1.2. 完整代码
public class MobileConfigUtil {
/**
* @return 手机类型 华为、小米、vivo、oppo
* @desc 获取手机类型
*/
public static String getMobileType() {
return Build.MANUFACTURER;
}
/**
* @desc 根据手机机型进入app自启动页面
*/
public static void jumpStartInterface(Context context) {
Intent intent = new Intent();
try {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ComponentName componentName = null;
if (getMobileType().equals("Xiaomi")) { // 小米、红米
// componentName = new ComponentName(
// "com.miui.securitycenter",
// "com.miui.permcenter.autostart.AutoStartManagementActivity");
// 在此根据用户手机当前版本跳转系统设置界面
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.setData(Uri.fromParts("package",
context.getPackageName(), null));
} else if (getMobileType().equals("Letv")) { // 乐视
intent.setAction("com.letv.android.permissionautoboot");
} else if (getMobileType().equals("samsung")) { // 三星
componentName = ComponentName.unflattenFromString(
"com.samsung.android.sm_cn/com.samsung.android.sm.ui.ram.AutoRunActivity");
} else if (getMobileType().equals("HONOR") // 荣耀
|| getMobileType().equals("HUAWEI") // 华为
|| getMobileType().equals("NOVA")) // nova
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
componentName = new ComponentName(
"com.huawei.systemmanager",
"com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity");
} else {
componentName = new ComponentName(
"com.huawei.systemmanager",
"com.huawei.systemmanager.com.huawei.permissionmanager.ui.MainActivity");
}
} else if (getMobileType().equals("vivo")) { // vivo
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// componentName = new ComponentName(
// "com.vivo.permissionmanager",
// "com.vivo.permissionmanager.activity.PurviewTabActivity");
// } else {
// componentName = ComponentName
// .unflattenFromString("com.iqoo.secure/.MainActivity");//i管家
// }
// intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// 在此根据用户手机当前版本跳转系统设置界面
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.setData(Uri.fromParts("package",
context.getPackageName(), null));
} else if (getMobileType().equals("Meizu")) {//魅族
//魅族内置手机管家界面
componentName = ComponentName.unflattenFromString("com.meizu.safe" +
"/.permission.PermissionMainActivity");
} else if (getMobileType().equals("OPPO")) { // OPPO
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
componentName = new ComponentName(
"com.coloros.safecenter",
"com.coloros.safecenter.startupapp.StartupAppListActivity");
} else {
componentName = new ComponentName(
"com.color.safecenter",
"com.color.safecenter.permission.startup.StartupAppListActivity");
}
} else if (getMobileType().equals("ulong")) { // 360手机
componentName = new ComponentName(
"com.yulong.android.coolsafe",
".ui.activity.autorun.AutoRunListActivity");
} else {
// 在此根据用户手机当前版本跳转系统设置界面
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.setData(Uri.fromParts("package",
context.getPackageName(), null));
}
intent.setComponent(componentName);
context.startActivity(intent);
} catch (Exception e) {//抛出异常就直接打开设置页面
intent = new Intent(Settings.ACTION_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
Log.e("HLQ_Struggle", "抛出异常就直接打开设置页面");
}
}
/**
* @desc 去配置界面
*/
public static void goConfigPage(Context context) {
Intent intent = new Intent(Settings.ACTION_SETTINGS);
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.setData(Uri.fromParts("package",
context.getPackageName(), null));
context.startActivity(intent);
}
}