有没有办法在 Android 中为应用程序图标添加徽章?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2905542/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 07:49:36  来源:igfitidea点击:

Is there a way to add a badge to an application icon in Android?

androidiconsbadge

提问by groomsy

On the iPhone, you can add a numbered badge to the application icon. On BlackBerry, I've successfully painted an image onto the application's icon while in the program. I want to do this for Android as well. I don't want to use the notification bar, as it's not something that needs to be notified instantly. Instead, I just want the user to be able to see how many new messages are in the application just by looking at the application icon.

在 iPhone 上,您可以向应用程序图标添加编号标记。在 BlackBerry 上,我在程序中成功地将图像绘制到应用程序的图标上。我也想为 Android 做这个。我不想使用通知栏,因为它不需要立即通知。相反,我只是希望用户能够通过查看应用程序图标来查看应用程序中有多少新消息。

采纳答案by HXCaine

Unfortunately, Android does not allow changing of the application icon because it's sealed in the APK once the program is compiled. There is no way to programmatically change it to a 'drawable'.

不幸的是,Android 不允许更改应用程序图标,因为一旦程序被编译,它就被密封在 APK 中。无法以编程方式将其更改为“可绘制”。

You may achieve your goal by using a widget instead of an icon. Widgets are highly customisable and can do what you want.

您可以通过使用小部件而不是图标来实现您的目标。小部件是高度可定制的,可以做你想做的。

There's a short discussion about the difference between iPhone icon notification and using widgets here:

这里有一个关于 iPhone 图标通知和使用小部件之间区别的简短讨论:

http://www.cnet.com/8301-19736_1-10278814-251.html

http://www.cnet.com/8301-19736_1-10278814-251.html

As you'll notice, there is virtually no difference between using a widget or an icon, since they can be the same size and look the same.

您会注意到,使用小部件或图标几乎没有区别,因为它们可以具有相同的大小和外观。

回答by Marcus

This can also be done for Sony's Xperia Home. I've blogged about it here, but the important parts are below. Sony devices use a class named BadgeReciever.

索尼的 Xperia Home 也可以这样做。我已经在这里写了关于它的博客,但重要的部分在下面。Sony 设备使用名为BadgeReciever.

  1. Declare the com.sonyericsson.home.permission.BROADCAST_BADGEpermission in your manifest file:

  2. Broadcast an Intentto the BadgeReceiver:

    Intent intent = new Intent();
    
    intent.setAction("com.sonyericsson.home.action.UPDATE_BADGE");
    intent.putExtra("com.sonyericsson.home.intent.extra.badge.ACTIVITY_NAME", "com.yourdomain.yourapp.MainActivity");
    intent.putExtra("com.sonyericsson.home.intent.extra.badge.SHOW_MESSAGE", true);
    intent.putExtra("com.sonyericsson.home.intent.extra.badge.MESSAGE", "99");
    intent.putExtra("com.sonyericsson.home.intent.extra.badge.PACKAGE_NAME", "com.yourdomain.yourapp");
    
    sendBroadcast(intent);
    
  3. Done. Once this Intentis broadcast the launcher should show a badge on your application icon.

  4. To remove the badge again, simply send a new broadcast, this time with SHOW_MESSAGEset to false:

    intent.putExtra("com.sonyericsson.home.intent.extra.badge.SHOW_MESSAGE", false);
    
  1. com.sonyericsson.home.permission.BROADCAST_BADGE在清单文件中声明权限:

  2. 广播IntentBadgeReceiver

    Intent intent = new Intent();
    
    intent.setAction("com.sonyericsson.home.action.UPDATE_BADGE");
    intent.putExtra("com.sonyericsson.home.intent.extra.badge.ACTIVITY_NAME", "com.yourdomain.yourapp.MainActivity");
    intent.putExtra("com.sonyericsson.home.intent.extra.badge.SHOW_MESSAGE", true);
    intent.putExtra("com.sonyericsson.home.intent.extra.badge.MESSAGE", "99");
    intent.putExtra("com.sonyericsson.home.intent.extra.badge.PACKAGE_NAME", "com.yourdomain.yourapp");
    
    sendBroadcast(intent);
    
  3. 完毕。一旦Intent广播,启动器应该在您的应用程序图标上显示一个徽章。

  4. 要再次删除徽章,只需发送一个新的广播,这次SHOW_MESSAGE设置为 false:

    intent.putExtra("com.sonyericsson.home.intent.extra.badge.SHOW_MESSAGE", false);
    

I've excluded details on how I found this to keep the answer short, but it's all available in the blog. Might be an interesting read for someone.

我已经排除了有关我如何找到答案的详细信息,以保持答案简短,但所有这些都可以在博客中找到。对某人来说可能是一个有趣的阅读。

I've also posted a seperate SO question about this hereand will add the full answer there once I'm allowed to (need 10 reputation to answer my own question within 8 hours).

我也张贴了关于这一个单独的SO问题,在这里,将有添加完整的答案,一旦我允许(需要10声誉回答8个小时之内我自己的问题)。

回答by Gagan Deep

ShortcutBadgerlibrary makes it possible and works with LG, Sony, Samsung, HTC and other custom Launchers.

ShortcutBadger库使其成为可能,并与 LG、索尼、三星、HTC 和其他自定义启动器一起使用。

It even has a way to display Badge Count in Pure Android devices desktop.

它甚至可以在纯 Android 设备桌面上显示徽章计数。

Updating the Badge Count in the application icon is as easy as calling:

更新应用程序图标中的徽章计数就像调用一样简单:

int badgeCount = 1;
ShortcutBadger.setBadge(getApplicationContext(), badgeCount);

It includes a demo application that allows you to test its behaviour.

它包括一个演示应用程序,允许您测试其行为。

OR

或者

you can also try activity-alias to do so, but in this you need to create different icons with badge values ,it will work great in case- you need to switch between 2 different App icons (need to create different activity-alias for displaying different icon i.e more icons = more activity-alias).

您也可以尝试使用活动别名来执行此操作,但在此您需要使用徽章值创建不同的图标,以防万一您需要在 2 个不同的应用程序图标之间切换(需要创建不同的活动别名来显示)不同的图标,即更多图标 = 更多活动别名)。

回答by amin saffar

Asus devices:

华硕设备:

public static class AsusHomeBadger implements Badger {

    private static final String INTENT_ACTION = "android.intent.action.BADGE_COUNT_UPDATE";
    private static final String INTENT_EXTRA_BADGE_COUNT = "badge_count";
    private static final String INTENT_EXTRA_PACKAGENAME = "badge_count_package_name";
    private static final String INTENT_EXTRA_ACTIVITY_NAME = "badge_count_class_name";

    @Override
    public void executeBadge(int badgeCount) {
        final Intent intent = new Intent(INTENT_ACTION);
        intent.putExtra(INTENT_EXTRA_BADGE_COUNT, badgeCount);
        intent.putExtra(INTENT_EXTRA_PACKAGENAME, componentName.getPackageName());
        intent.putExtra(INTENT_EXTRA_ACTIVITY_NAME, componentName.getClassName());
        intent.putExtra("badge_vip_count", 0);
        if (canResolveBroadcast(intent)) {
            AndroidUtilities.runOnUIThread(new Runnable() {
                @Override
                public void run() {
                    ApplicationLoader.applicationContext.sendBroadcast(intent);
                }
            });
        }
    }

    @Override
    public List<String> getSupportLaunchers() {
        return Arrays.asList("com.asus.launcher");
    }
}

Huawei devices:

华为设备:

public static class HuaweiHomeBadger implements Badger {

    @Override
    public void executeBadge(int badgeCount) {
        final Bundle localBundle = new Bundle();
        localBundle.putString("package", ApplicationLoader.applicationContext.getPackageName());
        localBundle.putString("class", componentName.getClassName());
        localBundle.putInt("badgenumber", badgeCount);
        AndroidUtilities.runOnUIThread(new Runnable() {
            @Override
            public void run() {
                try {
                    ApplicationLoader.applicationContext.getContentResolver().call(Uri.parse("content://com.huawei.android.launcher.settings/badge/"), "change_badge", null, localBundle);
                } catch (Exception e) {
                    FileLog.e(e);
                }
            }
        });
    }

    @Override
    public List<String> getSupportLaunchers() {
        return Arrays.asList(
                "com.huawei.android.launcher"
        );
    }
}

HTC devices:

HTC 设备:

public static class NewHtcHomeBadger implements Badger {

    public static final String INTENT_UPDATE_SHORTCUT = "com.htc.launcher.action.UPDATE_SHORTCUT";
    public static final String INTENT_SET_NOTIFICATION = "com.htc.launcher.action.SET_NOTIFICATION";
    public static final String PACKAGENAME = "packagename";
    public static final String COUNT = "count";
    public static final String EXTRA_COMPONENT = "com.htc.launcher.extra.COMPONENT";
    public static final String EXTRA_COUNT = "com.htc.launcher.extra.COUNT";

    @Override
    public void executeBadge(int badgeCount) {

        final Intent intent1 = new Intent(INTENT_SET_NOTIFICATION);
        intent1.putExtra(EXTRA_COMPONENT, componentName.flattenToShortString());
        intent1.putExtra(EXTRA_COUNT, badgeCount);

        final Intent intent = new Intent(INTENT_UPDATE_SHORTCUT);
        intent.putExtra(PACKAGENAME, componentName.getPackageName());
        intent.putExtra(COUNT, badgeCount);

        if (canResolveBroadcast(intent1) || canResolveBroadcast(intent)) {
            AndroidUtilities.runOnUIThread(new Runnable() {
                @Override
                public void run() {
                    ApplicationLoader.applicationContext.sendBroadcast(intent1);
                    ApplicationLoader.applicationContext.sendBroadcast(intent);
                }
            });
        }
    }

    @Override
    public List<String> getSupportLaunchers() {
        return Arrays.asList("com.htc.launcher");
    }
}

Samsung devices:

三星设备:

public static class SamsungHomeBadger implements Badger {
    private static final String CONTENT_URI = "content://com.sec.badge/apps?notify=true";
    private static final String[] CONTENT_PROJECTION = new String[]{"_id","class"};

    private static DefaultBadger defaultBadger;

    @Override
    public void executeBadge(int badgeCount) {
        try {
            if (defaultBadger == null) {
                defaultBadger = new DefaultBadger();
            }
            defaultBadger.executeBadge(badgeCount);
        } catch (Exception ignore) {

        }

        Uri mUri = Uri.parse(CONTENT_URI);
        ContentResolver contentResolver = ApplicationLoader.applicationContext.getContentResolver();
        Cursor cursor = null;
        try {
            cursor = contentResolver.query(mUri, CONTENT_PROJECTION, "package=?", new String[]{componentName.getPackageName()}, null);
            if (cursor != null) {
                String entryActivityName = componentName.getClassName();
                boolean entryActivityExist = false;
                while (cursor.moveToNext()) {
                    int id = cursor.getInt(0);
                    ContentValues contentValues = getContentValues(componentName, badgeCount, false);
                    contentResolver.update(mUri, contentValues, "_id=?", new String[]{String.valueOf(id)});
                    if (entryActivityName.equals(cursor.getString(cursor.getColumnIndex("class")))) {
                        entryActivityExist = true;
                    }
                }

                if (!entryActivityExist) {
                    ContentValues contentValues = getContentValues(componentName, badgeCount, true);
                    contentResolver.insert(mUri, contentValues);
                }
            }
        } finally {
            close(cursor);
        }
    }

    private ContentValues getContentValues(ComponentName componentName, int badgeCount, boolean isInsert) {
        ContentValues contentValues = new ContentValues();
        if (isInsert) {
            contentValues.put("package", componentName.getPackageName());
            contentValues.put("class", componentName.getClassName());
        }

        contentValues.put("badgecount", badgeCount);

        return contentValues;
    }

    @Override
    public List<String> getSupportLaunchers() {
        return Arrays.asList(
                "com.sec.android.app.launcher",
                "com.sec.android.app.twlauncher"
        );
    }
}

Sony devices:

索尼设备:

public static class SonyHomeBadger implements Badger {

    private static final String INTENT_ACTION = "com.sonyericsson.home.action.UPDATE_BADGE";
    private static final String INTENT_EXTRA_PACKAGE_NAME = "com.sonyericsson.home.intent.extra.badge.PACKAGE_NAME";
    private static final String INTENT_EXTRA_ACTIVITY_NAME = "com.sonyericsson.home.intent.extra.badge.ACTIVITY_NAME";
    private static final String INTENT_EXTRA_MESSAGE = "com.sonyericsson.home.intent.extra.badge.MESSAGE";
    private static final String INTENT_EXTRA_SHOW_MESSAGE = "com.sonyericsson.home.intent.extra.badge.SHOW_MESSAGE";

    private static final String PROVIDER_CONTENT_URI = "content://com.sonymobile.home.resourceprovider/badge";
    private static final String PROVIDER_COLUMNS_BADGE_COUNT = "badge_count";
    private static final String PROVIDER_COLUMNS_PACKAGE_NAME = "package_name";
    private static final String PROVIDER_COLUMNS_ACTIVITY_NAME = "activity_name";
    private static final String SONY_HOME_PROVIDER_NAME = "com.sonymobile.home.resourceprovider";
    private final Uri BADGE_CONTENT_URI = Uri.parse(PROVIDER_CONTENT_URI);

    private static AsyncQueryHandler mQueryHandler;

    @Override
    public void executeBadge(int badgeCount) {
        if (sonyBadgeContentProviderExists()) {
            executeBadgeByContentProvider(badgeCount);
        } else {
            executeBadgeByBroadcast(badgeCount);
        }
    }

    @Override
    public List<String> getSupportLaunchers() {
        return Arrays.asList("com.sonyericsson.home", "com.sonymobile.home");
    }

    private static void executeBadgeByBroadcast(int badgeCount) {
        final Intent intent = new Intent(INTENT_ACTION);
        intent.putExtra(INTENT_EXTRA_PACKAGE_NAME, componentName.getPackageName());
        intent.putExtra(INTENT_EXTRA_ACTIVITY_NAME, componentName.getClassName());
        intent.putExtra(INTENT_EXTRA_MESSAGE, String.valueOf(badgeCount));
        intent.putExtra(INTENT_EXTRA_SHOW_MESSAGE, badgeCount > 0);
        AndroidUtilities.runOnUIThread(new Runnable() {
            @Override
            public void run() {
                ApplicationLoader.applicationContext.sendBroadcast(intent);
            }
        });
    }

    private void executeBadgeByContentProvider(int badgeCount) {
        if (badgeCount < 0) {
            return;
        }

        if (mQueryHandler == null) {
            mQueryHandler = new AsyncQueryHandler(ApplicationLoader.applicationContext.getApplicationContext().getContentResolver()) {

                @Override
                public void handleMessage(Message msg) {
                    try {
                        super.handleMessage(msg);
                    } catch (Throwable ignore) {

                    }
                }
            };
        }
        insertBadgeAsync(badgeCount, componentName.getPackageName(), componentName.getClassName());
    }

    private void insertBadgeAsync(int badgeCount, String packageName, String activityName) {
        final ContentValues contentValues = new ContentValues();
        contentValues.put(PROVIDER_COLUMNS_BADGE_COUNT, badgeCount);
        contentValues.put(PROVIDER_COLUMNS_PACKAGE_NAME, packageName);
        contentValues.put(PROVIDER_COLUMNS_ACTIVITY_NAME, activityName);
        mQueryHandler.startInsert(0, null, BADGE_CONTENT_URI, contentValues);
    }

    private static boolean sonyBadgeContentProviderExists() {
        boolean exists = false;
        ProviderInfo info = ApplicationLoader.applicationContext.getPackageManager().resolveContentProvider(SONY_HOME_PROVIDER_NAME, 0);
        if (info != null) {
            exists = true;
        }
        return exists;
    }
}

Xiaomi devices:

小米设备:

public static class XiaomiHomeBadger implements Badger {

    public static final String INTENT_ACTION = "android.intent.action.APPLICATION_MESSAGE_UPDATE";
    public static final String EXTRA_UPDATE_APP_COMPONENT_NAME = "android.intent.extra.update_application_component_name";
    public static final String EXTRA_UPDATE_APP_MSG_TEXT = "android.intent.extra.update_application_message_text";

    @Override
    public void executeBadge(int badgeCount) {
        try {
            Class miuiNotificationClass = Class.forName("android.app.MiuiNotification");
            Object miuiNotification = miuiNotificationClass.newInstance();
            Field field = miuiNotification.getClass().getDeclaredField("messageCount");
            field.setAccessible(true);
            field.set(miuiNotification, String.valueOf(badgeCount == 0 ? "" : badgeCount));
        } catch (Throwable e) {
            final Intent localIntent = new Intent(INTENT_ACTION);
            localIntent.putExtra(EXTRA_UPDATE_APP_COMPONENT_NAME, componentName.getPackageName() + "/" + componentName.getClassName());
            localIntent.putExtra(EXTRA_UPDATE_APP_MSG_TEXT, String.valueOf(badgeCount == 0 ? "" : badgeCount));
            if (canResolveBroadcast(localIntent)) {
                AndroidUtilities.runOnUIThread(new Runnable() {
                    @Override
                    public void run() {
                        ApplicationLoader.applicationContext.sendBroadcast(localIntent);
                    }
                });
            }
        }
    }

    @Override
    public List<String> getSupportLaunchers() {
        return Arrays.asList(
                "com.miui.miuilite",
                "com.miui.home",
                "com.miui.miuihome",
                "com.miui.miuihome2",
                "com.miui.mihome",
                "com.miui.mihome2"
        );
    }
}

回答by Zohaib Amir

As of API 28, this is now officially supported:

从 API 28 开始,现在正式支持:

Starting with 8.0 (API level 26), notification badges (also known as notification dots) appear on a launcher icon when the associated app has an active notification. Users can long-press on the app icon to reveal the notifications (alongside any app shortcuts), as shown in figure 1.

These dots appear by default in launcher apps that support them and there's nothing your app needs to do. However, there might be situations in which you don't want the to notification dot to appear or you want to control exactly which notifications to appear there.

从 8.0(API 级别 26)开始,当关联的应用程序有活动通知时,通知标志(也称为通知点)会出现在启动器图标上。用户可以长按应用程序图标以显示通知(以及任何应用程序快捷方式),如图 1 所示。

这些点默认出现在支持它们的启动器应用程序中,您的应用程序无需执行任何操作。但是,在某些情况下,您可能不希望出现通知点,或者您想准确控制在那里显示哪些通知。

To set a custom number, call setNumber() on the notification:

要设置自定义号码,请在通知上调用 setNumber():

mNotification.setNumber(messageCount)

回答by grebulon

Here's how to do it for:

以下是如何做到这一点:

I think there's also a way to do it on the LG launcher, but haven't found out how yet.

我认为在 LG 启动器上也有一种方法可以做到这一点,但还没有找到方法。