android 桌面圖標添加數字角標



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

 親測華為手機可行!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM