好久没写博客了,这段时间一直在做项目忙得要死啊。然后新需求来了,领导要求做一个像iOS那样能提醒用户未读消息数量的角标。查了下资料出现频率最多的就是ShortcutBadger和ShortcutHelper,这两个项目兼容了挺多手机,但是一看这两个项目的更新时间都有点久了,使用之后也发现有好多都已经不起作用了。
华为角标官方文档:
华为还是蛮不错的提供了角标的详细使用,但不要忘了添加权限。
注:关于华为文档链接可能失效的问题,到华为开发者页面搜索角标,能找到华为角标开发指南书。
小米角标官方文档:
小米做的也挺厚道,在开放平台上搜索就能找到角标的使用,但仍存在两个问题。
联想ZUK官方文档:
虽然在市面上占的手机份额不是很多,但却也给出了详细的使用角标的方法。
索尼官方文档:
索尼官方给出的有点麻烦,官网搜索badge之后看了好几个答案才发现了官方使用方法。
谷歌官方文档:
这是Android 8.0新出现的,但也仅仅是圆点,没有数字颜色也不能控制。
华为
华为对外提供了数据库URI、操作数据库的权限,通过指定的接口方式,APP将需要显示的角标数量和应用的一些包名之类的信息传给华为桌面便能显示未读角标信息了,但不要忘了添加权限。
private static void badgeHuawei(Context context, int badgeCount) {
try {
Bundle bunlde = new Bundle();
bunlde.putString("package", context.getPackageName());
bunlde.putString("class", launcherClassName);
bunlde.putInt("badgenumber", badgeCount);
context.getContentResolver().call(Uri.parse("content://com.huawei.android.launcher.settings/badge/"), "change_badge", null, bunlde);
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
小米
小米虽然给出了官方文档但还是存在两个问题:
1、小米手机在添加角标方法执行的时候如果在APP内或未清理掉之前通知,角标不会出现;
private static void badgeXiaomi(final Context context, final int badgeCount) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//延迟1秒是为了避免执行操作的时候还在app内,如要真正避免还是需要控制调用的时机
try {
Notification notification = getNotification(context, badgeCount);
Field field = notification.getClass().getDeclaredField("extraNotification");
Object extraNotification = field.get(notification);
Method method = extraNotification.getClass().getDeclaredMethod("setMessageCount", int.class);
method.invoke(extraNotification, badgeCount);
BadgerUtil.notify(notification, badgeCount);
} catch (Exception e) {
e.printStackTrace();
// 网上找的据说是miui 6之前的版本,没有miui6之前版本的小米手机不知道有没有效
Intent localIntent = new Intent("android.intent.action.APPLICATION_MESSAGE_UPDATE");
localIntent.putExtra("android.intent.extra.update_application_component_name", context.getPackageName() + "/" + getLauncherClassName(context));
localIntent.putExtra("android.intent.extra.update_application_message_text", String.valueOf(badgeCount == 0 ? "" : badgeCount));
context.sendBroadcast(localIntent);
}
}
}, 1000);
}
2、Android 8.0对通知的使用做了调整需要使用先设置NotificationChannel,否则会提示错误信息,具体可以看官方文档;
private static NotificationManager notificationManager;
private static Notification getNotification(Context context, int badgeCount) {
if (notificationManager == null) {
notificationManager = ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//8.0之后添加角标需要NotificationChannel
NotificationChannel channel = new NotificationChannel("badge", "badge", NotificationManager.IMPORTANCE_LOW);
channel.setShowBadge(true);
((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
}
}
Notification notification = new NotificationCompat.Builder(context, "badge")
.setContentTitle("通知")
.setContentText("新消息")
.setSmallIcon(R.drawable.ic_launcher)
.setBadgeIconType(NotificationCompat.BADGE_ICON_SMALL)
.setNumber(badgeCount)
.setAutoCancel(true)
.build();
return notification;
}
/**
* 发送通知
*/
private static void notify(Notification notification, int badgeCount) {
notificationManager.cancel(TAG, NOTIFY_ID);
if (badgeCount > 0) {
notificationManager.notify(TAG, NOTIFY_ID, notification);
}
}
联想ZUK
zuk的使用和联想差不多也是提供操作数据库的,同时也需要添加权限。
private static void badgeZuk(Context context, int badgeCount) {
Bundle extra = new Bundle();
extra.putInt("app_badge_count", badgeCount);
context.getContentResolver().call(Uri.parse("content://com.android.badge/badge"), "setAppBadgeCount", null, extra);
}
索尼
索尼官方给出的方法和网上大部分在使用的方法好像不一样,由于没有索尼手机没法测试,权限也有点不一样,我这里全加上了。
private static void badgeSony(Context context, int badgeCount) {
if (asyncQueryHandler == null) {
asyncQueryHandler = new AsyncQueryHandler(context.getContentResolver()) {
};
}
try {
//官方给出方法
ContentValues contentValues = new ContentValues();
contentValues.put("badge_count", badgeCount);
contentValues.put("package_name", context.getPackageName());
contentValues.put("activity_name", launcherClassName);
asyncQueryHandler.startInsert(0, null, Uri.parse("content://com.sonymobile.home.resourceprovider/badge"), contentValues);
} catch (Exception e) {
//网上大部分使用方法
Intent intent = new Intent("com.sonyericsson.home.action.UPDATE_BADGE");
intent.putExtra("com.sonyericsson.home.intent.extra.badge.SHOW_MESSAGE", badgeCount > 0);
intent.putExtra("com.sonyericsson.home.intent.extra.badge.ACTIVITY_NAME", launcherClassName);
intent.putExtra("com.sonyericsson.home.intent.extra.badge.MESSAGE", String.valueOf(badgeCount > 0 ? badgeCount : ""));
intent.putExtra("com.sonyericsson.home.intent.extra.badge.PACKAGE_NAME", context.getPackageName());
context.sendBroadcast(intent);
}
}
三星
在ShortcutBadger中使用了数据库操作的方式但又添加了废弃的注释,或许老版本有使用,新版本不能使用了吧。
private static void badgeSamsung(Context context, int badgeCount) {
Uri uri = Uri.parse("content://com.sec.badge/apps");
String columnId = "_id";
String columnPackage = "package";
String columnClass = "class";
String columnBadgeCount = "badgeCount";
Cursor cursor = null;
try {
ContentResolver contentResolver = context.getContentResolver();
cursor = contentResolver.query(uri, new String[]{columnId}, columnPackage + "=?", new String[]{context.getPackageName()}, null);
if (cursor == null || !cursor.moveToFirst()) {
ContentValues contentValues = new ContentValues();
contentValues.put(columnPackage, context.getPackageName());
contentValues.put(columnClass, launcherClassName);
contentValues.put(columnBadgeCount, badgeCount);
contentResolver.insert(uri, contentValues);
} else {
int idColumnIndex = cursor.getColumnIndex(columnId);
ContentValues contentValues = new ContentValues();
contentValues.put(columnBadgeCount, badgeCount);
contentResolver.update(uri, contentValues, columnId + "=?", new String[]{String.valueOf(cursor.getInt(idColumnIndex))});
}
} catch (Exception e) {
Intent intent = new Intent("android.intent.action.BADGE_COUNT_UPDATE");
intent.putExtra("badge_count", badgeCount);
intent.putExtra("badge_count_package_name", context.getPackageName());
intent.putExtra("badge_count_class_name", launcherClassName);
context.sendBroadcast(intent);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
HTC
经测试,HTC只需要发送广播即可,也不需要权限,5.0,7.0亲测有效
private static void badgeHtc(Context context, int badgeCount) {
try {
Intent intent = new Intent("android.intent.action.BADGE_COUNT_UPDATE");
intent.putExtra("badge_count", badgeCount);
intent.putExtra("badge_count_package_name", context.getPackageName());
intent.putExtra("badge_count_class_name", launcherClassName);
context.sendBroadcast(intent);
} catch (Exception e) {
}
}
谷歌
Android 8.0给出了一种没有数字且不能改变颜色的圆点角标
private static NotificationManager notificationManager;
private static Notification getNotification(Context context, int badgeCount) {
if (notificationManager == null) {
notificationManager = ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//8.0之后添加角标需要NotificationChannel
NotificationChannel channel = new NotificationChannel("badge", "badge", NotificationManager.IMPORTANCE_LOW);
channel.setShowBadge(true);
((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
}
}
Notification notification = new NotificationCompat.Builder(context, "badge")
.setContentTitle("通知")
.setContentText("新消息")
.setSmallIcon(R.drawable.ic_launcher)
.setBadgeIconType(NotificationCompat.BADGE_ICON_SMALL)
.setNumber(badgeCount)
.setAutoCancel(true)
.build();
return notification;
}
/**
* 发送通知
*/
private static void notify(Notification notification, int badgeCount) {
notificationManager.cancel(TAG, NOTIFY_ID);
if (badgeCount > 0) {
notificationManager.notify(TAG, NOTIFY_ID, notification);
}
}
OPPO和vivo
这两个手机由于广告和线下店的原因在市场上占的份额还是相当多的,但是对角标的使用却非常坑。首先是OPPO,没有官方文档,找客服之后,只能说非常非常非常麻烦
然后没办法咯,只能看看人家QQ和微信是怎么实现的了
QQ实现:
微信实现:
网上查了下也是这么实现的,添加到代码中使用,并没有什么用,一时好奇把包名改成com.tencent.mobileqq,恭喜您的角标上线了。。。OPPO和vivo都可以了。。。无语啊。。。
详细代码可以看GitHub,如有问题也可以留言一起交流。