Android 在应用图标上设置未读消息数量

简介: Android 在应用图标上设置未读消息数量
* 针对国内支持的Launcher分别开发,支持为:
* ** 常见机型及是否支持
* *** 华为 支持
* 小米 支持
* OPPO 可以支持但需要申请
* VIVO 不支持
* SAMSUNG 支持
* MEIZU 不支持
* google 8.0开始支持 显示一个点,长按点弹出数字

image.gif

不造轮子不累赘叙述,直接封装

使用方法:

1.在使用之前首先 初始化 ,三个方法的参数分别是 应用包名/启动页的Activity及Context,四个参数的构造方法第三个是notification

DesktopCornerUtil.init("com.lonbon.nytest", "com.lonbon.view.activity.WelcomeActivity", BaseApplication.context);

image.gif

/**
 * 初始化 init 建议放在Application中执行
 * t is recommended to execute in Application
 *
 * @param packageNameParameter      @desc 应用包名
 * @param mainActivityNameParameter @desc MainActivity
 * @param contextParameter          @desc BaseApplication context
 */
public static void init(String packageNameParameter, String mainActivityNameParameter, Context contextParameter) {
    packageName = packageNameParameter;
    context = contextParameter;
    mainActivityName = mainActivityNameParameter;
}

image.gif

2.设置未读数量

DesktopCornerUtil.setBadgeNumber(1);

image.gif

注意的是:小米系统是自动会有的,且小米和三星系统 必须在后台设置才有效,前台设置无效,比如直接在前台时diamagnetic设置为10,那么不会显示,如果后台时收到通知会自动显示10

3.所有代码 转载请标明出处 欢迎反馈问题

/**
 * @author Huanglinqing
 * @blog: https://blog.csdn.net/huangliniqng
 * @date 2019/6/26
 * @desc 桌面角标显示方案 单例模式
 * <p>
 * 针对国内支持的Launcher分别开发,支持为:
 * ** 常见机型及是否支持
 * *** 华为 支持
 * 小米 支持
 * OPPO 可以支持但需要申请
 * VIVO 不支持
 * SAMSUNG 支持
 * MEIZU 不支持
 * google 8.0开始支持 显示一个点,长按点弹出数字
 * 其他杂牌机不支持
 * <p>
 * ------------------------------------------------------
 * English:
 * <p>
 * * Developed separately for the domestically supported Launcher, the support is:
 *   * ** Common models and support
 *   * *** Huawei Support
 *   * Xiaomi Support
 *   * OPPO can support but need to apply
 *   * VIVO does not support
 *   * SAMSUNG support
 *   * MEIZU does not support
 *   * google 8.0 starts to support display a point, long press the point to pop up the number
 *   * Other brands are not supported
 */
public class DesktopCornerUtil {
    /**
     * 华为手机launcher主题
     * <p>
     * Huawei mobile phone launcher theme
     */
    private static final String HUWEI_LAUNCHERNAME = "com.huawei.android.launcher";
    /**
     * 小米手机launcher主题
     * <p>
     * MIUI phone launcher theme
     */
    private static final String MIUI_LAUNCHERNAME = "com.miui.home";
    /**
     * 摩托罗拉和宏达手机launcher主题
     * <p>
     * Motorola and HTC mobile phone launcher theme
     */
    private static final String MOTOANDHTC_LAUNCHERNAME = " com.android.launcher";
    /**
     * 三星手机launcher主题
     * <p>
     * Samsung mobile phone launcher theme
     */
    private static final String SAMSUNG_LAUNCHERNAME = "com.sec.android.app.launcher";
    /**
     * google 手机launcher主题
     * <p>
     * Google phone launcher theme
     */
    private static final String GOOGLE_LAUNCHERNAME = "com.google.android.apps.nexuslauncher";
    private volatile static DesktopCornerUtil desktopCornerUtil;
    /**
     * vivo手机厂商名字
     * Vivo mobile phone manufacturer name
     */
    private static final String VIVO_MANUFACTURER_NAME = "vivo";
    /**
     * OPPO 手机厂商名字
     * OPPO mobile phone manufacturer name
     */
    private static final String OPPO_MANUFACTURER_NANE = "OPPO";
    /**
     * 应用包名
     * Application package name
     */
    private static String packageName = null;
    /**
     * context 对象 这里建议传递Application的context 避免内存泄漏
     * It is recommended to pass the Application context to avoid memory leaks.
     */
    static Context context = null;
    /**
     * 主Activity的名字 为全路径 比如 com.***..**Activity
     * The name of the main Activity is the full path. For example, com.***..**Activity
     */
    private static String mainActivityName = null;
    /**
     * notification 对象 小米系统会默认设置 如果修改默认逻辑 必须获取notification对象
     * The millet system will default settings. If you modify the default logic,
     * you must get the notification object.
     */
    private static Notification notification = null;
    private DesktopCornerUtil() {
    }
    public static DesktopCornerUtil getInstance() {
        if (desktopCornerUtil == null) {
            synchronized (DesktopCornerUtil.class) {
                if (desktopCornerUtil == null) {
                    desktopCornerUtil = new DesktopCornerUtil();
                }
            }
        }
        return desktopCornerUtil;
    }
    /**
     * 初始化 init 建议放在Application中执行
     * t is recommended to execute in Application
     *
     * @param packageNameParameter      @desc 应用包名
     * @param mainActivityNameParameter @desc MainActivity
     * @param contextParameter          @desc BaseApplication context
     */
    public static void init(String packageNameParameter, String mainActivityNameParameter, Context contextParameter) {
        packageName = packageNameParameter;
        context = contextParameter;
        mainActivityName = mainActivityNameParameter;
    }
    /**
     * @param packageNameParameter  @desc 应用包名
     * @param mainActivityNameParameter @desc MainActivity
     * @param notication        通知
     * @param contextParameter  @desc BaseApplication context
     */
    public static void init(String packageNameParameter, String mainActivityNameParameter, Notification notication, Context contextParameter) {
        packageName = packageNameParameter;
        context = contextParameter;
        mainActivityName = mainActivityNameParameter;
    }
    /**
     * 获取launcher相关信息  根据launcher
     * 分别开发
     * <p>
     * miui: com.miui.home
     * <p>
     * huawei: com.huawei.android.launcher
     * <p>
     * moto and htc: com.android.launcher
     * <p>
     * samsung: com.sec.android.app.launcher
     * <p>
     * goole:com.google.android.apps.nexuslauncher
     * <p>
     * BaseApplication.getContext() is Application context
     *
     * @return
     */
    private static String getLauncherMessage() {
        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_HOME);
        if (context == null) {
            return "";
        } else {
            final ResolveInfo res = context
                    .getPackageManager().resolveActivity(intent, 0);
            if (res.activityInfo == null) {
                return "";
            }
            if (context.getString(R.string.android).
                    equals(res.activityInfo.packageName)) {
                return "";
            }
            return res.activityInfo.packageName;
        }
    }
    /**
     * 设置角标数字
     * Set the angle number
     *
     * @param badgeNumber @desc 数量
     */
    public static void setBadgeNumber(int badgeNumber) {
        if (badgeNumber >= 0) {
            switch (getLauncherMessage()) {
                case HUWEI_LAUNCHERNAME:
                    setBadgeNumberHuawei(badgeNumber);
                    break;
                case MIUI_LAUNCHERNAME:
                    setBadgeNumberMiui(badgeNumber);
                    break;
                case MOTOANDHTC_LAUNCHERNAME:
                    setBadgeNumberhtc(badgeNumber);
                    break;
                case SAMSUNG_LAUNCHERNAME:
                    setBadgeNumberSamsung(badgeNumber);
                    break;
                case GOOGLE_LAUNCHERNAME:
                    setBadgeNumberGoogle(badgeNumber);
                    break;
                default:
                    //再根据制造商去判断
                    String manufacturer = Build.MANUFACTURER;
                    switch (manufacturer) {
                        case VIVO_MANUFACTURER_NAME:
                            setBadgeNumberVivo(badgeNumber);
                            break;
                        case OPPO_MANUFACTURER_NANE:
                            setBadgeNumberOppo(badgeNumber);
                            break;
                        default:
                            break;
                    }
                    break;
            }
        } else {
            // TODO: 2019/6/27 donothing
        }
    }
    /**
     * Google手机设置角标 只支持8.0以上
     * Google phone settings corner Only supports 8.0 or above
     *
     * @param badgeNumber @desc 数量
     */
    private static void setBadgeNumberGoogle(int badgeNumber) {
        if (TextUtils.isEmpty(packageName)) {
            return;
        }
        if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.O) {
            return;
        }
        Intent intent = new Intent("android.intent.action.BADGE_COUNT_UPDATE");
        intent.putExtra("badge_count", badgeNumber);
        intent.putExtra("badge_count_package_name", packageName);
        intent.putExtra("badge_count_class_name", mainActivityName);
        context.sendBroadcast(intent);
    }
    /**
     * htc和摩托罗拉设置角标
     * Htc and Motorola set the corners
     *
     * @param badgeNumber @desc 数量
     */
    private static void setBadgeNumberhtc(int badgeNumber) {
        if (TextUtils.isEmpty(packageName)) {
            return;
        }
        Intent intentNotification = new Intent("com.htc.launcher.action.SET_NOTIFICATION");
        intentNotification.putExtra("com.htc.launcher.extra.COMPONENT", packageName);
        intentNotification.putExtra("com.htc.launcher.extra.COUNT", badgeNumber);
        context.sendBroadcast(intentNotification);
        Intent intentShortcut = new Intent("com.htc.launcher.action.UPDATE_SHORTCUT");
        intentShortcut.putExtra("packagename", packageName);
        intentShortcut.putExtra("count", badgeNumber);
        context.sendBroadcast(intentShortcut);
    }
    /**
     * 小米手机设置角标
     * MIUI mobile phone settings corner
     * 当APP处于前台时,数字会自动清空
     * When the app is in the foreground, the number will be automatically cleared.
     *
     * @param badgeNumber @desc 数量
     */
    private static void setBadgeNumberMiui(int badgeNumber) {
        try {
            if (notification == null) {
                return;
            } else {
                Field field = notification.getClass().getDeclaredField("extraNotification");
                Object extraNotification = field.get(notification);
                Method method = extraNotification.getClass().getDeclaredMethod("setMessageCoun", int.class);
                method.invoke(extraNotification, badgeNumber);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 华为手机设置角标
     * Huawei mobile phone settings corner
     *
     * @param badgeNumber @desc 数量
     */
    private static void setBadgeNumberHuawei(int badgeNumber) {
        if (TextUtils.isEmpty(packageName)) {
            return;
        }
        Bundle extra = new Bundle();
        extra.putString("package", packageName);
        extra.putString("class", mainActivityName);
        extra.putInt("badgenumber", badgeNumber);
        context.getContentResolver().call(Uri.parse("content://com.huawei.android.launcher.settings/badge/"),
                "change_badge", null, extra);
    }
    /**
     * 三星手机 设置角标
     * Samsung mobile phone set corner
     *
     * @param badgeNumber @desc 数量
     */
    private static void setBadgeNumberSamsung(int badgeNumber) {
        if (TextUtils.isEmpty(packageName)) {
            return;
        }
        Intent intent = new Intent("android.intent.action.BADGE_COUNT_UPDATE");
        intent.putExtra("badge_count", badgeNumber);
        intent.putExtra("badge_count_package_name", packageName);
        intent.putExtra("badge_count_class_name", mainActivityName);
        context.sendBroadcast(intent);
    }
    /**
     * vivo 手机 设置角标
     * Vivo mobile phone set corner
     *
     * @param badgeNumber @desc 数量
     */
    public static void setBadgeNumberVivo(int badgeNumber) {
        try {
            Intent intent = new Intent("launcher.action.CHANGE_APPLICATION_NOTIFICATION_NUM");
            intent.putExtra("packageName", packageName);
            String launchClassName = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()).getComponent().getClassName();
            intent.putExtra("className", launchClassName);
            intent.putExtra("notificationNum", badgeNumber);
            context.sendBroadcast(intent);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 服务是否启动
     *
     * @param intent @desc 查找的服务
     * @return
     */
    public static boolean broadcastStarts(Intent intent) {
        PackageManager packageManager = context.getPackageManager();
        List<ResolveInfo> receivers = packageManager.queryBroadcastReceivers(intent, 0);
        return receivers != null && receivers.size() > 0;
    }
    /**
     * Oppo 手机 设置角标
     * OPPO mobile phone set corner
     *
     * @param badgeNumber @desc 数量
     */
    public static void setBadgeNumberOppo(int badgeNumber) {
        try {
            Intent intent = new Intent("com.oppo.unsettledevent");
            intent.putExtra("pakeageName", context.getPackageName());
            intent.putExtra("number", badgeNumber);
            intent.putExtra("upgradeNumber", badgeNumber);
            if (broadcastStarts(intent)) {
                context.sendBroadcast(intent);
            } else {
                try {
                    Bundle extras = new Bundle();
                    extras.putInt("app_badge_count", badgeNumber);
                    context.getContentResolver().call(Uri.parse("content://com.android.badge/badge"), "setAppBadgeCount", null, extras);
                } catch (Throwable th) {
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

image.gif


目录
相关文章
|
存储 Android开发
如何查看Flutter应用在Android设备上已被撤销的权限?
如何查看Flutter应用在Android设备上已被撤销的权限?
767 64
|
Android开发 开发者
Android设置View是否可用
在Android开发中,有时需要将布局设置为不可点击状态(失去焦点)。常见的解决方法是使用`setOnClickListener(null)`,但本文介绍一种更通用的方式:通过封装`setViewEnabled`方法实现。该方法可递归设置View及其子View的启用状态,支持传入目标View和布尔值(`true`为可用,`false`为禁用)。例如,调用`setViewEnabled(edittext, false)`即可禁用EditText。文章附有源码及示例动图,帮助开发者快速理解与应用。
314 1
|
10月前
|
存储 消息中间件 人工智能
【04】AI辅助编程完整的安卓二次商业实战-寻找修改替换新UI首页图标-菜单图标-消息列表图标-优雅草伊凡
【04】AI辅助编程完整的安卓二次商业实战-寻找修改替换新UI首页图标-菜单图标-消息列表图标-优雅草伊凡
578 4
|
10月前
|
XML 存储 Java
【06】AI辅助编程完整的安卓二次商业实战-背景布局变更增加背景-二开发现页面跳转逻辑-替换剩余图标-优雅草卓伊凡
【06】AI辅助编程完整的安卓二次商业实战-背景布局变更增加背景-二开发现页面跳转逻辑-替换剩余图标-优雅草卓伊凡
234 3
【06】AI辅助编程完整的安卓二次商业实战-背景布局变更增加背景-二开发现页面跳转逻辑-替换剩余图标-优雅草卓伊凡
|
10月前
|
XML 编解码 Android开发
非常经典的Android开发问题-mipmap图标目录和drawable图标目录的区别和适用场景实战举例-优雅草卓伊凡
非常经典的Android开发问题-mipmap图标目录和drawable图标目录的区别和适用场景实战举例-优雅草卓伊凡
807 0
非常经典的Android开发问题-mipmap图标目录和drawable图标目录的区别和适用场景实战举例-优雅草卓伊凡
|
Android开发 开发者
Android中Dialog位置+样式的设置
本文介绍了在Android开发中如何设置Dialog的位置和样式。通过自定义`MyDialog`类,可以灵活调整Dialog的显示位置,例如将其固定在屏幕底部,并设置宽度匹配父布局。同时,文章还展示了如何模仿Android原生Dialog样式,通过定义`MyDialogStyle`去除标题栏、设置背景透明度、添加阴影效果以及配置点击外部关闭等功能,从而实现更加美观和符合需求的Dialog效果。代码示例详细,便于开发者快速上手实现。
711 2
|
前端开发 Java Shell
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
1024 20
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
Dart 前端开发 Android开发
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
539 4
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
JSON Java API
探索安卓开发:打造你的首个天气应用
在这篇技术指南中,我们将一起潜入安卓开发的海洋,学习如何从零开始构建一个简单的天气应用。通过这个实践项目,你将掌握安卓开发的核心概念、界面设计、网络编程以及数据解析等技能。无论你是初学者还是有一定基础的开发者,这篇文章都将为你提供一个清晰的路线图和实用的代码示例,帮助你在安卓开发的道路上迈出坚实的一步。让我们一起开始这段旅程,打造属于你自己的第一个安卓应用吧!
444 14
|
搜索推荐 前端开发 测试技术
打造个性化安卓应用:从设计到开发的全面指南
在这个数字时代,拥有一个定制的移动应用不仅是一种趋势,更是个人或企业品牌的重要延伸。本文将引导你通过一系列简单易懂的步骤,从构思你的应用理念开始,直至实现一个功能齐全的安卓应用。无论你是编程新手还是希望拓展技能的开发者,这篇文章都将为你提供必要的工具和知识,帮助你将创意转化为现实。

热门文章

最新文章