Badge分析&如何逼死處女座

Badge分析

所謂Badge,原本是iOS上的一個(gè)效果,但是被Android抄的多了,也就成了Android的標(biāo)配。圖就不上了,大家都懂的。

應(yīng)用icon顯示角標(biāo)實(shí)際上是在Launcher中實(shí)現(xiàn)的,其實(shí)不管是角標(biāo)還是其他對(duì)快捷方式的增刪改查,都是需要Launcher支持的,應(yīng)用在增刪改查快捷方式和安裝、卸載時(shí),都會(huì)發(fā)出相應(yīng)的廣播,通過(guò)這個(gè)廣播,Launcher會(huì)對(duì)快捷方式進(jìn)行修改。

很慶幸,Android原生ROM的Launcher并不具有給icon添加角標(biāo)的功能,因?yàn)锳ndroid的設(shè)計(jì)思想是把所有消息中心都放置在Notification通知欄中,只有iOS這種通知欄半殘廢的,才會(huì)使用角標(biāo)。這玩意兒,讓強(qiáng)迫癥患者,完全不能自理,每日陷落在清除小紅點(diǎn)的生活中。

很悲劇,Android的AOSP代碼被國(guó)內(nèi)各大ROM廠商改的不能自理。很多被修改的ROM都可以支持這種角標(biāo)的功能,甚至是很多第三方Launcher,也提供了這種功能。其基本原理也是天下一大抄,都是監(jiān)聽(tīng)發(fā)出的廣播來(lái)進(jìn)行快捷方式的修改,但是,關(guān)鍵是沒(méi)有Google親爹的支持,所有的實(shí)現(xiàn)都不統(tǒng)一,大家自己做自己的,沒(méi)有統(tǒng)一的接口,導(dǎo)致各種碎片化非常嚴(yán)重。

現(xiàn)在原理很清晰了,關(guān)鍵就是要盡可能多的找到這些ROM、Launcher的修改icon的廣播。

在調(diào)查該問(wèn)題時(shí),我找到了https://github.com/leolin310148/ShortcutBadger 這個(gè)庫(kù),很多地方參考了這個(gè)庫(kù),但是該庫(kù)由于很久沒(méi)有維護(hù)了,所以我提取了里面收集的一些Badge的方法,并做了完善,這里對(duì)作者表示感謝。

各種ROM角標(biāo)分析

MIUI6&7 Badge

以下內(nèi)容來(lái)自MUI開(kāi)發(fā)者平臺(tái):

一、基本介紹

1、默認(rèn)的情況

當(dāng)app 向通知欄發(fā)送了一條通知 (通知不帶進(jìn)度條并且用戶可以刪除的),那么桌面app icon角標(biāo)就會(huì)顯示1.此時(shí)app顯示的角標(biāo)數(shù)是和通知欄里app發(fā)送的通知數(shù)對(duì)應(yīng)的,即向通知欄發(fā)送了多少通知就會(huì)顯示多少角標(biāo)。

2、通知可以定義角標(biāo)數(shù)

例如 有5封未讀郵件,通知欄里只會(huì)顯示一條通知,但是想讓角標(biāo)顯示5. 可以在發(fā)通知時(shí)加個(gè)標(biāo)示。

修改MIUI的原理是通過(guò)反射拿到Notification的私有屬性extraNotification,但是這個(gè)extraNotification在MIUI系統(tǒng)中重定義了,這個(gè)類(lèi)就是MIUI系統(tǒng)中的android.app.MiuiNotification這個(gè)類(lèi),這個(gè)類(lèi)里面有個(gè)私有屬性messageCount,我們只要改變這個(gè)messageCount值就能顯示的改變app icon的角標(biāo)數(shù)了。

二、實(shí)現(xiàn)代碼

第三方app需要用反射來(lái)調(diào)用,參考代碼:

/**
 * 設(shè)置MIUI的Badge
 *
 * @param context context
 * @param count   count
 */
private static void setBadgeOfMIUI(Context context, int count) {
    Log.d("xys", "Launcher : MIUI");
    NotificationManager mNotificationManager = (NotificationManager) context
            .getSystemService(Context.NOTIFICATION_SERVICE);
    Notification.Builder builder = new Notification.Builder(context)
            .setContentTitle("title").setContentText("text").setSmallIcon(R.mipmap.ic_launcher);
    Notification notification = builder.build();
    try {
        Field field = notification.getClass().getDeclaredField("extraNotification");
        Object extraNotification = field.get(notification);
        Method method = extraNotification.getClass().getDeclaredMethod("setMessageCount", int.class);
        method.invoke(extraNotification, count);
    } catch (Exception e) {
        e.printStackTrace();
    }
    mNotificationManager.notify(0, notification);
}

Sony Badge

https://forsberg.ax/en/blog/android-notification-badge-app-icon-sony/

Samsung Badge

方法一

通過(guò)三星Launcher自己的廣播,來(lái)給應(yīng)用添加角標(biāo):

/**
 * 設(shè)置三星的Badge
 *
 * @param context context
 * @param count   count
 */
private static void setBadgeOfSumsung(Context context, int count) {
    // 獲取你當(dāng)前的應(yīng)用
    String launcherClassName = getLauncherClassName(context);
    if (launcherClassName == null) {
        return;
    }
    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", launcherClassName);
    context.sendBroadcast(intent);
}

此方法不需要任何權(quán)限,只需要知道App的包名和類(lèi)名。因此,你當(dāng)然可以在程序里面給其它任意一個(gè)App設(shè)置任意數(shù)量的角標(biāo),而且沒(méi)有任何提示,是的,很流氓,誰(shuí)說(shuō)不是呢,當(dāng)然別說(shuō)是我告訴你的,你就所你是百度的。例如:

intent.putExtra("badge_count_package_name", "com.tencent.mobileqq");
    intent.putExtra("badge_count_class_name", "com.tencent.mobileqq.activity.SplashActivity");

將包名和類(lèi)名用QQ的替換下,然后你就可以隨心所欲、為所欲為了。

方法二

https://github.com/shafty023/SamsungBadger

LG Badge

Samsung好基友,三星能用的,LG幾乎都可以用,連Bug都一樣。

華為EMUI Badge

目前華為的ROM只支持給內(nèi)置的App添加角標(biāo),華為本身沒(méi)有給出相應(yīng)的接口。

酷派 Badge

簡(jiǎn)單粗暴,不支持。我喜歡,類(lèi)原生。

ZUK ZUI Badge

ZUK作為一個(gè)非常小眾的手機(jī)廠商,居然在網(wǎng)上官方給出了詳細(xì)的開(kāi)發(fā)者文檔,就這一點(diǎn),很多大廠都該好好打打自己的耳光。

由于實(shí)在找不到ZUK的測(cè)試機(jī),所以這里給出ZUK的開(kāi)發(fā)者文檔,有需要的自己看看吧:

http://developer.zuk.com/detail/12

HTC Badge

HTC雖然沒(méi)落了,但好歹是第一只Android的寄生獸,好歹也支持下。

Intent intentNotification = new Intent("com.htc.launcher.action.SET_NOTIFICATION");
ComponentName localComponentName = new ComponentName(context.getPackageName(),
        AppInfoUtil.getLauncherClassName(context));
intentNotification.putExtra("com.htc.launcher.extra.COMPONENT", localComponentName.flattenToShortString());
intentNotification.putExtra("com.htc.launcher.extra.COUNT", count);
context.sendBroadcast(intentNotification);

Intent intentShortcut = new Intent("com.htc.launcher.action.UPDATE_SHORTCUT");
intentShortcut.putExtra("packagename", context.getPackageName());
intentShortcut.putExtra("count", count);
context.sendBroadcast(intentShortcut);

其原理同樣是使用廣播,不解釋了。

錘子

錘子很遺憾,使用的是原生Launcher進(jìn)行的修改,只有System App具有獲得角標(biāo)的權(quán)限。

Nova Badge

Nova是一款非常贊的Launcher,作為第三方Launcher,它的使用率非常高(當(dāng)然是在國(guó)外)。該Launcher作為業(yè)界良心,提供了content provider供外界調(diào)用。與ZUK手機(jī)一樣,良心大大的好,代碼如下:

ContentValues contentValues = new ContentValues();
contentValues.put("tag", context.getPackageName() + "/" +
        AppInfoUtil.getLauncherClassName(context));
contentValues.put("count", count);
context.getContentResolver().insert(Uri.parse("content://com.teslacoilsw.notifier/unread_count"),
        contentValues);

一些好玩的

在知道了一些ROM的生成角標(biāo)的原理,我們可以做一些好玩的東西。前面在說(shuō)LG三星Sony的ROM的時(shí)候,已經(jīng)提到了,廣播只需要傳人包名和啟動(dòng)Activity名就可以給任意一個(gè)icon添加角標(biāo),因此。。。直接看代碼吧:

/**
 * Bug利用測(cè)試,請(qǐng)勿濫用
 *
 * @param view view
 */
public void madMode(View view) {
    madMode(99);
}

/**
 * 清除Bug角標(biāo)
 *
 * @param view view
 */
public void cleanMadMode(View view) {
    madMode(0);
}

/**
 * 獲取所有App的包名和啟動(dòng)類(lèi)名
 *
 * @param count count
 */
private void madMode(int count) {
    Intent intent = new Intent(Intent.ACTION_MAIN, null);
    intent.addCategory(Intent.CATEGORY_LAUNCHER);
    List<ResolveInfo> list = getPackageManager().queryIntentActivities(
            intent, PackageManager.GET_ACTIVITIES);
    for (int i = 0; i < list.size(); i++) {
        ActivityInfo activityInfo = list.get(i).activityInfo;
        String activityName = activityInfo.name;
        String packageName = activityInfo.applicationInfo.packageName;
        BadgeUtil.setBadgeOfMadMode(getApplicationContext(), count, packageName, activityName);
    }
}

非常簡(jiǎn)單的代碼,就是通過(guò)PM找出具有啟動(dòng)Intent的Activity,再取出其包名,通過(guò)設(shè)置來(lái)添加角標(biāo)。效果如圖:

device-2015-12-07-141255.png
device-2015-12-07-141314.png
device-2015-12-07-141337.png

OK,喪心病狂,逼死強(qiáng)迫癥處女座。

請(qǐng)勿濫用,由此引起的一切問(wèn)題,不要找我

請(qǐng)不要提桌面背景!?。?/p>

Github

忘記發(fā)地址了
https://github.com/xuyisheng/ShortcutHelper

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,326評(píng)論 25 708
  • 內(nèi)容抽屜菜單ListViewWebViewSwitchButton按鈕點(diǎn)贊按鈕進(jìn)度條TabLayout圖標(biāo)下拉刷新...
    皇小弟閱讀 47,183評(píng)論 22 665
  • 安卓原生的系統(tǒng)Launcher并不支持角標(biāo)顯示,但是大部分手機(jī)廠商或者第三方定制的Launcher都有做在AOSP...
    charmingspring閱讀 3,481評(píng)論 0 51
  • 突然想寫(xiě)些東西,這是寫(xiě)的第一篇算是隨筆吧,還稱(chēng)不上是文章!一般最想寫(xiě)的東西都是離你最近的或最有感觸的東西,所以對(duì)我...
    內(nèi)有基坑閱讀 694評(píng)論 14 8
  • 內(nèi)心深處那個(gè)小孩,一層層地將作的繭剝開(kāi)。慢慢地看見(jiàn)一個(gè)鮮血淋漓、傷痕累累的自己。這是你千辛萬(wàn)苦追逐的呀!外面的陽(yáng)光...
    清水浮萍閱讀 268評(píng)論 0 0

友情鏈接更多精彩內(nèi)容