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

学员投稿:华为,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实战开发干货,请关注下面“千里马学框架”

相关文章:

  • 项目三 - 任务8:实现词频统计功能
  • [论文阅读]Prompt Injection attack against LLM-integrated Applications
  • Linux 网络配置现代实践:Netplan 与 ifcfg 的全景对比与工程指南20250526
  • 炫云云渲染,构筑虚实交融的3D数字新视界
  • python(linux环境)-pickle、json、time、zipfile模块的使用
  • 【C++11】lambda表达式 || 函数包装器 || bind用法
  • Cesium 实战 26 - 自定义纹理材质 - 实际应用之飞线(抛物线)
  • HTML与Flask表单之间的关系(chatgtp提供)
  • 【每日渲美学】3ds Max橱柜材质教程:厨房高光烤漆、木纹、亚克力、亚光板材渲染优化指南
  • 智能灾备驱动数字政府转型:从合规保障到智能治理跃升
  • 人工智能的能源困境:繁荣与危机并存的未来
  • Unity---OSC(Open Sound Control)、TouchOSC Editor、创建布局
  • 31.第二阶段x64游戏实战-封包-线程发包
  • Structure-Revealing Low-Light Image Enhancement Via Robust Retinex Model论文阅读
  • Git Push 失败:HTTP 413 Request Entity Too Large
  • Linux之软件包管理器(CentOS系统) —— yum
  • React笔记-使用Ant Design X样板间
  • Django压缩包形式下载文件
  • django三级联动
  • 【硬核DIY · 嵌入式AI】ESP32碰上AI——用Arduino在ESP32-S3上实现AI音频分类
  • 哈尔滨建设工程招聘信息网站/全网推广费用
  • 网站建设外包行业/seo网站制作优化
  • 搭建品牌电商网站怎么做/网页搜索引擎优化技术
  • 大学生网站建设规划书/华夏思源培训机构官网
  • 新手站长做装修网站/社群运营
  • 如何做微网站/近期国内外重大新闻10条