一、背景
本篇介绍一下笔者在维护IM应用时,设置App角标的相关经验。同时这里设置角标都是基于系统厂商的Launcher,没有适配三方的Launcher应用,因为我们统计下来发现近些年使用三方Launcher应用比较少了,大部分用户还是以系统Launcher为主。所在在我们的项目中,主要是适配各个厂商。
二、厂商角标设置规则
华为
Bundle bundle = new Bundle(); bundle.putString("package", context.getPackageName()); String launchClassName = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()).getComponent().getClassName(); bundle.putString("class", launchClassName); bundle.putInt("badgenumber", number); context.getContentResolver().call(Uri.parse("content://com.huawei.android.launcher.settings/badge/"), "change_badge", null, bundle);
荣耀
荣耀从华为独立之后,其设置角标的规则也进行更改,不过整体的改动不大:
Bundle bundle = new Bundle(); bundle.putString("package", context.getPackageName()); String launchClassName = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()).getComponent().getClassName();bundle.putString("class", launchClassName); bundle.putInt("badgenumber", number); context.getContentResolver().call(Uri.parse("content://com.hihonor.android.launcher.settings/badge/"), "change_badge", null, bundle);
vivo
Funtouch OS
申请权限<!--funtouch os-->
<!--funtouch os--><uses-permission android:name="com.vivo.notification.permission.BADGE_ICON" />
适配代码:
Intent intent = new Intent(); int missedCalls = 10; intent.setAction("launcher.action.CHANGE_APPLICATION_NOTIFICATION_NUM"); intent.putExtra("packageName", "com.android.xxxx"); //接入方自己的包名 intent.putExtra("className", "com.android.xxxx.Mainxxxx"); //对应接入方的launcher入口的activity全路径activity名字(AndroidManifest中标识了android.intent.category.LAUNCHER的activity) intent.putExtra("notificationNum", missedCalls); intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); sendBroadcast(intent);
注意: 在ard8.0以后,还需要给Intent加上下面的Flag
Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
如果此Flag获取不到,则改为此方法
public static int invokeIntconstants(String CanonicalName, String name, int default_value) { int value = default_value; try { Class<?> c = Class.forName(CanonicalName); Field Field = c.getField(name); value = (int) Field.get(c); } catch (Exception e) { e.printStackTrace(); } finally { return value; } }
Origin OS
确定系统版本
Class<?> spClass = Class.forName("android.os.SystemProperties"); Method method = spClass.getMethod("get", String.class, String.class); method.setAccessible(true); currentOsName= (String) method.invoke(null, "ro.vivo.os.name" ,defName); currentOsVersion=(String) method.invoke(null, "ro.vivo.os.version" ,defVersion);
申请权限<!--origin os-->
<uses-permission android:name="com.vivo.abe.permission.launcher.notification.num" />
设置代码
public static void setBadgeNumber() { Uri uri = Uri.parse("content://" +"com.vivo.abe.provider.launcher.notification.num"); Bundle extra = new Bundle(); extra.putString("package", String);//接入的App包名 extra.putString("class", String);//接入的App class名 extra.putInt("badgenumber", int);//目标的角标数 /*这里一定要先使用 ContentProviderClient 建立非稳连接,不可以直接通过 getContentResolver()调用 call 方法,会有 Server 端崩溃带崩 Client 端的风险*/ ContentProviderClient client = null; try { client = getContentResolver().acquireUnstableContentProviderClient(uri); if (client != null) { int result = client.call("change_badge", null, extra).getInt("result"); } } catch (Exception e) { e.printStackTrace(); } finally { if (client != null) { if(Build.VERSION.SDK_INT >=Build.VERSION_CODES.N){ client.close(); } else { client.release(); } } } }
魅族
申请权限<!--魅族角标-->
<uses-permission android:name="com.meizu.flyme.launcher.permission.WRITE_BADGE_EXTRAS"/>
设置代码
Bundle extra = new Bundle(); extra.putString("package", context.getPackageName()); extra.putString("class", "yourLauncherClassName"); extra.putInt("badge_number", number); context.getContentResolver().call(Uri.parse("content://" + "com.meizu.flyme.launcher.app_extras" + "/badge_extras"), "change_badge", null, extra);
OPPO
public static void setBadgeNumber(Context context, int number) { try { if (number == 0) { number = -1; } Intent intent = new Intent("com.oppo.unsettledevent"); intent.putExtra("pakeageName", context.getPackageName()); intent.putExtra("number", number); intent.putExtra("upgradeNumber", number); if (canResolveBroadcast(context, intent)) { context.sendBroadcast(intent); } else { try { Bundle extras = new Bundle(); extras.putInt("app_badge_count", number); context.getContentResolver().call(Uri.parse("content://com.android.badge/badge"), "setAppBadgeCount", null, extras); } catch (Throwable t) { t.printStackTrace(); } } } catch (Exception e) { e.printStackTrace(); } } private static boolean canResolveBroadcast(Context context, Intent intent) { PackageManager packageManager = context.getPackageManager(); List<ResolveInfo> receivers = packageManager.queryBroadcastReceivers(intent, 0); return receivers != null && receivers.size() > 0; }
小米
小米手机比较特殊,其App角标与App通知相关联,无法脱离通知栏独立设置角标未读数量。
三星
public static void setBadgeNumber(Context context, int number) { Intent localIntent = new Intent("android.intent.action.BADGE_COUNT_UPDATE"); //数字 localIntent.putExtra("badge_count", number); //包名 localIntent.putExtra("badge_count_package_name", context.getPackageName()); //启动页 localIntent.putExtra("badge_count_class_name", BadgeNumberManager.getLauncherClassName(context)); context.sendBroadcast(localIntent); }
sony
public static void setBadgeNumber(Context context, int number) { boolean isShow = true; if ("0".equals(number)) { isShow = false; } Intent localIntent = new Intent(); //是否显示 localIntent.putExtra("com.sonyericsson.home.intent.extra.badge.SHOW_MESSAGE", isShow); localIntent.setAction("com.sonyericsson.home.action.UPDATE_BADGE"); //启动页 localIntent.putExtra("com.sonyericsson.home.intent.extra.badge.ACTIVITY_NAME", BadgeNumberManager.getLauncherClassName(context)); //数字 localIntent.putExtra("com.sonyericsson.home.intent.extra.badge.MESSAGE", number); //包名 localIntent.putExtra("com.sonyericsson.home.intent.extra.badge.PACKAGE_NAME", context.getPackageName()); context.sendBroadcast(localIntent); }
三、总结&注意事项
封装建议
以上各个厂商设置角标的方式都不同,可以考虑封装成不同的策略,基于Build.MANUFACTURER
字段来选择不同的策略,使上层无感知。
注意事项
在实践过程中,我们发现频繁设置角标可能会引发卡顿。
起因是我们的卡顿监控发现部分卡顿堆栈竟然是设置角标,经过排查发现用户接收消息非常频繁。而我们的策略是只要应用内的未读数发生变化,那么就会立刻更新角标的未读数。这就导致可能会非常频繁的更新应用角标。
发现此问题后,我们调整了策略。优化后的策略是当App在前台时,不更新角标。当App切换到后台再统一更新,这样可以大大的减少更新频率。优化策略后线上由于频繁更新角标引发的卡顿也就消失了。
总结
本篇主要是总结一下各个厂商的角标适配代码,以及过程中我们遇到的问题。读者遇到相关需求直接拿来使用就好,不过厂商也可能会随时更新,使用时也请做好测试。
作者:半山居士
链接:https://juejin.cn/post/7475229875822559273
来源:
互联网
本文观点不代表码客-全球程序员交流社区立场,不承担法律责任,文章及观点也不构成任何投资意见。
评论列表