角标是从 iOS 那边 copy 过来的一个功能,目前 Android 没有提供系统 API 对此做支持。如果需要适配这个功能需要遵循主流的 Android 手机厂商的适配规范,文章列举的 华为 三星 vivo HTC 的适配方式。
一 判断机型
if (Build.MANUFACTURER.equalsIgnoreCase("HUAWEI")) {
// luncherPackageName : com.huawei.android.internal.app
badgeHandler = new HuaweiBadgeHandler(context);
return;
}
if (Build.MANUFACTURER.equalsIgnoreCase("vivo")) {
badgeHandler = new VivoBadgeHandler(context);
return;
}
if (Build.MANUFACTURER.equalsIgnoreCase("samsung")) {
badgeHandler = new SamsungBadgeHandler(context);
return;
}
if (Build.MANUFACTURER.equalsIgnoreCase("HTC")) {
badgeHandler = new HtcBadgeHandler(context);
return;
}
二 各机型适配规则:
1 华为:
public class HuaweiBadgeHandler implements IBadgeHandler {
private static final String TAG = HuaweiBadgeHandler.class.getSimpleName();
private Context context;
private boolean isSupportedBade = false;
private String packageName;
private String launchClassName;
private ExecutorService executorService = Executors.newSingleThreadExecutor();
HuaweiBadgeHandler(Context context) {
this.context = context;
try {
packageName = context.getPackageName();
launchClassName = context.getPackageManager()
.getLaunchIntentForPackage(packageName)
.getComponent().getClassName();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void updateBadgeCount(int count) {
checkIsSupportedByVersion();
if (isSupportedBade) {
ChangeBadgeRunnable runnable = new ChangeBadgeRunnable(count);
executorService.submit(runnable);
}
}
private void checkIsSupportedByVersion() {
if (launchClassName == null) {
isSupportedBade = false;
return;
}
try {
PackageManager manager = context.getPackageManager();
PackageInfo info = manager.getPackageInfo("com.huawei.android.launcher",
0);
if (info.versionCode >= 63025) {
isSupportedBade = true;
}
RLog.d(TAG, "checkIsSupportedByVersion versionCode " + info.versionCode + " isSupportedBade: " + isSupportedBade);
} catch (Exception e) {
e.printStackTrace();
}
}
private class ChangeBadgeRunnable implements Runnable {
private int count;
ChangeBadgeRunnable(int count) {
this.count = count;
}
@Override
public void run() {
try {
Bundle bundle = new Bundle();//需要存储的数据
bundle.putString("package", packageName);//包名
bundle.putString("class", launchClassName);//启动的Activity完整名称
bundle.putInt("badgenumber", count);//未读信息条数
context.getContentResolver().call(
Uri.parse("content://com.huawei.android.launcher.settings/badge/"),
"change_badge", null, bundle);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
2 Htc:
public class HtcBadgeHandler implements IBadgeHandler {
private Context context;
private static final String EXTRA_COMPONENT = "com.htc.launcher.extra.COMPONENT";
private static final String EXTRA_COUNT = "com.htc.launcher.extra.COUNT";
private static final String INTENT_SET_NOTIFICATION = "com.htc.launcher.action.SET_NOTIFICATION";
private static final String INTENT_UPDATE_SHORTCUT = "com.htc.launcher.action.UPDATE_SHORTCUT";
private static final String COUNT = "count";
private static final String PACKAGENAME = "packagename";
private ComponentName componentName;
public HtcBadgeHandler(Context context) {
this.context = context;
componentName = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()).getComponent();
}
@Override
public void updateBadgeCount(int count) {
Intent intent = new Intent(INTENT_SET_NOTIFICATION);
intent.putExtra(EXTRA_COMPONENT, componentName.flattenToShortString());
intent.putExtra(EXTRA_COUNT, count);
Intent intent1 = new Intent(INTENT_UPDATE_SHORTCUT);
intent1.putExtra(PACKAGENAME, context.getPackageName());
intent1.putExtra(COUNT, count);
if (canResolveBroadcast(intent) || canResolveBroadcast(intent1)) {
context.sendBroadcast(intent);
context.sendBroadcast(intent1);
}
}
private boolean canResolveBroadcast(Intent intent) {
PackageManager packageManager = context.getPackageManager();
List<ResolveInfo> receivers = packageManager.queryBroadcastReceivers(intent, 0);
return receivers != null && receivers.size() > 0;
}
}
3 三星:
public class SamsungBadgeHandler implements IBadgeHandler {
private Context context;
public SamsungBadgeHandler(Context context) {
this.context = context;
}
@Override
public void updateBadgeCount(int count) {
String launchClassName = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()).getComponent().getClassName();
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", launchClassName);
context.sendBroadcast(intent);
}
}
4 Vivo:
public class VivoBadgeHandler implements IBadgeHandler {
private Context context;
public VivoBadgeHandler(Context context) {
this.context = context;
}
@Override
public void updateBadgeCount(int count) {
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", count);
context.sendBroadcast(intent);
}
}
角标适配的复杂在于机型厂商多样,以及如何更好的跟自身业务结合,例如一些需要杀死主进程还需要提醒角标的场景。
希望后续 google 可以在某个版本出系统级别的 API 接口来规范 Android 角标的问题。