Badge分析&如何逼死處女座
Badge分析
所謂Badge,原本是iOS上的一個效果,但是被Android抄的多了,也就成了Android的標配。圖就不上了,大家都懂的。
應用icon顯示角標實際上是在Launcher中實現的,其實不管是角標還是其他對快捷方式的增刪改查,都是需要Launcher支援的,應用在增刪改查快捷方式和安裝、解除安裝時,都會發出相應的廣播,通過這個廣播,Launcher會對快捷方式進行修改。
很慶幸,Android原生ROM的Launcher並不具有給icon新增角標的功能,因為Android的設計思想是把所有訊息中心都放置在Notification通知欄中,只有iOS這種通知欄半殘廢的,才會使用角標。這玩意兒,讓強迫症患者,完全不能自理,每日陷落在清除小紅點的生活中。
很悲劇,Android的AOSP程式碼被國內各大ROM廠商改的不能自理。很多被修改的ROM都可以支援這種角標的功能,甚至是很多第三方Launcher,也提供了這種功能。其基本原理也是天下一大抄,都是監聽發出的廣播來進行快捷方式的修改,但是,關鍵是沒有Google親爹的支援,所有的實現都不統一,大家自己做自己的,沒有統一的介面,導致各種碎片化非常嚴重。
現在原理很清晰了,關鍵就是要儘可能多的找到這些ROM、Launcher的修改icon的廣播。
在調查該問題時,我找到了https://github.com/leolin310148/ShortcutBadger 這個庫,很多地方參考了這個庫,但是該庫由於很久沒有維護了,所以我提取了裡面收集的一些Badge的方法,並做了完善,這裡對作者表示感謝。
各種ROM角標分析
MIUI6&7 Badge
以下內容來自MUI開發者平臺:
一、基本介紹
1、預設的情況
當app 向通知欄傳送了一條通知 (通知不帶進度條並且使用者可以刪除的),那麼桌面app icon角標就會顯示1.此時app顯示的角標數是和通知欄裡app傳送的通知數對應的,即向通知欄傳送了多少通知就會顯示多少角標。
2、通知可以定義角標數
例如 有5封未讀郵件,通知欄裡只會顯示一條通知,但是想讓角標顯示5. 可以在發通知時加個標示。
修改MIUI的原理是通過反射拿到Notification的私有屬性extraNotification,但是這個extraNotification在MIUI系統中重定義了,這個類就是MIUI系統中的android.app.MiuiNotification這個類,這個類裡面有個私有屬性messageCount,我們只要改變這個messageCount
值就能顯示的改變app icon的角標數了。二、實現程式碼
第三方app需要用反射來呼叫,參考程式碼:
/**
* 設定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
Samsung Badge
方法一
通過三星Launcher自己的廣播,來給應用新增角標:
/**
* 設定三星的Badge
*
* @param context context
* @param count count
*/
private static void setBadgeOfSumsung(Context context, int count) {
// 獲取你當前的應用
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);
}
此方法不需要任何許可權,只需要知道App的包名和類名。因此,你當然可以在程式裡面給其它任意一個App設定任意數量的角標,而且沒有任何提示,是的,很流氓,誰說不是呢,當然別說是我告訴你的,你就所你是百度的。例如:
intent.putExtra("badge_count_package_name", "com.tencent.mobileqq");
intent.putExtra("badge_count_class_name", "com.tencent.mobileqq.activity.SplashActivity");
將包名和類名用QQ的替換下,然後你就可以隨心所欲、為所欲為了。
方法二
LG Badge
Samsung好基友,三星能用的,LG幾乎都可以用,連Bug都一樣。
華為EMUI Badge
目前華為的ROM只支援給內建的App新增角標,華為本身沒有給出相應的介面。
酷派 Badge
簡單粗暴,不支援。我喜歡,類原生。
ZUK ZUI Badge
ZUK作為一個非常小眾的手機廠商,居然在網上官方給出了詳細的開發者文件,就這一點,很多大廠都該好好打打自己的耳光。
由於實在找不到ZUK的測試機,所以這裡給出ZUK的開發者文件,有需要的自己看看吧:
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進行的修改,只有System App具有獲得角標的許可權。
Nova Badge
Nova是一款非常讚的Launcher,作為第三方Launcher,它的使用率非常高(當然是在國外)。該Launcher作為業界良心,提供了content provider供外界呼叫。與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的生成角標的原理,我們可以做一些好玩的東西。前面在說LG三星Sony的ROM的時候,已經提到了,廣播只需要傳人包名和啟動Activity名就可以給任意一個icon新增角標,因此。。。直接看程式碼吧:
/**
* Bug利用測試,請勿濫用
*
* @param view view
*/
public void madMode(View view) {
madMode(99);
}
/**
* 清除Bug角標
*
* @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,再取出其包名,通過設定來新增角標。效果如圖:
OK,喪心病狂,逼死強迫症處女座。
請勿濫用,由此引起的一切問題,不要找我
請不要提桌面背景!!!