LZ-Says:情,杂乱。绪,如同乱麻。若年的感情,似乎像个破碎的镜子,一点点破碎,一次次分裂。看着破碎镜子中的自己,呵,MD,感情的白痴。挫败感,席卷而来,压的透不过气。像个 SB 一样,以为搞点 502 就能粘合了?真特么的是个天字一号纯 SB。满手的渣子沫,似乎疼过劲儿了。余下时光,enmmm,各自安好。

一、前言

话说,在某天,正在烦恼某个功能点如何实现更好、更快,老大来了一句,iOS 应用图标有未读提示,这个华为手机怎么没有呢?来,搞一下。

朦朦胧胧接了任务。嗯,就这样开启了辛酸路。

来,过来个人,抱着哭会儿。

先看看效果图,手机拍个短信、钉钉、QQ 的小效果:

看到了吗?zou si 它~!

昏暗无光的样式呐,默默 MMP~!

Enmmm,另外在此注明下,本内容由 LZ 小白以及偶家明远小哥哥一块完成,下面贴出小哥哥博客地址:

https://blog.csdn.net/qq_33869391

Enmmm,下面开启辛酸路吧。

二、辛酸路

首先看到应用程序 Logo 显示未读消息,内心第一想法便是,So so easy,相比良好的厂商以及提供了相关 Api 咯,LZ 无非就是整合一下,然而卵。

想了想,目前市面上主流的几款机型:

  • 华为

  • 小米

  • VIVO,OPPO

  • 爆炸神机 三星

  • 魅族、一加、索尼、联想。。。

想想要兼容每家好烦呢,也不知道文档写的 6 不 6 ,对于 LZ 这样小白理解力够不够。事实证明,LZ 想多了,满脸的生无可恋。

一起来看“每家“ API 文档

2.1 华为

角标是华为桌面提供给各应用显示未读消息用的,会在应用图标右上角绘制一张消息条数的图标。

贴心的华为为我们描述了角标的作用。

  • 华为桌面角标业务介绍:https://developer.huawei.com/consumer/cn/devservice/doc/30801;

  • 华为桌面角标开发指导书:https://developer.huawei.com/consumer/cn/devservice/doc/30802;

  • 华为桌面未读角标对外接口说明书:http://obs.cn-north-1.myhwclouds.com/consumer/docattachment/87918b190abda6d7b7a568a7ef1dfc314cd9ad040faccf1a999dcff158ec7d79/badge.pdf

这里需要注意:

当桌面不支持角标功能时,接口会抛出异常,应用可以在调用接口的地方加上try … catch(Exception e) 语句以免程序崩溃。

2.2 小米

  • MIUI 6 至 MIUI 10 桌面角标适配说明:https://dev.mi.com/console/doc/detail?pId=939

这里需要注意:

当应用向通知栏发送了一条通知 (除了进度条样式和常驻通知外),应用图标的右上角就会显示「1」。值得一提,角标的数字代表应用的通知数,即应用发送了「x」条通知,角标就会显示为「x」。

如果开发者不满意默认逻辑,想要自定义角标的数字,可以通过调用接口告知系统即可。

2.3 OPPO、VIVO

  • OPPO 开发平台:https://open.oppomobile.com/wiki/doc#id=10026;

  • VIVO 开放平台:https://dev.vivo.com.cn/documentCenter/doc/135。

Enmmm,上面俩个地址暂时找不到,LZ 附上询问客服的截图,供大家一览~

上面是 OPPO ,下面 VIVO,不愧是好基友。

2.4 联想

  • 应用图标动态角标显示:http://developer.zuk.com/detail/12

就是这个代码呐,有点乱糟糟,排版不太好。

2.5 剩下的呐?Enmmm,没找到。

MMP。。。

2.6 简单总结

Enmmm,只想说,华为,我爱你~!

好人,一生平安呐~

LZ 总有自己的犟劲儿,同时 LZ 查看了程序猿最大异性交友平台,找到了以下曾经“辉煌“的库:

  • https://github.com/q1113225201/Badger

  • https://github.com/leolin310148/ShortcutBadger

Enmmm,还有良心博文:

  • Badge分析&如何逼死处女座:https://www.jianshu.com/p/0992ff9eeeb6

  • 【笔记】Android桌面角标Badge官方文档和兼容性解决:https://blog.csdn.net/q1113225201/article/details/79858032

三、来波实践

到现在,我算是明白了,想彻底兼容,估计还得兼容每个厂商 ROM,而且谁知道每个系统版本会不会出现一些变动,至少这些对于 LZ 目前而言,太过于困难,那么,LZ 基于目前现有资料,尽力而为吧。

LZ 简单描述下本文 LZ 思路:

  1. 创建定时器,用于模拟接收消息,便于显示于角标内;
  2. 依据上方提供文档地址,整合工具类,当然,抽取部分 GitHub 当年优秀之作整合为一个 Utils;
  3. enmmm,开搞。这里需要注意小米需要单独绑定通知以及对于未提供 API 接口的设备,LZ 目前能力有限,暂不涉及。

下面开发放大招咯~各位和 LZ 一样的伸手党福利来咯!

3.1 骚年,给我一波权限

    <uses-permission android:name="android.permission.INTERNET" /><!-- 华为角标 --><uses-permission android:name="com.huawei.android.launcher.permission.CHANGE_BADGE" /><!-- 三星角标 --><uses-permission android:name="com.sec.android.provider.badge.permission.READ" /><uses-permission android:name="com.sec.android.provider.badge.permission.WRITE" /><!-- HTC角标 --><uses-permission android:name="com.htc.launcher.permission.READ_SETTINGS" /><uses-permission android:name="com.htc.launcher.permission.UPDATE_SHORTCUT" /><!-- 联想角标 --><uses-permission android:name="android.permission.READ_APP_BADGE" /><!-- 索尼角标 --><uses-permission android:name="com.sonymobile.home.permission.PROVIDER_INSERT_BADGE" /><uses-permission android:name="com.sonyericsson.home.permission.BROADCAST_BADGE" /><uses-permission android:name="com.sonyericsson.home.action.UPDATE_BADGE" />

3.2 骚年,Utils 奉上

package com.heliquan.badgedemo;import android.app.Notification;
import android.content.ComponentName;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;import java.lang.reflect.Field;
import java.lang.reflect.Method;/*** @author: heliquan* @data: 2018/9/11* @desc: 机型角标适配*/
public class BadgeUtils {/*** Retrieve launcher activity name of the application from the context** @param context The context of the application package.* @return launcher activity name of this application. From the* "android:name" attribute.*/public static String getLauncherClassName(Context context) {PackageManager packageManager = context.getPackageManager();Intent intent = new Intent(Intent.ACTION_MAIN);// To limit the components this Intent will resolve to, by setting an explicit package name.intent.setPackage(context.getPackageName());intent.addCategory(Intent.CATEGORY_LAUNCHER);// All Application must have 1 Activity at least.Launcher activity must be found!ResolveInfo info = packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);// get a ResolveInfo containing ACTION_MAIN, CATEGORY_LAUNCHER if there is no Activity which has filtered by CATEGORY_DEFAULTif (info == null) {info = packageManager.resolveActivity(intent, 0);}// 另一种实现方式// ComponentName componentName = context.getPackageManager().getLaunchIntentForPackage(mContext.getPackageName()).getComponent();// return componentName.getClassName();return info.activityInfo.name;}/*** 设置Badge 目前支持Launcher:* EXUI MIUI Sony Samsung LG HTC Nova* 魅族 努比亚 666 果断不支持* OPPO VIVO 狗** @param context  context* @param msgCount count*/public static void setBadgeCount(Context context, int msgCount) {if (msgCount <= 0) {msgCount = 0;} else {msgCount = Math.max(0, Math.min(msgCount, 99));}Log.e("Love", "当前设备类型: " + Build.MANUFACTURER);if (Build.MANUFACTURER.toLowerCase().contains("huawei")) {setBadgeOfEXUI(context, msgCount);} else if (Build.MANUFACTURER.toLowerCase().contains("nova")) {setBadgeOfNova(context, msgCount);} else if (Build.MANUFACTURER.toLowerCase().contains("zuk")) {setBadgeOfZuk(context, msgCount);} else if (Build.MANUFACTURER.equalsIgnoreCase("sony")) {setBadgeOfSony(context, msgCount);} else if (Build.MANUFACTURER.toLowerCase().contains("samsung") ||Build.MANUFACTURER.toLowerCase().contains("lg")) {setBadgeOfSumsung(context, msgCount);} else if (Build.MANUFACTURER.toLowerCase().contains("htc")) {setBadgeOfHTC(context, msgCount);} else {// 不管了}}/*** 设置华为Badge* 良心企业呐* 需要添加权限:<uses-permission android:name="com.huawei.android.launcher.permission.CHANGE_BADGE" />** @param context* @param count*/private static void setBadgeOfEXUI(Context context, int count) {try {Bundle badgeBundle = new Bundle();badgeBundle.putString("package", context.getPackageName());badgeBundle.putString("class", getLauncherClassName(context));badgeBundle.putInt("badgenumber", count);context.getContentResolver().call(Uri.parse("content://com.huawei.android.launcher.settings/badge/"),"change_badge", null, badgeBundle);} catch (Exception e) {}}/*** 设置Nova的Badge** @param context context* @param count   count*/private static void setBadgeOfNova(Context context, int count) {ContentValues contentValues = new ContentValues();contentValues.put("tag", context.getPackageName() + "/" +getLauncherClassName(context));contentValues.put("count", count);context.getContentResolver().insert(Uri.parse("content://com.teslacoilsw.notifier/unread_count"),contentValues);}/*** 设置联想ZUK的Badge* 需要添加权限:<uses-permission android:name="android.permission.READ_APP_BADGE" />** @param context* @param count*/private static void setBadgeOfZuk(Context context, int count) {Bundle extra = new Bundle();extra.putInt("app_badge_count", count);context.getContentResolver().call(Uri.parse("content://com.android.badge/badge"),"setAppBadgeCount", null, extra);}/*** 设置MIUI的Badge 小米需要和通知栏进行绑定 MMP*/public static void getBadgeOfMINU(Notification notification, int count) {try {Field field = notification.getClass().getDeclaredField("extraNotification");Object extraNotification = field.get(notification);Method method = extraNotification.getClass().getDeclaredMethod("setMessageCount", int.class);method.invoke(extraNotification, count);} catch (Exception e) {e.printStackTrace();}}/*** 设置索尼的Badge* 需添加权限:<uses-permission android:name="com.sonymobile.home.permission.PROVIDER_INSERT_BADGE" />* <uses-permission android:name="com.sonyericsson.home.permission.BROADCAST_BADGE" />* <uses-permission android:name="com.sonyericsson.home.action.UPDATE_BADGE" />** @param context context* @param count   count*/private static void setBadgeOfSony(Context context, int count) {String launcherClassName = getLauncherClassName(context);if (launcherClassName == null) {return;}boolean isShow = true;if (count == 0) {isShow = false;}Intent localIntent = new Intent();localIntent.setAction("com.sonyericsson.home.action.UPDATE_BADGE");localIntent.putExtra("com.sonyericsson.home.intent.extra.badge.SHOW_MESSAGE", isShow); // 是否显示localIntent.putExtra("com.sonyericsson.home.intent.extra.badge.ACTIVITY_NAME", launcherClassName); // 启动页localIntent.putExtra("com.sonyericsson.home.intent.extra.badge.MESSAGE", String.valueOf(count)); // 数字localIntent.putExtra("com.sonyericsson.home.intent.extra.badge.PACKAGE_NAME", context.getPackageName()); // 包名context.sendBroadcast(localIntent);}/*** 设置三星的Badge设置LG的Badge* 需添加权限:<uses-permission android:name="com.sec.android.provider.badge.permission.READ" />* <uses-permission android:name="com.sec.android.provider.badge.permission.WRITE" />** @param context context* @param count   count*/private static void setBadgeOfSumsung(Context context, int count) {// 获取你当前的应用String launcherClassName = getLauncherClassName(context);if (launcherClassName == null) {return;}Intent intent = new Intent("android.intent.action.BADGE_COUNT_UPDATE");intent.putExtra("badge_count", count);intent.putExtra("badge_count_package_name", context.getPackageName());intent.putExtra("badge_count_class_name", launcherClassName);context.sendBroadcast(intent);}/*** 设置HTC的Badge** @param context context* @param count   count*/private static void setBadgeOfHTC(Context context, int count) {Intent intentNotification = new Intent("com.htc.launcher.action.SET_NOTIFICATION");ComponentName localComponentName = new ComponentName(context.getPackageName(),getLauncherClassName(context));intentNotification.putExtra("com.htc.launcher.extra.COMPONENT", localComponentName.flattenToShortString());intentNotification.putExtra("com.htc.launcher.extra.COUNT", count);context.sendBroadcast(intentNotification);Intent intentShortcut = new Intent("com.htc.launcher.action.UPDATE_SHORTCUT");intentShortcut.putExtra("packagename", context.getPackageName());intentShortcut.putExtra("count", count);context.sendBroadcast(intentShortcut);}}

3.3 骚年,走起?

package com.heliquan.badgedemo;import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.NotificationCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.TextView;/*** @author: heliquan* @data: 2018/9/11* @desc: 机型角标适配*/
public class MainActivity extends AppCompatActivity {private MainActivity mSelfActivity = MainActivity.this;private TextView mShowBadge;// 模拟接收消息private Handler mBadgeHandler = new Handler();private int mBadgeCount = 1;private static final String CHANNEL_ID = "heliquan";private static final long[] VIBRATION_PATTERN = new long[]{0, 180, 80, 120};Runnable runnable = new Runnable() {@Overridepublic void run() {int tempNUm = mBadgeCount++;mShowBadge.setText("当前未读消息为:" + tempNUm);Log.e("Love", "当前未读消息为:" + tempNUm);if (Build.MANUFACTURER.equalsIgnoreCase("xiaomi")) {PackageManager pm = getPackageManager();Intent launchIntent = getPackageManager().getLaunchIntentForPackage(packageName);PendingIntent pendingIntent = PendingIntent.getActivity(mSelfActivity, 0, launchIntent, PendingIntent.FLAG_UPDATE_CURRENT);NotificationCompat.Builder builder = new NotificationCompat.Builder(mSelfActivity, CHANNEL_ID).setSmallIcon(getApplicationInfo().icon).setContentTitle(pm.getApplicationLabel(getApplicationInfo()).toString()).setTicker("Ticker:" + tempNUm).setContentText("贺贺,我是第" + tempNUm + "个").setWhen(System.currentTimeMillis()).setAutoCancel(true).setContentIntent(pendingIntent);Notification notification = builder.build();BadgeUtils.getBadgeOfMINU(notification, tempNUm);notificationManager.notify(0, notification);} else {BadgeUtils.setBadgeCount(mSelfActivity, tempNUm);}mBadgeHandler.postDelayed(this, 1500);}};private NotificationManager notificationManager;private String packageName;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initNotification();initView();}private void initNotification() {notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);if (Build.VERSION.SDK_INT >= 26) {// Create the notification channel for Android 8.0NotificationChannel channel = new NotificationChannel(CHANNEL_ID,"test for He.", NotificationManager.IMPORTANCE_DEFAULT);channel.setVibrationPattern(VIBRATION_PATTERN);notificationManager.createNotificationChannel(channel);}packageName = getApplicationInfo().packageName;}private void initView() {mShowBadge = findViewById(R.id.showBadgeNum);initViewData();}private void initViewData() {mBadgeHandler.postDelayed(runnable, 1500);}}

3.4 来波最后的效果看看:

3.5 最后,LZ 附上目前测试通过的设备

小米5 MIUI 9.6 Android 版本 8.0.0
红米 note 4 MIUI 10 8.8.31 开发版 6.0
华为 Honor 9 Lite EMUI 8.0.0 系统 8.0
荣耀 9 系统 8.0

当然有好的方案欢迎一起沟通交流~

四、个人公众号

不定期发布博文,最近有点忙,感谢老铁理解,欢迎关注~

工作篇 之 记录一次兼容手机角标的辛酸史。。。相关推荐

  1. android 小米角标,关于 小米手机 角标的问题

    平常可能都会看到 比如 三星,小米, 系统有类似 ios上app消息通知效果的 右上角 消息角标 在网络上 也有相关方面的资料,但是也有一点是有问题的 就比如在 miui 6 上 这个查了相关资料后, ...

  2. 工作篇-佛山三水恒大-2020.11.13

    ** 工作篇-佛山三水恒大-2020.11.14 **TAG:此篇文章估计会很长,因为工作的时候变数太多了,预计五千字左右,想看的可以耐心看完,均为个人实战经验.===害,其实是上学期间请假去做的,还 ...

  3. 一网打尽Mac上的高效工具 - 效率工作篇(附演示视频)

    写在前面:博主是一只经过实战开发历练后投身培训事业的"小山猪",昵称取自动画片<狮子王>中的"彭彭",总是以乐观.积极的心态对待周边的事物.本人的技 ...

  4. 一篇读懂:Android/iOS手机如何通过音频接口(耳机孔)与外设通信

    一文读懂Android/iOS手机如何通过音频接口与外设通信 更多技术干货,欢迎扫码关注博主微信公众号:HowieXue,一起学习探讨软硬件技术知识经验,关注就有海量学习资料免费领哦: 目录 一文读懂 ...

  5. 第一篇随意记录博文:关于程序员的五年之痒

    第一篇随意记录博文:关于程序员的五年之痒 大家好! 2015年9月16号开启了我在北京实习的第一份工作,这个是一家外包公司,由于要使用到日语,每天到公司后还要开早会晨读日语(扯淡规章制度),还好大学学 ...

  6. Android手机平板两不误,使用Fragment实现兼容手机和平板的程序

    转载请注明出处:http://blog.csdn.net/sinyu890807/article/details/8744943 记得我之前参与开发过一个华为的项目,要求程序可以支持好几种终端设备,其 ...

  7. 吴军《硅谷来信》工作篇学习总结

    [学习总结]| 作者 / Edison Zhou 这是恰童鞋骚年的第215篇原创文章 2018年在得到App上订阅了吴军老师的<硅谷来信>,从此每天的碎片时间就开始听吴军老师在大洋彼岸寄来 ...

  8. Android Fragment 兼容手机和平板

    记得我之前参与开发过一个华为的项目,要求程序可以支持好几种终端设备,其中就包括Android手机和Android Pad.然后为了节省人力,公司无节操地让Android手机和Android Pad都由 ...

  9. 技能树成长——工作篇

    技能树--工作篇 上班三个月,觉得自己懂得可实在是太少了,每天都埋头在学习,每天都在向师傅请教问题,浏览器每天的状态都是这样的:       学校里学的一些知识终究过于表面,在实际中要会的还有更多.自 ...

最新文章

  1. python 批量resize性能比较
  2. Java 二维数组的初始化
  3. C#调用WebService
  4. Origin Pro中常用的快捷键
  5. docker 容器日志集中 ELK + filebeat
  6. 基于drools_Drools:基于PHREAK堆栈的评估和向后链接
  7. java 状态机_Java 数据持久化系列之池化技术
  8. python表格模板_python 网站 使用表单和模板
  9. 微信开发者工具在线调试
  10. 苹果照片库的照片,直接拖到桌面上
  11. Atitit 完整知识体系表 attilax总结 要读哪些书
  12. 编译Notepad2语法高亮记事本源码心得
  13. 设置谷歌浏览器深色黑色背景
  14. cb.conjunction()的意思
  15. WIN10阻止OA附件打开
  16. java中Hashset集合删除元素_从Java中的HashSet中删除单个元素
  17. 微信小程序请求封装token
  18. WPF 使用 Composition API 做高性能渲染
  19. 实现IDApython自动化加载模块PDB
  20. Java根据内容生成图片

热门文章

  1. java 反引 双引号_Shell 单引号 双引号 反引号 反斜线
  2. 接触式声学多普勒(ADCP)在线测流系统是由什么组成的?
  3. 地平线 旭日X3 SDB开发板 (一) 环境及案例运行记录
  4. 深圳数千司机账号突然被封 滴滴出行称审核异常信息
  5. 07_JavaScript数据结构与算法(七)双向链表
  6. 用python画一个双层圆环筒状闭环源码
  7. Cadence Virtual.Component.CO-Design.v2.2-ISO 1CD(虚拟元件协同设计,VCC)
  8. 将自己的手机卡设置成空号
  9. mindspore.Profiler如何获取算子的aicore_time、mte1_time等数据
  10. 7-3 逆序的三位数 (c语言)