关于Android类似qq和微信那种在桌面图标右上角更新数字的研究

时间:2020-12-17 14:16:42
记录下这个需求的研究  写的超级随意  大家凑合看 不懂再问 一起探讨

因为我们的产品也需要有即时通讯了  消息更新不可避免  
首先 要实现这个功能  当然是要借助系统的Launcher。

而谷歌并没有开放出这个标准的接口或者方法  
于是各大厂商都对Launcher这块做了各自的改动,这也给第三方开发者想要统一处理这个需求加大了难度。
网上demo也有一些  大部分是通过发送广播的方式,来通知系统更新图标上的数字

 比如我之前在github上找到一个demoTestShortCut 就很不错, 针对三星(亲测)、索尼、小米   小米貌似在miui系统里已经内部处理了这种情况  发通知栏消息的时候 会自动加数字
/***
      * 三星手机:应用图标的快捷方式上加数字
      * @param context
      * @param num
      */
    public static void samsungShortCut(Context context, String num)
     {
        int numInt = Integer.valueOf(num);
        if (numInt < 1)
        {
          num = "0";
        }else if (numInt > 99){
            num = "99";
        }
          String activityName = getLaunchActivityName(context);
        Intent localIntent = new Intent("android.intent.action.BADGE_COUNT_UPDATE");
        localIntent.putExtra("badge_count", Integer.parseInt(num));
        localIntent.putExtra("badge_count_package_name", context.getPackageName());
        localIntent.putExtra("badge_count_class_name", activityName);
        context.sendBroadcast(localIntent);
     }

/***
      * 索尼手机:应用图标的快捷方式上加数字
      * @param context
      * @param num
      */
    public static void sonyShortCut(Context context, String num)
      {
        String activityName = getLaunchActivityName(context);
        if (activityName == null){
          return;
        }
        Intent localIntent = new Intent();
        int numInt = Integer.valueOf(num);
        boolean isShow = true;
        if (numInt < 1){
          num = "";
          isShow = false;
        }else if (numInt > 99){
            num = "99";
        }
         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", activityName);
        localIntent.putExtra("com.sonyericsson.home.intent.extra.badge.MESSAGE", num);
        localIntent.putExtra("com.sonyericsson.home.intent.extra.badge.PACKAGE_NAME", context.getPackageName());
        context.sendBroadcast(localIntent);
      }

/***
     * 在小米应用图标的快捷方式上加数字<br>
     * 
     * 
     * @param context
     * @param num 显示的数字:大于99,为"99",当为""时,不显示数字,相当于隐藏了)<br><br>
     * 
     * 注意点:
     * context.getPackageName()+"/."+clazz.getSimpleName() (这个是启动activity的路径)中的"/."不能缺少
     * 
     */
    public static void xiaoMiShortCut(Context context,Class<?> clazz, String num)
      {
        Log.e(TAG, "xiaoMiShortCut....");
         Intent localIntent = new Intent("android.intent.action.APPLICATION_MESSAGE_UPDATE");
        localIntent.putExtra("android.intent.extra.update_application_component_name", context.getPackageName()+"/."+clazz.getSimpleName());
        if(TextUtils.isEmpty(num)){
            num = "";
        }else{
            int numInt = Integer.valueOf(num);
            if (numInt > 0){
              if (numInt > 99){
                    num = "99";
              }
            }else{
                num = "0";
            }
        }
        localIntent.putExtra("android.intent.extra.update_application_message_text", num);
        context.sendBroadcast(localIntent);
      }        



但没办法,我们的产品需要针对的是下面这三个厂商
华为 OPPO VIVO  使用上面的demo确没办法做到,所以还得继续研究
于是在找了很多资料没有结果以后 我决定反编译QQ和微信的源码来研究  (注:有很多机型qq和微信也没办法做到这个需求)
先从qq开始  反编译以后 在源码里搜索了很多关键字  
终于让我找到了这个类  BadgeUtilImpl.class 
太兴奋了。

  public static void  changeOPPOBadge(Context paramContext, int paramInt)
  {
    int i = 99;
    if (!isEnabled(paramContext));
    for (int j = 0; ; j = paramInt)
    {
      if (j > i);
      while (true)
      {
        if (QLog.isColorLevel())
          QLog.d("BadgeUtilImpl", 2, "changeOPPOBadge mcount=" + i);
        try
        {
          Bundle localBundle = new Bundle();
          localBundle.putInt("app_badge_count", i);
          paramContext.getContentResolver().call(Uri.parse("content://com.android.badge/badge"), "setAppBadgeCount", null, localBundle);
          return;
          i = j;
        }
        catch (Exception localException)
        {
          QLog.d("BadgeUtilImpl", 2, "OPPOBadge badge get a  crash" + localException.getMessage());
          return;
        }
      }
    }
  }


  public static String  getLauncherClassName(Context paramContext)
  {
    String str;
    if (!TextUtils.isEmpty(mLauncherClassName))
      str = mLauncherClassName;
    while (true)
    {
      return str;
      PackageManager localPackageManager = paramContext.getPackageManager();
      Intent localIntent = new Intent("android.intent.action.MAIN");
      localIntent.addCategory("android.intent.category.LAUNCHER");
      try
      {
        Iterator localIterator = localPackageManager.queryIntentActivities(localIntent, 0).iterator();
        while (true)
          if (localIterator.hasNext())
          {
            ResolveInfo localResolveInfo = (ResolveInfo)localIterator.next();
            if (!localResolveInfo.activityInfo.applicationInfo.packageName.equalsIgnoreCase(paramContext.getPackageName()))
              continue;
            str = localResolveInfo.activityInfo.name;
            mLauncherClassName = str;
            if (!QLog.isColorLevel())
              break;
            QLog.d("BadgeUtilImpl", 2, "getLauncherClassName" + mLauncherClassName);
            return str;
          }
      }
      catch (Exception localException)
      {
        return null;
      }
    }
    return null;
  }

 

  public static void  setBadge(Context paramContext, int paramInt)
  {
    setBadge(paramContext, paramInt, false);
  }

  public static void  setBadge(Context paramContext, int paramInt, boolean paramBoolean)
  {
    if (QLog.isColorLevel())
      QLog.d("BadgeUtilImpl", 2, "setBadge count=" + paramInt + "|forceSet=" + paramBoolean);
    if ((!isEnabled(paramContext)) && (!paramBoolean));
    do
    {
      return;
      if (isQQLanucher())
        setQQLauncherBadges(paramContext, paramInt);
      if (Build.MANUFACTURER.equalsIgnoreCase("ZUK"))
        changeZUKBadge(paramContext, paramInt);
      if (islenovoLanucher("com.lenovo.launcher"))
        setLenovoBadge(paramContext, paramInt);
      if (Build.MANUFACTURER.equalsIgnoreCase("Xiaomi"))
      {
        changeMIBadge(paramContext, paramInt);
        return;
      }
      if (Build.MANUFACTURER.equalsIgnoreCase("samsung"))
      {
        setSamsungBadge(paramContext, paramInt);
        return;
      }
      if (!Build.MANUFACTURER.equalsIgnoreCase("huawei"))
        continue;
      setHuaweiBadge(paramContext, paramInt);
      return;
    }
    while (!Build.MANUFACTURER.equalsIgnoreCase("OPPO"));
    changeOPPOBadge(paramContext, paramInt);
  }

  public static void  setHuaweiBadge(Context paramContext, int paramInt)
  {
    while (true)
    {
      try
      {
        if (!QLog.isColorLevel())
          continue;
        QLog.d("BadgeUtilImpl", 2, "huawiBadge mcount=" + paramInt);
        String str = getLauncherClassName(paramContext);
        if (str == null)
        {
          return;
          Bundle localBundle = new Bundle();
          localBundle.putString("package", paramContext.getPackageName());
          localBundle.putString("class", str);
          localBundle.putInt("badgenumber", paramInt);
          paramContext.getContentResolver().call(Uri.parse("content://com.huawei.android.launcher.settings/badge/"), "change_badge", null, localBundle);
          return;
        }
      }
      catch (Throwable localThrowable)
      {
        return;
      }
      if (paramInt <= 99)
        continue;
      paramInt = 99;
    }
  }

qq这里面有针对华为和OPPO的

我用华为荣耀6亲测过有效  但是华为Meta却不行(我试过 微信和qq同样不行)


OPPO的没效果 提示没有此Uri (OPPO r7  qq和微信及其他第三方app 也都不能显示数字)


再来看看vivo
qq没法显示数字 但是微信会显示  于是驱使我研究微信的源码
微信的源码混淆的比较多 找起来比qq费事  不过还是让我找到了线索
在这个包目录下com.tencent.mm.booter.notification 找到了类文件d
找到了这段代码
Intent localIntent1 = new Intent("launcher.action.CHANGE_APPLICATION_NOTIFICATION_NUM");
            localIntent1.putExtra("packageName", context.getPackageName());
            localIntent1.putExtra("className", MainActivity.class.getName());
            localIntent1.putExtra("notificationNum", paramInt);
            context.sendBroadcast(localIntent1);

经测试 vivo 也可以显示了.. 

总结一句:网上找不到资料的时候 就去研究第三方app源码吧 也许能事半功倍呢  虽然有点不厚道 哈哈