Android实现应用数字角标

4,443 阅读3分钟

        最近遇到一个需求,需要将APP内某几个tab的未读消息数显示到桌面的应用角标上,于是查阅了一番资料,并咨询了几家应用开放平台,踩了几个小坑,最终勉强实现了自己的需求。由于国内主流手机为华为、小米、vivo、OPPO,故目前只准备实现这四款机型的角标功能,不过OPPO在咨询客服的时候被告知不开放数字角标的功能,因此目前就实现了华为、小米与vivo的需求。

一、华为机型

华为提供有实现方式,需要注意的地方只有两点,一个是在manifest中添加权限,
<uses-permission android:name="com.huawei.android.launcher.permission.CHANGE_BADGE"/>另一个是填写的地方是项目的launcherActivity,具体代码如下:

     /** 
        * 华为手机 创建角标 
        * @param context         
        * @param num  角标数 
        */
    public void setHuaWeiBadgeNum(Context context,int num) {
        try {
            Bundle bunlde = new Bundle();
            bunlde.putString("package", context.getPackageName());
            bunlde.putString("class", "com.xxxx.xxxx.LauncherActivity");//此处为启动页路径
            bunlde.putInt("badgenumber", num);
            context.getContentResolver().call(Uri.parse("content://com.huawei.android.launcher.settings/badge/"), "change_badge", null, bunlde);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

二、小米机型

        小米厂商的角标设置别出心裁,厂商通过通知消息来创建角标信息,所以,想要让小米手机显示应用角标,需要搭配通知一起使用。这不是什么问题,问题是当我按照文档中实现后,发现应用只有第一次会显示角标,之后都不会再显示了。其实这时候小米是创建了角标,不过由于APP在前台,所以创建后又消失了,导致我以为没有创建成功。发现这个问题后,我的实现方式就改为,当APP退到后台的时候 再去创建通知,这样角标就能正常显示了。

注意点:

          1、   提前把手机的通知过滤给关掉,不然只会有通知不会有角标显示。

2、 如果消息通知使用同一个id,则需要每次发送通知前将上一条消息清除掉,否则不会                   显示角标。

  /** 
     * 小米手机创建通知信息并创建角标
     * @param context
     * @param num      */
public void setXiaoMiBadgeNum(Context context,int num) {
    try{                NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        String title = "消息提示";
        String desc = "您有" + num + "条未读消息";  
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
            String channelId = "default";    
            String channelName = "默认通知";    
            NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH);    
            channel.setShowBadge(true);    
            notificationManager.createNotificationChannel(channel);
        }

    Notification notification = new NotificationCompat.Builder(context, "default") 
       .setContentTitle(title)
       .setContentText(desc)        
       .setWhen(System.currentTimeMillis())
       .setSmallIcon(R.mipmap.icon_logo)
       .setAutoCancel(true)
       .setChannelId("default")
       .setNumber(num)
       .setBadgeIconType(NotificationCompat.BADGE_ICON_SMALL)
       .build();

    //取消掉上一条通知消息
    notificationManager.cancel(1);
    Field field = notification.getClass().getDeclaredField("extraNotification");
    Object extraNotification = field.get(notification);
    Method method = extraNotification.getClass().getDeclaredMethod("setMessageCount", int.class);
    method.invoke(extraNotification, num);
    notificationManager.notify(1, notification);

  }catch (Exception e){
    e.printStackTrace();
  }
}



BaseApplication.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
     @Override   
     public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        }   
     @Override    
     public void onActivityStarted(Activity activity) { 
       }   
     @Override   
     public void onActivityResumed(Activity activity) { 
       }   
     @Override    
     public void onActivityPaused(Activity activity) {   
     }    
     @Override   
     public void onActivityStopped(Activity activity) { 
            //此处判断是小米机型并且是在后台则调用
           if (Build.MANUFACTURER.equalsIgnoreCase("xiaomi") && !AppUtils.isForeground()) {
                setXiaoMiBadgeNum(activity);        
            }    
     }
    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
    }
    @Override
    public void onActivityDestroyed(Activity activity) {
    }
});

//当前应用是否处于前台
public static boolean isForeground() {
    android.app.ActivityManager am = (ActivityManager) BaseApplication.getSystemService(Context.ACTIVITY_SERVICE);
    ComponentName cn = am.getRunningTasks(1).get(0).topActivity;
    String currentPackageName = cn.getPackageName();
    if (!TextUtils.isEmpty(currentPackageName) && currentPackageName.equals(BaseApplication.getPackageName())) {
        return true;
    }
    return false;
}



三、vivo机型

        vivo之前是不开放角标的,现在官方文档里开放了角标并且提供了对应的方法,与华为用法差不多,不过存在一定的限制条件。一、不能使用vivo自身的推送渠道,二、手机需要8.0及以上的Android版本。

官方文档中提示8.0以上版本需要添加flag

intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);

不过在intent的源码中,FLAG_RECEIVER_INCLUDE_BACKGROUND是被@hide修饰的,外部无法调用,所以这里直接将它对应的int值填入

vivo也需要在manifest中添加权限,不要忘记了:

<uses-permission android:name="com.vivo.notification.permission.BADGE_ICON" />

/**
 * vivo手机创建角标
 * 只有非vivo推送渠道并且8.0以上手机才可以使用下列方式
 * @param context
 */@SuppressLint("WrongConstant")
public void setVivoBadgeNum(Context context,int num) {
    Intent intent = new Intent();
    intent.setAction("launcher.action.CHANGE_APPLICATION_NOTIFICATION_NUM");
    intent.addFlags(0x01000000); //FLAG_RECEIVER_INCLUDE_BACKGROUND对应的int值
    intent.putExtra("packageName", context.getPackageName());
    intent.putExtra("className", "com.xxxx.xxxx.LauncherActivity");
    intent.putExtra("notificationNum", num);
    context.sendBroadcast(intent);
}