当前位置: 首页 > backend >正文

学员投稿:华为,ov等手机主流大厂桌面未读计数角标更新接口汇总

背景:

上一篇文章马哥有分享关于桌面角标应该如何设计的文章:
聊一聊android桌面的未读计数角标应该如何设计呢?
有一个学员朋友就积极联系马哥,说他原来做第三方应用的,有负责过app在各个手机桌面显示角标功能,对这个角标适配深感麻烦,也非常希望google官方可以完全统一这一块的桌面角标功能各个手机厂商各自为战的情况。
学员朋友也分享出来的了他以前适配各个手机厂商的桌面角标的相关详细接口调用,当时适配有10种手机的桌面角标功能。
下面学员朋友开始分享app适配各个手机厂商的桌面角标。

适配整体情况:

适配角标一般需要去各个厂商的官方文档中进行寻找,有的厂商还经常没有文档,这个时候可能就需要通过一些官方商务渠道或者论坛售后渠道等联系获取适配方案。不过最简单方法当然是去网上搜人家现成开源的,当时我们就有参考github上一个开源的角标适配库,用它就可以实现大部分主流手机桌面的角标功能。

接口设计讲解:

主要有以下2个接口方法:

void executeBadge
主要负责真正实现对角标的设置,也就是在这个方法中实现对手机厂商的角标设置

List getSupportLaunchers()
主要来实现提供出哪些桌面包名是可以支持角标的,因为有的厂商可能有一些桌面是不支持的。

主流厂商方案

其实主要的这些厂商普遍分为3个技术实现方向:

1.采用类似华为的方案,采用contentprovider,使用call接口调用传递app角标数据

2.采用Brocast广播方案,相关角标数据使用广播发送

3、小米方案特殊一些,采用通知相关接口,属于比较另类

下面列出一些主流手机的桌面角标接口实现(因为本人不做app好些年了,不确定下面接口是否已经更新变化)

华为

public class HuaweiHomeBadger extends Badger {private final Uri CONTENT_URI = Uri.parse("content://com.huawei.android.launcher.settings/badge/");@Overridepublic void executeBadge(Context context, ComponentName componentName, int badgeCount) throws ShortcutBadgeException {Bundle localBundle = new Bundle();localBundle.putString("package", context.getPackageName());localBundle.putString("class", componentName.getClassName());localBundle.putInt("badgenumber", badgeCount);context.getContentResolver().call(CONTENT_URI, "change_badge", null, localBundle);}@Overridepublic List<String> getSupportLaunchers() {return Arrays.asList("com.huawei.android.launcher");}}

OPPO

public class OPPOHomeBader extends Badger {private static final String PROVIDER_CONTENT_URI = "content://com.android.badge/badge";private static final String INTENT_ACTION = "com.oppo.unsettledevent";private static final String INTENT_EXTRA_PACKAGENAME = "pakeageName";private static final String INTENT_EXTRA_BADGE_COUNT = "number";private static final String INTENT_EXTRA_BADGE_UPGRADENUMBER = "upgradeNumber";private static final String INTENT_EXTRA_BADGEUPGRADE_COUNT = "app_badge_count";private static int ROMVERSION = -1;@TargetApi(Build.VERSION_CODES.HONEYCOMB)@Overridepublic void executeBadge(Context context, ComponentName componentName, int badgeCount) throws ShortcutBadgeException {if (badgeCount == 0) {badgeCount = -1;}Intent intent = new Intent(INTENT_ACTION);intent.putExtra(INTENT_EXTRA_PACKAGENAME, componentName.getPackageName());intent.putExtra(INTENT_EXTRA_BADGE_COUNT, badgeCount);intent.putExtra(INTENT_EXTRA_BADGE_UPGRADENUMBER, badgeCount);if (canResolveBroadcast(context, intent)) {context.sendBroadcast(intent);} else {int version = getSupportVersion();if (version == 6) {try {Bundle extras = new Bundle();extras.putInt(INTENT_EXTRA_BADGEUPGRADE_COUNT, badgeCount);context.getContentResolver().call(Uri.parse(PROVIDER_CONTENT_URI), "setAppBadgeCount", null, extras);} catch (Throwable th) {throw new ShortcutBadgeException("unable to resolve intent: " + intent.toString());}}}}@Overridepublic List<String> getSupportLaunchers() {return Collections.singletonList("com.oppo.launcher");}private int getSupportVersion() {int i = ROMVERSION;if (i >= 0) {return ROMVERSION;}try {i = ((Integer) executeClassLoad(getClass("com.color.os.ColorBuild"), "getColorOSVERSION", null, null)).intValue();} catch (Exception e) {i = 0;}if (i == 0) {try {String str = getSystemProperty("ro.build.version.opporom");if (str.startsWith("V1.4")) {return 3;}if (str.startsWith("V2.0")) {return 4;}if (str.startsWith("V2.1")) {return 5;}} catch (Exception ignored) {}}ROMVERSION = i;return ROMVERSION;}private Object executeClassLoad(Class cls, String str, Class[] clsArr, Object[] objArr) {Object obj = null;if (!(cls == null || checkObjExists(str))) {Method method = getMethod(cls, str, clsArr);if (method != null) {method.setAccessible(true);try {obj = method.invoke(null, objArr);} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}}return obj;}private Method getMethod(Class cls, String str, Class[] clsArr) {Method method = null;if (cls == null || checkObjExists(str)) {return method;}try {cls.getMethods();cls.getDeclaredMethods();return cls.getDeclaredMethod(str, clsArr);} catch (Exception e) {try {return cls.getMethod(str, clsArr);} catch (Exception e2) {return cls.getSuperclass() != null ? getMethod(cls.getSuperclass(), str, clsArr) : method;}}}private Class getClass(String str) {Class cls = null;try {cls = Class.forName(str);} catch (ClassNotFoundException ignored) {}return cls;}private boolean checkObjExists(Object obj) {return obj == null || obj.toString().equals("") || obj.toString().trim().equals("null");}private String getSystemProperty(String propName) {String line;BufferedReader input = null;try {Process p = Runtime.getRuntime().exec("getprop " + propName);input = new BufferedReader(new InputStreamReader(p.getInputStream()), 1024);line = input.readLine();} catch (IOException ex) {return null;} finally {try {if (input != null) {input.close();}} catch (IOException var2) {}}return line;}
}

vivo

public class VivoHomeBadger extends Badger {@Overridepublic void executeBadge(Context context, ComponentName componentName, int badgeCount) throws ShortcutBadgeException {Intent intent = new Intent("launcher.action.CHANGE_APPLICATION_NOTIFICATION_NUM");intent.putExtra("packageName", context.getPackageName());intent.putExtra("className", componentName.getClassName());intent.putExtra("notificationNum", badgeCount);context.sendBroadcast(intent);}@Overridepublic List<String> getSupportLaunchers() {return Arrays.asList("com.vivo.launcher");}
}

中兴

public class ZTEHomeBadger extends Badger {private final Uri CONTENT_URI = Uri.parse("content://com.android.launcher3.cornermark.unreadbadge");@Overridepublic void executeBadge(Context context, ComponentName componentName, int badgeCount)throws ShortcutBadgeException {Bundle extra = new Bundle();extra.putInt("app_badge_count", badgeCount);extra.putString("app_badge_component_name", componentName.flattenToString());if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {context.getContentResolver().call(CONTENT_URI, "setAppUnreadCount", null, extra);}}@Overridepublic List<String> getSupportLaunchers() {return new ArrayList<String>(0);}} 

联想Zuk

需在设置 – 通知和状态栏 – 应用角标管理 中开启应用

public class ZukHomeBadger extends Badger {private final Uri CONTENT_URI = Uri.parse("content://com.android.badge/badge");@TargetApi(Build.VERSION_CODES.HONEYCOMB)@Overridepublic void executeBadge(Context context, ComponentName componentName, int badgeCount) throws ShortcutBadgeException {Bundle extra = new Bundle();extra.putInt("app_badge_count", badgeCount);context.getContentResolver().call(CONTENT_URI, "setAppBadgeCount", null, extra);}@Overridepublic List<String> getSupportLaunchers() {return Collections.singletonList("com.zui.launcher");}}

Sony

public class SonyHomeBadger extends Badger {private static final String INTENT_ACTION = "com.sonyericsson.home.action.UPDATE_BADGE";private static final String INTENT_EXTRA_PACKAGE_NAME = "com.sonyericsson.home.intent.extra.badge.PACKAGE_NAME";private static final String INTENT_EXTRA_ACTIVITY_NAME = "com.sonyericsson.home.intent.extra.badge.ACTIVITY_NAME";private static final String INTENT_EXTRA_MESSAGE = "com.sonyericsson.home.intent.extra.badge.MESSAGE";private static final String INTENT_EXTRA_SHOW_MESSAGE = "com.sonyericsson.home.intent.extra.badge.SHOW_MESSAGE";private static final String PROVIDER_CONTENT_URI = "content://com.sonymobile.home.resourceprovider/badge";private static final String PROVIDER_COLUMNS_BADGE_COUNT = "badge_count";private static final String PROVIDER_COLUMNS_PACKAGE_NAME = "package_name";private static final String PROVIDER_COLUMNS_ACTIVITY_NAME = "activity_name";private static final String SONY_HOME_PROVIDER_NAME = "com.sonymobile.home.resourceprovider";private final Uri BADGE_CONTENT_URI = Uri.parse(PROVIDER_CONTENT_URI);private AsyncQueryHandler mQueryHandler;@Overridepublic void executeBadge(Context context, ComponentName componentName,int badgeCount) throws ShortcutBadgeException {if (sonyBadgeContentProviderExists(context)) {executeBadgeByContentProvider(context, componentName, badgeCount);} else {executeBadgeByBroadcast(context, componentName, badgeCount);}}@Overridepublic List<String> getSupportLaunchers() {return Arrays.asList("com.sonyericsson.home", "com.sonymobile.home");}private static void executeBadgeByBroadcast(Context context, ComponentName componentName, int badgeCount) {Intent intent = new Intent(INTENT_ACTION);intent.putExtra(INTENT_EXTRA_PACKAGE_NAME, componentName.getPackageName());intent.putExtra(INTENT_EXTRA_ACTIVITY_NAME, componentName.getClassName());intent.putExtra(INTENT_EXTRA_MESSAGE, String.valueOf(badgeCount));intent.putExtra(INTENT_EXTRA_SHOW_MESSAGE, badgeCount > 0);context.sendBroadcast(intent);}/*** Send request to Sony badge content provider to set badge in Sony home launcher.** @param context       the context to use* @param componentName the componentName to use* @param badgeCount    the badge count*/private void executeBadgeByContentProvider(Context context, ComponentName componentName,int badgeCount) {if (badgeCount < 0) {return;}final ContentValues contentValues = createContentValues(badgeCount, componentName);if (Looper.myLooper() == Looper.getMainLooper()) {// We're in the main thread. Let's ensure the badge update happens in a background// thread by using an AsyncQueryHandler and an async update.if (mQueryHandler == null) {mQueryHandler = new AsyncQueryHandler(context.getApplicationContext().getContentResolver()) {};}insertBadgeAsync(contentValues);} else {// Already in a background thread. Let's update the badge synchronously. Otherwise,// if we use the AsyncQueryHandler, this thread may already be dead by the time the// async execution finishes, which will lead to an IllegalStateException.insertBadgeSync(context, contentValues);}}/*** Asynchronously inserts the badge counter.** @param contentValues Content values containing the badge count, package and activity names*/private void insertBadgeAsync(final ContentValues contentValues) {mQueryHandler.startInsert(0, null, BADGE_CONTENT_URI, contentValues);}/*** Synchronously inserts the badge counter.** @param context       Caller context* @param contentValues Content values containing the badge count, package and activity names*/private void insertBadgeSync(final Context context, final ContentValues contentValues) {context.getApplicationContext().getContentResolver().insert(BADGE_CONTENT_URI, contentValues);}/*** Creates a ContentValues object to be used in the badge counter update. The package and* activity names must correspond to an activity that holds an intent filter with action* "android.intent.action.MAIN" and category android.intent.category.LAUNCHER" in the manifest.* Also, it is not allowed to publish badges on behalf of another client, so the package and* activity names must belong to the process from which the insert is made.* To be able to insert badges, the app must have the PROVIDER_INSERT_BADGE* permission in the manifest file. In case these conditions are not* fulfilled, or any content values are missing, there will be an unhandled* exception on the background thread.** @param badgeCount    the badge count* @param componentName the component name from which package and class name will be extracted**/private ContentValues createContentValues(final int badgeCount,final ComponentName componentName) {final ContentValues contentValues = new ContentValues();contentValues.put(PROVIDER_COLUMNS_BADGE_COUNT, badgeCount);contentValues.put(PROVIDER_COLUMNS_PACKAGE_NAME, componentName.getPackageName());contentValues.put(PROVIDER_COLUMNS_ACTIVITY_NAME, componentName.getClassName());return contentValues;}/*** Check if the latest Sony badge content provider exists .** @param context the context to use* @return true if Sony badge content provider exists, otherwise false.*/private static boolean sonyBadgeContentProviderExists(Context context) {boolean exists = false;ProviderInfo info = context.getPackageManager().resolveContentProvider(SONY_HOME_PROVIDER_NAME, 0);if (info != null) {exists = true;}return exists;}
}

三星

public class SamsungHomeBadger extends Badger {private static final String CONTENT_URI = "content://com.sec.badge/apps?notify=true";private static final String[] CONTENT_PROJECTION = new String[]{"_id", "class"};private DefaultBadger defaultBadger;public SamsungHomeBadger() {if (Build.VERSION.SDK_INT >= 21) {defaultBadger = new DefaultBadger();}}@Overridepublic void executeBadge(Context context, ComponentName componentName, int badgeCount) throws ShortcutBadgeException {if (defaultBadger != null && defaultBadger.isSupported(context)) {defaultBadger.executeBadge(context, componentName, badgeCount);} else {Uri mUri = Uri.parse(CONTENT_URI);ContentResolver contentResolver = context.getContentResolver();Cursor cursor = null;try {cursor = contentResolver.query(mUri, CONTENT_PROJECTION, "package=?", new String[]{componentName.getPackageName()}, null);if (cursor != null) {String entryActivityName = componentName.getClassName();boolean entryActivityExist = false;while (cursor.moveToNext()) {int id = cursor.getInt(0);ContentValues contentValues = getContentValues(componentName, badgeCount, false);contentResolver.update(mUri, contentValues, "_id=?", new String[]{String.valueOf(id)});if (entryActivityName.equals(cursor.getString(cursor.getColumnIndex("class")))) {entryActivityExist = true;}}if (!entryActivityExist) {ContentValues contentValues = getContentValues(componentName, badgeCount, true);contentResolver.insert(mUri, contentValues);}}} finally {if (cursor != null && !cursor.isClosed()) {cursor.close();}}}}private ContentValues getContentValues(ComponentName componentName, int badgeCount, boolean isInsert) {ContentValues contentValues = new ContentValues();if (isInsert) {contentValues.put("package", componentName.getPackageName());contentValues.put("class", componentName.getClassName());}contentValues.put("badgecount", badgeCount);return contentValues;}@Overridepublic List<String> getSupportLaunchers() {return Arrays.asList("com.sec.android.app.launcher","com.sec.android.app.twlauncher");}
}

小米

ublic class XiaomiHomeBadger extends Badger {public static final String INTENT_ACTION = "android.intent.action.APPLICATION_MESSAGE_UPDATE";public static final String EXTRA_UPDATE_APP_COMPONENT_NAME = "android.intent.extra.update_application_component_name";public static final String EXTRA_UPDATE_APP_MSG_TEXT = "android.intent.extra.update_application_message_text";private ResolveInfo resolveInfo;@Overridepublic void executeBadge(Context context, ComponentName componentName, int badgeCount) throws ShortcutBadgeException {try {Class miuiNotificationClass = Class.forName("android.app.MiuiNotification");Object miuiNotification = miuiNotificationClass.newInstance();Field field = miuiNotification.getClass().getDeclaredField("messageCount");field.setAccessible(true);try {field.set(miuiNotification, String.valueOf(badgeCount == 0 ? "" : badgeCount));} catch (Exception e) {field.set(miuiNotification, badgeCount);}} catch (Exception e) {Intent localIntent = new Intent(INTENT_ACTION);localIntent.putExtra(EXTRA_UPDATE_APP_COMPONENT_NAME, componentName.getPackageName() + "/" + componentName.getClassName());localIntent.putExtra(EXTRA_UPDATE_APP_MSG_TEXT, String.valueOf(badgeCount == 0 ? "" : badgeCount));if (canResolveBroadcast(context, localIntent)) {context.sendBroadcast(localIntent);}}if (Build.MANUFACTURER.equalsIgnoreCase("Xiaomi")) {tryNewMiuiBadge(context, badgeCount);}}@TargetApi(Build.VERSION_CODES.JELLY_BEAN)private void tryNewMiuiBadge(Context context, int badgeCount) throws ShortcutBadgeException {if (resolveInfo == null) {Intent intent = new Intent(Intent.ACTION_MAIN);intent.addCategory(Intent.CATEGORY_HOME);resolveInfo = context.getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);}if (resolveInfo != null) {NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);Notification.Builder builder = new Notification.Builder(context).setContentTitle("").setContentText("").setSmallIcon(resolveInfo.getIconResource());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, badgeCount);mNotificationManager.notify(0, notification);} catch (Exception e) {throw new ShortcutBadgeException("not able to set badge", e);}}}@Overridepublic List<String> getSupportLaunchers() {return Arrays.asList("com.miui.miuilite","com.miui.home","com.miui.miuihome","com.miui.miuihome2","com.miui.mihome","com.miui.mihome2","com.i.miui.launcher");}
}

华硕

public class AsusHomeBadger extends Badger {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";@Overridepublic 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());intent.putExtra("badge_vip_count", 0);if (canResolveBroadcast(context, intent)) {context.sendBroadcast(intent);} else {throw new ShortcutBadgeException("unable to resolve intent: " + intent.toString());}}@Overridepublic List<String> getSupportLaunchers() {return Arrays.asList("com.asus.launcher");}
}

大家也可以直接去看看开源
https://gitee.com/yufeilong/badger-helper-master

更多framework实战开发干货,请关注下面“千里马学框架”

http://www.xdnf.cn/news/8954.html

相关文章:

  • 解析Java String.getBytes()编码与new String()解码的字符集转换机制
  • 深入解析Kafka JVM堆内存:优化策略与监控实践
  • 深入理解JavaScript设计模式之原型模式
  • SpringBoot(四)--- Mybatis、PageHelper、事务
  • 【LLM】LLM源码阅读与分析工具DeepWiki项目
  • C++ 中的引用参数(Reference Parameter)‌
  • 数据结构第2章绪论 (竟成)
  • JavaWeb:SpringBoot Bean管理
  • 豆瓣电视剧数据工程实践:从爬虫到智能存储的技术演进(含完整代码)
  • 墨水屏 函数Paint_SetScale的详解
  • 【公式】MathType,axmath公式批量统一大小
  • MMDetection3D最全源码安装教程
  • Python打卡训练营day31-文件拆分
  • 【深度学习-Day 17】神经网络的心脏:反向传播算法全解析
  • 【工具变量】上市公司企业未来主业业绩数据集(2000-2023年)
  • 内存管理(第五、六章)
  • RV1126的RGA模块讲解
  • 7.Java String类深度解析:从不可变魔法到性能优化实战
  • 【电机控制】基于STM32F103C8T6的四轮智能车设计——直流有刷有感PID控制(硬件篇)
  • Java基础知识回顾
  • CLion-2025 嵌入式开发调试环境详细搭建
  • Mysql 中的锁
  • 2025京麒CTF挑战赛 计算器 WriteUP
  • 2024 CKA模拟系统制作 | Step-By-Step | 5、题目搭建-查看Pod CPU资源使用量
  • 滑动窗口算法:高效处理数组与字符串子序列问题的利器
  • (九)PMSM驱动控制学习---无感控制之高阶滑膜观测器
  • 61580 RT控制
  • SCI与EI期刊分区及影响因子汇总
  • 超越UniAD!百度哈工大X-Driver:基于视觉语言模型的可解释自动驾驶
  • 多线程的基础知识以及应用