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

时间:2020-12-17 14:16:36
记录下这个需求的研究  写的超级随意  大家凑合看 不懂再问 一起探讨
因为我们的产品也需要有即时通讯了  消息更新不可避免   首先 要实现这个功能  当然是要借助系统的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源码吧 也许能事半功倍呢  虽然有点不厚道 哈哈