角標是從 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 角標的問題。