是否支持角標並不與手機廠商有關,而是你當前使用的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; } }
親測華為手機可行!