Android 4.1: Як перевірити, чи сповіщення відключені для програми?


98

Android 4.1 пропонує користувачеві прапорець, щоб вимкнути сповіщення для певної програми.

Однак, як розробник, ми не маємо можливості дізнатися, чи був дзвінок для повідомлення ефективним чи ні.

Мені дійсно потрібно перевірити, чи відключені сповіщення для поточної програми, але я не можу знайти жодних налаштувань для цього в API.

Чи є спосіб перевірити це налаштування в коді?


1
Ви насправді не повинні цим займатися. Просто припустіть, що ваше повідомлення було успішним. Якщо користувач явно вимкнув ваші сповіщення, то він / вона, мабуть, мав для цього поважні причини, і вашій програмі не повинно бути цікаво, відображалось це повідомлення чи ні.
Кевін Коппок

Я пояснив причину в перших коментарях anwser.
Гійом Перро

1
Ось проблема для позначення зірочкою / відстеження code.google.com/p/android/issues/detail?id=38482 Насправді це потрібно ....
brandall

Відповіді:


147

Ви не можете на 100% не можете.

Це запитується у цьому відео Google I / O 2012, і керівник проекту для нових сповіщень заявляє, що ви не можете.


Редагувати

Оновлення 2016 року: тепер ви можете перевірити це, як зазначено у цьому відео Google I / O 2016 .

Використовуйте NotificationManagerCompat.areNotificationsEnabled()з бібліотеки підтримки, щоб перевірити, чи не блокуються сповіщення в API 19+. Версії нижче API 19 повернуть істину (сповіщення ввімкнено).

введіть тут опис зображення


2
У відео немає нічого, що показує, що ми не можемо прочитати цей параметр. Просто, щоб було зрозуміло: я просто хочу мати можливість прочитати поточний стан прапорця, не змінюючи його. Боюся, ти не зрозумів мого питання.
Гійом Перро,

2
Це нам потрібно, оскільки ми показуємо одночасно 1 повідомлення (яке може бути як у додатку, так і в системному рядку). Якщо відображається системне сповіщення, ми не відображаємо банер додатків і навпаки. Якщо ми не можемо знати, відображається повідомлення чи ні, ми більше не можемо керувати його життєвим циклом. Напевно, нам доведеться повністю змінити спосіб управління сповіщеннями зараз ...
Гійом Перро

9
FYI, запитання задається (і відповідає) о 48:05 у відео (під час запитань) одним коротким словом ... Ні. youtube.com/…
Devunwired

2
@Stavros_S оновив відповідь із повним посиланням. NotificationManagerCompat.areNotificationsEnabled () .
Суфіан

17
@Stavros_S Вам потрібно скористатисяNotificationManagerCompat.from(ctx).areNotificationsEnabled()
AlexAndro

38

Насправді це зробити досить просто:

/**
 * Created by desgraci on 5/7/15.
*/
public class NotificationsUtils {

    private static final String CHECK_OP_NO_THROW = "checkOpNoThrow";
    private static final String OP_POST_NOTIFICATION = "OP_POST_NOTIFICATION";

    public static boolean isNotificationEnabled(Context context) {

        AppOpsManager mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);

        ApplicationInfo appInfo = context.getApplicationInfo();

        String pkg = context.getApplicationContext().getPackageName();

        int uid = appInfo.uid;

        Class appOpsClass = null; /* Context.APP_OPS_MANAGER */

        try {

            appOpsClass = Class.forName(AppOpsManager.class.getName());

            Method checkOpNoThrowMethod = appOpsClass.getMethod(CHECK_OP_NO_THROW, Integer.TYPE, Integer.TYPE, String.class);

            Field opPostNotificationValue = appOpsClass.getDeclaredField(OP_POST_NOTIFICATION);
            int value = (int)opPostNotificationValue.get(Integer.class);

            return ((int)checkOpNoThrowMethod.invoke(mAppOps,value, uid, pkg) == AppOpsManager.MODE_ALLOWED);

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return false;
    }
}

3
На момент публікації запитання Android 4.1 був актуальним, це призначено лише для Android 4.4+ і, схоже, використовує роздуми, а документація не рекомендує використовувати його для несистемного додатка.
Гійом Перро

@GuillaumePerrot насправді, ти маєш рацію щодо роздумів, але знову ж таки, документація та офіційні заяви від android говорять, що ти не можеш цього зробити, ти також можеш дотримуватися цього. Пробачте про проблему з версією, я не можу вам у цьому допомогти. Якщо ваш клієнт / рішення цього вимагає, то, можливо, ви захочете трохи підняти потрібну версію, оскільки саме SDK обмежує вас на той момент. Повідомте мене, якщо ви знайдете альтернативний спосіб.
desgraci

1
Досить справедливо, але ви повинні припустити, що повернення справжнє, якщо ви не можете отримати інформацію. Принаймні, у моєму випадку використання має більше сенсу. Або встановіть значення за замовчуванням як параметр у статичній функції, щоб зробити її більш багаторазовою.
Гійом Перро

1
@Rahul Matte, GlobalContext - це просто клас утиліти, який я використовую для збереження посилання на контекст, ви можете передавати контекст методом, якщо ви не використовуєте / або не бажаєте використовувати цю структуру. Сподіваюся, це допомагає!
desgraci

1
Я сподіваюся, що вони цього не роблять: p, але походить від google XD, оскільки тут використовується відображення, OP_POST_NOTIFICATION читав код на grep після того, як виявив, що бореться з тією ж проблемою.
desgraci

38

Відповідь від @blundell правильна, але в нових версіях є незначні зміни.

NotificationManagerCompat.from(context).areNotificationsEnabled()

5

Якщо ви використовуєте Xamarin і вам потрібна ця відповідь, ви можете використовувати цей код:

//return true if this option is not supported.
public class NotificationsUtils 
{
    private const String CHECK_OP_NO_THROW = "checkOpNoThrow";
    private const String OP_POST_NOTIFICATION = "OP_POST_NOTIFICATION";

    public static bool IsNotificationEnabled(global::Android.Content.Context context) {

        AppOpsManager mAppOps = (AppOpsManager) context.GetSystemService(global::Android.Content.Context.AppOpsService);

        ApplicationInfo appInfo = context.ApplicationInfo;

        String pkg = context.ApplicationContext.PackageName;

        int uid = appInfo.Uid;

        try {

            var appOpsClass = Java.Lang.Class.ForName("android.app.AppOpsManager");
            var checkOpNoThrowMethod = appOpsClass.GetMethod(CHECK_OP_NO_THROW,Java.Lang.Integer.Type,Java.Lang.Integer.Type,new Java.Lang.String().Class);//need to add String.Type

            var opPostNotificationValue = appOpsClass.GetDeclaredField (OP_POST_NOTIFICATION);
            var value = (int)opPostNotificationValue.GetInt(Java.Lang.Integer.Type);
            var mode = (int)checkOpNoThrowMethod.Invoke(mAppOps,value, uid, pkg);
            return (mode == (int)AppOpsManagerMode.Allowed);

        } catch (Exception) 
        {
            System.Diagnostics.Debug.WriteLine  ("Notification services is off or not supported");
        } 
        return true;
    }
}

@AdamPedley AreNotificationsEnabled () було додано в API 24 developer.android.com/reference/android/app/…
Sune Kjærgård

Ви маєте рацію, мабуть, раніше це неправильно прочитали. Я видалив свій оригінальний коментар, щоб нікого не заплутати.
Адам Педлі,

5

Здається, немає можливості запитати стан сповіщення.

Я рекомендую це:

  • Створіть свою програму з повідомленнями.
  • Дозвольте користувачеві відключити сповіщення з налаштувань програми.
  • Перевірте, чи натиснуті сповіщення. Якщо користувач натискає сповіщення, збережіть це в налаштуваннях.
  • Якщо у вашому додатку ввімкнено налаштування сповіщень і якщо користувач має Android 4.1+ (API 16), але якщо користувач не натискає сповіщення кілька днів / тижнів, припустимо, що користувач відключив сповіщення.

Не на 100% правильно. Але це дає думку.
Наприклад, якщо користувач не натискає жодне повідомлення програми протягом 10-15 днів, можливо, він його вимкнув


1
Це дуже широкий і абстрактний підхід.
Ігор Ганапольський

Це найкращий підхід! Ми робимо це в нашому додатку, і ви можете точно сказати, якщо сповіщення вимкнено. PendingIndent для КОЖНОЇ дії та збережіть його за бажанням. Не забудьте скинути, якщо смартфон перезавантажився.
JacksOnF1re

2

Я використовую цей метод, щоб перевірити, чи активовані сповіщення чи ні, вищезазначені методи будуть працювати для перевірки того, чи активовані сповіщення чи ні. Але починаючи з Android 8 і далі для створення сповіщень, ми повинні спочатку створити канал , тож від Oreo ми повинні перевірити, чи ваш канал сповіщень увімкнено чи ні .

    /**
     * Checking Whether notifications are enabled or not
     * @return true if notifications are enabled otherwise false
     */
    public static final String CHANNEL_ID = your_channel_id";

    private boolean isNotificationChannelEnabled(){
        if(NotificationManagerCompat.from(this).areNotificationsEnabled()) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
                NotificationChannel channel = manager.getNotificationChannel(CHANNEL_ID);
                if (channel == null)
                    return true; //channel is not yet created so return boolean
                // by only checking whether notifications enabled or not
                return channel.getImportance() != NotificationManager.IMPORTANCE_NONE;
            }
            return true;
        }
        return false;
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.