-- 做者 謝恩銘 轉載請註明出處javascript
角標是什麼意思呢?java
看下圖便可明瞭:android
能夠看到圖中的樂購這個app右上角的紅色的圓圈,裏面有10這個數字的,就是一種角標。git
角標,英語是badge,也就是「徽章,像章,獎章; 象徵,標記」的意思。程序員
通常來講,應用的角標是用來標記有多少條提醒(Notification)沒讀(unread),一旦點擊提示進應用閱讀了,角標也會消失。github
角標本來是蘋果的iOS中的東西,Android原生並不支持角標,由於Google的意思是讓你們用Notification(提示欄)便可,角標實在大有讓處女座「跳崖」的風險。幸虧我不是...編程
最近公司的項目中,客戶的一個新需求是在咱們的加密信息應用上加上角標功能,由於咱們的合做夥伴是三星(能夠參看個人這篇文章:程序員在法國 | 我被法國國防部盯上了!),所以我就去網上找相關資料。微信
找的時候,才知道上面所說的Android原生不支持角標一事。不過無妨,厲害的Android第三方廠商能夠經過在自定義的Launcher(啓動器)中操做來實現添加角標。app
我在第一時間固然是去找三星的移動設備如何添加角標,不過卻有幸找到了Github上的比較普適的項目。ide
把我導向Github的天然是Stack Overflow,而把我導向Stack Overflow的就是Google,所以我會說:爲何程序員必定要會用Google和Stack Overflow? 。
通常來講,如今被引用最多的Android添加和去除角標的Github項目是這位中國人寫的:github.com/leolin31014…
這個項目挺不錯,雖然更新不是特別勤快,但最近一次更新是在2016年10月31日,也就是兩個月前,還能夠接受。
《Android羣英傳》和《Android羣英傳:神兵利器》的做者 徐宜生 也在本身的Github上建了一個項目:github.com/xuyisheng/S… ,挺有意思,裏面還有號稱「瘋狂模式」的爲全部在手機桌面上的應用加上99的角標數的功能,固然了,去除的代碼也有,否則處女座豈不是要暈了~
添加角標的原理就是發送一個Broadcast(廣播),在廣播的Intent中指定須要被添加角標的應用的packageName(包名),className(類名),count(角標數目)。固然了,不一樣廠商的手機的角標操做的Intent的action是不同的。
所以,咱們若是要給本身的手機裏的應用添加角標,只須要簡單的利用上面兩個項目中的代碼便可,通常不須要把所有項目搬過來。固然了,若是你要適配全部手機,那麼能夠全盤引用項目。
好比我要給三星的手機的應用添加角標,那麼我只須要作如下的幾步便可:
<uses-permission android:name="com.sec.android.provider.badge.permission.READ" />
<uses-permission android:name="com.sec.android.provider.badge.permission.WRITE" />複製代碼
public class BadgeUtils {
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";
public static void setBadgeCount(Context context, ComponentName componentName, int badgeCount) {
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());
context.sendBroadcast(intent);
}
}複製代碼
使用上面的代碼時,只須要傳入三個參數,也就是:
applicationContext.getPackageManager()
.getLaunchIntentForPackage(applicationContext.getPackageName())
.getComponent()複製代碼
固然了,若是你不想要傳入三個參數這麼麻煩,你也能夠再寫一個方法getLauncherClassName,就只須要傳入兩個參數便可。BadgeUtils中的代碼變爲:
public class BadgeUtils {
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";
public static void setBadgeCount(Context context, int badgeCount) {
String launcherClassName = getLauncherClassName(context);
if (launcherClassName == null) {
return;
}
Intent intent = new Intent(INTENT_ACTION);
intent.putExtra(INTENT_EXTRA_BADGE_COUNT, badgeCount);
intent.putExtra(INTENT_EXTRA_PACKAGENAME, context.getPackageName());
intent.putExtra(INTENT_EXTRA_ACTIVITY_NAME, launcherClassName);
context.sendBroadcast(intent);
}
private static String getLauncherClassName(Context context) {
PackageManager pm = context.getPackageManager();
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, 0);
for (ResolveInfo resolveInfo : resolveInfos) {
String pkgName = resolveInfo.activityInfo.applicationInfo.packageName;
if (pkgName.equalsIgnoreCase(context.getPackageName())) {
String className = resolveInfo.activityInfo.name;
return className;
}
}
return null;
}
}複製代碼
使用時傳入兩個參數便可:
要清除應用的角標就很簡單了,給badgeCount傳入0便可。
BadgeUtils.setBadgeCount(context,
context.getPackageManager()
.getLaunchIntentForPackage(context.getPackageName())
.getComponent(),
0);複製代碼
或者
BadgeUtils.setBadgeCount(context, 0);複製代碼
上面的 github.com/leolin31014… 這個項目中,基本已經包含了大多數能夠定製角標的Android生產廠商的添加角標的代碼實現,不過它也提到:
三星和LG(這兩個難兄難弟)的代碼有不少相似,連角標處理的廣播的Intent中的action也是同樣的,都是:
"android.intent.action.BADGE_COUNT_UPDATE"複製代碼
可是做者在三星和LG的兩個角標操做實現類中寫了註釋:
// Deprecated, Samsung devices will use DefaultBadger
// Deprecated, LG devices will use DefaultBadger複製代碼
意思是「三星和LG的實現代碼已經Deprecated(失效了),請用DefaultBadger類」。
所以,這兩個須要用 github.com/leolin31014… 中的實現:
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(Context context, ComponentName componentName, int badgeCount) throws ShortcutBadgeException {
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());
if (BroadcastHelper.canResolveBroadcast(context, intent)) {
context.sendBroadcast(intent);
} else {
throw new ShortcutBadgeException("unable to resolve intent: " + intent.toString());
}
}複製代碼
不過上面的代碼有一個小問題,就是那句
if (BroadcastHelper.canResolveBroadcast(context, intent)) {複製代碼
在有些設備(好比Samsung Galaxy S5)上會拋出異常(Exception),找不處處理"android.intent.action.BADGE_COUNT_UPDATE"這個Intent的BroadcastReceiver,很奇怪。
但有些設備(好比Samsung Galaxy A5)上又運行正常,沒有拋出異常。
解決辦法是去除這一個檢測,把
if (BroadcastHelper.canResolveBroadcast(context, intent)) {
context.sendBroadcast(intent);
} else {
throw new ShortcutBadgeException("unable to resolve intent: " + intent.toString());
}複製代碼
替換爲簡單的
context.sendBroadcast(intent);複製代碼
就能夠了。
也就是我上面本身實做時的代碼。
Android的角標添加和移除畢竟是基於各大手機廠商的Launcher的定製,所以不是正統的Android技巧,隨着廠商的Launcher的改變,也許你的代碼將來就不必定有用了,所以須要不斷修改,「推陳出新」。
不過正所謂「生命在於折騰」,而這也是咱們喜歡Android系統的緣由。這個萌萌的機器人能夠經得起咱們隨意折騰,在嵌入式領域的應用前途也是很不錯的。
你們在平時學習編程的時候,也能夠把本身的代碼或經驗彙總到Github項目,一來惠己利人,二來提升本身的業界知名度。
人世間,
萬千情感皆有溫度,
千萬代碼似有性格。
這裏有原創教程,IT叢林......
和你一塊兒探索程序人生。
微信公衆號「程序員聯盟」ProgrammerLeague
我是謝恩銘,在巴黎奮鬥的嵌入式軟件工程師。
我的簡介熱愛生活,喜歡游泳,略懂烹飪。人生格言:「向着標杆直跑」