54

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

4

6 回答 6

35

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

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

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

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

您会注意到,使用小部件或图标几乎没有区别,因为它们可以是相同的大小并且看起来相同。

于 2010-05-25T14:34:23.597 回答
16

这也适用于索尼的 Xperia Home。我在这里写过博客,但重要的部分如下。Sony 设备使用一个名为BadgeReciever.

  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);
    

我已排除有关如何找到此问题的详细信息以保持答案简短,但所有内容都可以在博客中找到。对某人来说可能是一本有趣的书。

我还在这里发布了一个单独的 SO 问题,一旦我被允许,我会在那里添加完整的答案(需要 10 名声望才能在 8 小时内回答我自己的问题)。

于 2013-11-26T13:51:13.127 回答
9

ShortcutBadger库使之成为可能,并与 LG、Sony、Samsung、HTC 和其他自定义启动器一起使用。

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

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

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

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

或者

您也可以尝试使用活动别名来这样做,但在此您需要创建带有徽章值的不同图标,这将非常适合 - 您需要在 2 个不同的应用程序图标之间切换(需要创建不同的活动别名来显示不同的图标,即更多图标=更多活动别名)。

于 2015-11-16T07:40:07.090 回答
2

华硕设备:

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");
    }
}

华为设备:

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 设备:

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");
    }
}

三星设备:

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"
        );
    }
}

索尼设备:

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;
    }
}

小米设备:

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"
        );
    }
}
于 2019-01-19T10:22:39.713 回答
0

以下是如何做到这一点:

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

于 2014-09-28T12:22:54.210 回答
0

从 API 26 开始,现在正式支持

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

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

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

mNotification.setNumber(messageCount)
于 2019-11-17T07:24:57.843 回答