Badge分析
所謂Badge源请,原本是iOS上的一個效果,但是被Android抄的多了边坤,也就成了Android的標(biāo)配。圖就不上了谅年,大家都懂的茧痒。
應(yīng)用icon顯示角標(biāo)實際上是在Launcher中實現(xiàn)的,其實不管是角標(biāo)還是其他對快捷方式的增刪改查融蹂,都是需要Launcher支持的旺订,應(yīng)用在增刪改查快捷方式和安裝弄企、卸載時,都會發(fā)出相應(yīng)的廣播区拳,通過這個廣播拘领,Launcher會對快捷方式進(jìn)行修改。
很慶幸樱调,Android原生ROM的Launcher并不具有給icon添加角標(biāo)的功能约素,因為Android的設(shè)計思想是把所有消息中心都放置在Notification通知欄中,只有iOS這種通知欄半殘廢的笆凌,才會使用角標(biāo)圣猎。這玩意兒,讓強迫癥患者菩颖,完全不能自理样漆,每日陷落在清除小紅點的生活中。
很悲劇晦闰,Android的AOSP代碼被國內(nèi)各大ROM廠商改的不能自理放祟。很多被修改的ROM都可以支持這種角標(biāo)的功能,甚至是很多第三方Launcher呻右,也提供了這種功能跪妥。其基本原理也是天下一大抄,都是監(jiān)聽發(fā)出的廣播來進(jìn)行快捷方式的修改声滥,但是眉撵,關(guān)鍵是沒有Google親爹的支持,所有的實現(xiàn)都不統(tǒng)一落塑,大家自己做自己的纽疟,沒有統(tǒng)一的接口,導(dǎo)致各種碎片化非常嚴(yán)重憾赁。
現(xiàn)在原理很清晰了污朽,關(guān)鍵就是要盡可能多的找到這些ROM、Launcher的修改icon的廣播龙考。
在調(diào)查該問題時蟆肆,我找到了https://github.com/leolin310148/ShortcutBadger 這個庫,很多地方參考了這個庫晦款,但是該庫由于很久沒有維護了炎功,所以我提取了里面收集的一些Badge的方法,并做了完善缓溅,這里對作者表示感謝蛇损。
各種ROM角標(biāo)分析
MIUI6&7 Badge
以下內(nèi)容來自MUI開發(fā)者平臺:
一、基本介紹
1、默認(rèn)的情況
當(dāng)app 向通知欄發(fā)送了一條通知 (通知不帶進(jìn)度條并且用戶可以刪除的)淤齐,那么桌面app icon角標(biāo)就會顯示1.此時app顯示的角標(biāo)數(shù)是和通知欄里app發(fā)送的通知數(shù)對應(yīng)的束世,即向通知欄發(fā)送了多少通知就會顯示多少角標(biāo)。
2床玻、通知可以定義角標(biāo)數(shù)
例如 有5封未讀郵件,通知欄里只會顯示一條通知沉帮,但是想讓角標(biāo)顯示5. 可以在發(fā)通知時加個標(biāo)示锈死。
修改MIUI的原理是通過反射拿到Notification的私有屬性extraNotification,但是這個extraNotification在MIUI系統(tǒng)中重定義了穆壕,這個類就是MIUI系統(tǒng)中的android.app.MiuiNotification這個類待牵,這個類里面有個私有屬性messageCount,我們只要改變這個messageCount值就能顯示的改變app icon的角標(biāo)數(shù)了喇勋。
二缨该、實現(xiàn)代碼
第三方app需要用反射來調(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
方法一
通過三星Launcher自己的廣播川背,來給應(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的包名和類名。因此熄云,你當(dāng)然可以在程序里面給其它任意一個App設(shè)置任意數(shù)量的角標(biāo)膨更,而且沒有任何提示,是的缴允,很流氓荚守,誰說不是呢,當(dāng)然別說是我告訴你的练般,你就所你是百度的矗漾。例如:
intent.putExtra("badge_count_package_name", "com.tencent.mobileqq");
intent.putExtra("badge_count_class_name", "com.tencent.mobileqq.activity.SplashActivity");
將包名和類名用QQ的替換下,然后你就可以隨心所欲薄料、為所欲為了敞贡。
方法二
https://github.com/shafty023/SamsungBadger
LG Badge
Samsung好基友,三星能用的都办,LG幾乎都可以用嫡锌,連Bug都一樣。
華為EMUI Badge
目前華為的ROM只支持給內(nèi)置的App添加角標(biāo)琳钉,華為本身沒有給出相應(yīng)的接口势木。
酷派 Badge
簡單粗暴,不支持歌懒。我喜歡啦桌,類原生。
ZUK ZUI Badge
ZUK作為一個非常小眾的手機廠商,居然在網(wǎng)上官方給出了詳細(xì)的開發(fā)者文檔甫男,就這一點且改,很多大廠都該好好打打自己的耳光。
由于實在找不到ZUK的測試機板驳,所以這里給出ZUK的開發(fā)者文檔又跛,有需要的自己看看吧:
http://developer.zuk.com/detail/12
HTC Badge
HTC雖然沒落了,但好歹是第一只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)然是在國外)滑进。該Launcher作為業(yè)界良心犀忱,提供了content provider供外界調(diào)用。與ZUK手機一樣扶关,良心大大的好峡碉,代碼如下:
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)的原理,我們可以做一些好玩的東西驮审。前面在說LG三星Sony的ROM的時候鲫寄,已經(jīng)提到了,廣播只需要傳人包名和啟動Activity名就可以給任意一個icon添加角標(biāo)疯淫,因此地来。。熙掺。直接看代碼吧:
/**
* Bug利用測試,請勿濫用
*
* @param view view
*/
public void madMode(View view) {
madMode(99);
}
/**
* 清除Bug角標(biāo)
*
* @param view view
*/
public void cleanMadMode(View view) {
madMode(0);
}
/**
* 獲取所有App的包名和啟動類名
*
* @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);
}
}
非常簡單的代碼未斑,就是通過PM找出具有啟動Intent的Activity,再取出其包名币绩,通過設(shè)置來添加角標(biāo)蜡秽。效果如圖:
OK,喪心病狂缆镣,逼死強迫癥處女座芽突。
請勿濫用,由此引起的一切問題董瞻,不要找我
請不要提桌面背景D觥L锇汀!
Github
忘記發(fā)地址了
https://github.com/xuyisheng/ShortcutHelper