Android App 厂商角标适配

一、背景 

本篇介绍一下笔者在维护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-->

<!--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

关注我获取更多知识或者投稿

5d29f987473bc06aaa4a46d1feea573e.jpeg

e13bc5f798183a71ec318ff34c2ada1c.jpeg

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值