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)。效果如圖:



OK,喪心病狂,逼死強(qiáng)迫癥處女座。
請(qǐng)勿濫用,由此引起的一切問(wèn)題,不要找我
請(qǐng)不要提桌面背景!?。?/p>
Github
忘記發(fā)地址了
https://github.com/xuyisheng/ShortcutHelper