是否支持角标并不与手机厂商有关,而是你当前使用的launcher开发厂商有关。
方法实现:
import android.app.Application; import android.app.Notification; import android.content.Intent; import android.support.annotation.NonNull; /** *谷歌 */ public class GoogleModelImpl implements IconBadgeNumModel { private static final String NOTIFICATION_ERROR = "google not support before API O"; @Override public Notification setIconBadgeNum(@NonNull Application context, Notification notification, int count) throws Exception { if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.O) { throw new Exception(NOTIFICATION_ERROR); } 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", Utils.getInstance().getLaunchIntentForPackage(context)); // com.test. badge.MainActivity is your apk main activity // if (Utils.getInstance().canResolveBroadcast(context, intent)) { context.sendBroadcast(intent); // } else { // throw new Exception(UNABLE_TO_RESOLVE_INTENT_ERROR_ + intent.toString()); // } return notification; } }
import android.app.Application; import android.app.Notification; import android.net.Uri; import android.os.Bundle; import android.support.annotation.NonNull; /** * https://developer.huawei.com/consumer/cn/devservice/doc/30802 * <p> * 华为 */ public class HuaWeiModelImpl implements IconBadgeNumModel { @Override public Notification setIconBadgeNum(@NonNull Application context, Notification notification, int count) throws Exception { Bundle bunlde = new Bundle(); bunlde.putString("package", context.getPackageName()); // com.test.badge is your package name bunlde.putString("class", Utils.getInstance().getLaunchIntentForPackage(context)); // com.test. badge.MainActivity is your apk main activity bunlde.putInt("badgenumber", count); context.getContentResolver().call(Uri.parse("content://com.huawei.android.launcher.settings/badge/"), "change_badge", null, bunlde); return notification; } }
import android.app.Application; import android.app.Notification; import android.support.annotation.NonNull; //魅族 public class MeizuModelImpl implements IconBadgeNumModel { private static final String NOTIFICATION_ERROR = "not support : meizu"; @Override public Notification setIconBadgeNum(@NonNull Application context, Notification notification, int count) throws Exception { if (true) { throw new Exception(NOTIFICATION_ERROR); } return null; } }
import android.app.Application; import android.app.Notification; import android.support.annotation.NonNull; /** * 以下是oppo客服原文(其中没有说明3.3中日活量和总下载量的标准) * <p> * 亲,您可以通过邮件的形式提交申请,邮件形式如下: * <p> * 1.主题:“申请开放OPPO手机应用角标权限——(应用名称)” * <p> * 2.收件人:devtec@oppo.com * <p> * 3.正文:应用角标申请所需材料 * 以下为应用角标申请所需材料: * 1.应用方申请人基本信息(姓名、邮箱、手机、微信); * 2.应用方厂商介绍(不少于200字); * 3.申请应用近一个月内IOS与安卓系统的平均日活量及总下载量介绍; * 4.申请应用产品主要功能介绍(不少于100字); * 5.申请应用期望角标出现的全部场景。(即哪些类的消息需要出现角标,需全部列出) * <p> * 您这边以邮件的形式申请接入角标后,OPPO方审核人员将在接收日期10个工作日内给出审核结果。感谢您对OPPO开放平台的关注与信任,还 * 请您耐心等待的哦~ */ public class OPPOModelImpl implements IconBadgeNumModel { private static final String NOTIFICATION_ERROR = "not support : oppo"; @Override public Notification setIconBadgeNum(@NonNull Application context, Notification notification, int count) throws Exception { if (true) { throw new Exception(NOTIFICATION_ERROR); } return null; } }
import android.app.Application; import android.app.Notification; import android.content.Intent; import android.support.annotation.NonNull; import static com.demo.badges.Utils.UNABLE_TO_RESOLVE_INTENT_ERROR_; /** * 没有找到官方文档说明,只有网上的方法 * <p> * Galaxy S8/SM-G9500/android 8.0 * Galaxy Galaxy Note8/SM-N9500/android 8.0 * 三星 */ public class SamsungModelImpl implements IconBadgeNumModel { private static final String NOTIFICATION_ERROR = "not support : samsung"; @Override public Notification setIconBadgeNum(@NonNull Application context, Notification notification, int count) throws Exception { 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", Utils.getInstance().getLaunchIntentForPackage(context)); if (Utils.getInstance().canResolveBroadcast(context, intent)) { context.sendBroadcast(intent); } else { throw new Exception(UNABLE_TO_RESOLVE_INTENT_ERROR_ + intent.toString()); } return notification; } }
import android.app.Application; import android.app.Notification; import android.support.annotation.NonNull; /** * 网上查到了此段代码,但在vivo X21A[android-8.1.0/Funtouch OS_4.0]真机上并未测试成功。 * 在vivo开发者平台上与人工客服联系后,对方回复暂时没有公开的方法可以设置,也没有渠道可以申请,只有vivo特别指定的应用可以实现(微信、微博等) */ public class VIVOModelImpl implements IconBadgeNumModel { private static final String NOTIFICATION_ERROR = "not support : vivo"; @Override public Notification setIconBadgeNum(@NonNull Application context, Notification notification, int count) throws Exception { if (true) { throw new Exception(NOTIFICATION_ERROR); } return null; } }
import android.app.Application; import android.app.Notification; import android.support.annotation.NonNull; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * https://dev.mi.com/console/doc/detail?pId=939 * <p> * 必须发送通知 */ public class XiaoMiModelImpl implements IconBadgeNumModel { private static final String NOTIFICATION_ERROR = "Xiaomi phones must send notification"; @Override public Notification setIconBadgeNum(@NonNull Application context, Notification notification, int count) throws Exception { if (notification == null) { throw new Exception(NOTIFICATION_ERROR); } Field field = notification.getClass().getDeclaredField("extraNotification"); Object extraNotification = field.get(notification); Method method = extraNotification.getClass().getDeclaredMethod("setMessageCount", int.class); method.invoke(extraNotification, count); return notification; } }
import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import java.util.List; public class Utils { public static final String UNABLE_TO_RESOLVE_INTENT_ERROR_ = "unable to resolve intent: "; private static Utils instance; public static Utils getInstance() { if (instance == null) { instance = new Utils(); } return instance; } public boolean canResolveBroadcast(Context context, Intent intent) { PackageManager packageManager = context.getPackageManager(); List<ResolveInfo> receivers = packageManager.queryBroadcastReceivers(intent, 0); return receivers != null && receivers.size() > 0; } public String getLaunchIntentForPackage(Context context) { return context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()).getComponent().getClassName(); } }
import android.app.Application; import android.app.Notification; import android.support.annotation.NonNull; public interface IconBadgeNumModel { Notification setIconBadgeNum(@NonNull Application context, Notification notification, int count) throws Exception; }
import android.content.Context; import android.content.Intent; import android.content.pm.ResolveInfo; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import java.util.HashMap; import java.util.Map; public class LauncherHelper { public final static String GOOGLE = "google"; public final static String HUAWEI = "huawei"; public final static String MEIZU = "meizu"; public final static String XIAOMI = "xiaomi"; public final static String OPPO = "oppo"; public final static String VIVO = "vivo"; public final static String SAMSUNG = "samsung"; private static Map<String, String> launcherMap; static { launcherMap = new HashMap<>(); launcherMap.put("com.huawei.android.launcher", HUAWEI); launcherMap.put("com.miui.home", XIAOMI); launcherMap.put("com.sec.android.app.launcher", SAMSUNG); launcherMap.put("com.google.android.apps.nexuslauncher", GOOGLE); } @Nullable public String getLauncherTypeByName(@NonNull String launcherName) { return launcherMap.get(launcherName); } @Nullable public String getLauncherPackageName(@NonNull Context context) { final Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_HOME); final ResolveInfo res = context.getPackageManager().resolveActivity(intent, 0); if (res.activityInfo == null) { // should not happen. A home is always installed, isn‘t it? return null; } if (res.activityInfo.packageName.equals("android")) { return null; } else { return res.activityInfo.packageName; } } }
import android.app.Application; import android.app.Notification; import android.os.Build; import android.support.annotation.NonNull; import android.text.TextUtils; import java.util.HashMap; import java.util.Map; public class IconBadgeNumManager implements IconBadgeNumModel { private static final String NOT_SUPPORT_PHONE = "not support your phone [ Build.MANUFACTURER is null ]"; private static final String NOT_SUPPORT_MANUFACTURER_ = "not support "; private static final String NOT_SUPPORT_LAUNCHER = "not support your launcher [ default launcher is null ]"; private static final String NOT_SUPPORT_LAUNCHER_ = "not support "; private Map<String, IconBadgeNumModel> iconBadgeNumModelMap; private LauncherHelper launcherHelper; public IconBadgeNumManager() { this.launcherHelper = new LauncherHelper(); iconBadgeNumModelMap = new HashMap<>(); } @Override public Notification setIconBadgeNum(@NonNull Application context, Notification notification, int count) throws Exception { IconBadgeNumModel iconBadgeNumModel = getSetIconBadgeNumModel(context); return iconBadgeNumModel.setIconBadgeNum(context, notification, count); } /** * 根据手机类型获取相应Model * * @deprecated 判断当前launcher更加准确 */ @Deprecated @NonNull private IconBadgeNumModel getIconBadgeNumModelByManufacturer() throws Exception { if (TextUtils.isEmpty(Build.MANUFACTURER)) { throw new Exception(NOT_SUPPORT_PHONE); } switch (Build.MANUFACTURER.toLowerCase()) { case MobileBrand.HUAWEI: return new GoogleModelImpl(); case MobileBrand.XIAOMI: return new XiaoMiModelImpl(); case MobileBrand.VIVO: return new VIVOModelImpl(); case MobileBrand.OPPO: return new OPPOModelImpl(); case MobileBrand.SAMSUNG: return new SamsungModelImpl(); case MobileBrand.MEIZU: return new MeizuModelImpl(); case MobileBrand.GOOGLE: return new GoogleModelImpl(); default: throw new Exception(NOT_SUPPORT_MANUFACTURER_ + Build.MANUFACTURER); } } /** * 根据手机当前launcher获取相应Model */ @NonNull private IconBadgeNumModel getIconBadgeNumModelByLauncher(@NonNull String launcherType) throws Exception { switch (launcherType) { case LauncherHelper.HUAWEI: return new HuaWeiModelImpl(); case LauncherHelper.XIAOMI: return new XiaoMiModelImpl(); case LauncherHelper.VIVO: return new VIVOModelImpl(); case LauncherHelper.OPPO: return new OPPOModelImpl(); case LauncherHelper.SAMSUNG: return new SamsungModelImpl(); case LauncherHelper.MEIZU: return new MeizuModelImpl(); case LauncherHelper.GOOGLE: return new GoogleModelImpl(); default: throw new Exception(NOT_SUPPORT_LAUNCHER_ + launcherType); } } @NonNull private IconBadgeNumModel getSetIconBadgeNumModel(@NonNull Application context) throws Exception { String launcherName = launcherHelper.getLauncherPackageName(context); if (TextUtils.isEmpty(launcherName)) { throw new Exception(NOT_SUPPORT_LAUNCHER); } String launcherType = launcherHelper.getLauncherTypeByName(launcherName); if (TextUtils.isEmpty(launcherType)) { throw new Exception(NOT_SUPPORT_LAUNCHER_ + launcherName); } if (iconBadgeNumModelMap.containsKey(launcherType)) { return iconBadgeNumModelMap.get(launcherType); } IconBadgeNumModel iconBadgeNumModel = getIconBadgeNumModelByLauncher(launcherType); iconBadgeNumModelMap.put(launcherType, iconBadgeNumModel); return iconBadgeNumModel; } }
测试:
import android.content.Intent; import android.os.Build; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import com.demo.badges.LauncherHelper; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.e(TAG, Build.MANUFACTURER); Log.e(TAG, new LauncherHelper().getLauncherPackageName(this)); findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent i = new Intent(MainActivity.this, MyService.class); startService(i); } }); findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent i = new Intent(MainActivity.this, MyService.class); stopService(i); } }); } }
import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.Service; import android.content.Context; import android.content.Intent; import android.graphics.Color; import android.os.Build; import android.os.IBinder; import android.support.annotation.RequiresApi; import android.support.v4.app.NotificationCompat; import com.demo.badges.IconBadgeNumManager; public class MyService extends Service { IconBadgeNumManager setIconBadgeNumManager; private boolean isStop; private int count; Thread thread = new Thread(new Runnable() { @Override public void run() { while (!isStop) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } count += 2; sendIconNumNotification(); } } }); public MyService() { setIconBadgeNumManager = new IconBadgeNumManager(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { isStop = false; thread.start(); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); isStop = true; } @Override public IBinder onBind(Intent intent) { throw new UnsupportedOperationException("Not yet implemented"); } private void sendIconNumNotification() { NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); if (nm == null) return; String notificationChannelId = null; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { NotificationChannel notificationChannel = createNotificationChannel(); nm.createNotificationChannel(notificationChannel); notificationChannelId = notificationChannel.getId(); } Notification notification = null; try { notification = new NotificationCompat.Builder(this, notificationChannelId) .setSmallIcon(getApplicationInfo().icon) .setWhen(System.currentTimeMillis()) .setContentTitle("title") .setContentText("content num: " + count) .setTicker("ticker") .setAutoCancel(true) .setNumber(count) .build(); notification = setIconBadgeNumManager.setIconBadgeNum(getApplication(), notification, count); nm.notify(32154, notification); } catch (Exception e) { e.printStackTrace(); } } @RequiresApi(api = Build.VERSION_CODES.O) private static NotificationChannel createNotificationChannel() { String channelId = "test"; NotificationChannel channel = null; channel = new NotificationChannel(channelId, "Channel1", NotificationManager.IMPORTANCE_DEFAULT); channel.enableLights(true); //是否在桌面icon右上角展示小红点 channel.setLightColor(Color.RED); //小红点颜色 channel.setShowBadge(true); //是否在久按桌面图标时显示此渠道的通知 return channel; } }
亲测华为手机可行!