Android 4.1: Comment vérifier que les notifications sont désactivées pour l'application?


98

Android 4.1 propose à l'utilisateur une case à cocher pour désactiver les notifications pour une application spécifique.

Cependant, en tant que développeur, nous n'avons aucun moyen de savoir si un appel à notifier a été efficace ou non.

J'ai vraiment besoin de vérifier si les notifications sont désactivées pour l'application actuelle, mais je ne trouve aucun paramètre pour cela dans l'API.

Existe-t-il un moyen de vérifier ce paramètre dans le code?


1
Vous ne devriez vraiment pas vous en préoccuper. Supposons simplement que votre notification a réussi. Si l'utilisateur a explicitement désactivé vos notifications, il avait probablement de bonnes raisons de le faire, et votre application ne devrait pas se soucier de savoir si la notification était affichée ou non.
Kevin Coppock

J'ai expliqué la raison dans les premiers commentaires de la réponse.
Guillaume Perrot

1
Voici le problème de star / track code.google.com/p/android/issues/detail?id=38482 Vraiment besoin de ça ....
brandall

Réponses:


147

Vous ne pouvez pas à 100%.

Il est demandé dans cette vidéo Google I / O 2012 et le responsable du projet pour les nouvelles notifications déclare que vous ne pouvez pas.


Éditer

Mise à jour 2016: vous pouvez maintenant le vérifier, comme indiqué dans cette vidéo Google I / O 2016 .

Utilisez NotificationManagerCompat.areNotificationsEnabled(), à partir de la bibliothèque de support, pour vérifier si les notifications sont bloquées sur l'API 19+. Les versions inférieures à l'API 19 renverront true (les notifications sont activées).

entrez la description de l'image ici


2
Rien dans la vidéo ne montre que nous ne pouvons pas lire ce paramètre. Juste pour être clair: je veux juste pouvoir lire l'état actuel de la case à cocher, sans le modifier. J'ai peur que vous n'ayez pas compris ma question.
Guillaume Perrot

2
Nous en avons besoin car nous affichons 1 notification à la fois (qui peut être intégrée à l'application ou dans la barre système). Si une notification système est affichée, nous n'affichons pas de bannière dans l'application et vice versa. Si nous ne pouvons pas savoir si une notification est affichée ou non, nous ne pouvons plus gérer son cycle de vie. Je suppose que nous devons complètement changer la façon dont nous gérons les notifications maintenant ...
Guillaume Perrot

9
Pour info, la question est posée (et répondue) à 48:05 dans la vidéo (pendant les questions / réponses) avec un petit mot ... Non. youtube.com/…
Devunwired

2
@Stavros_S réponse mise à jour avec le lien complet. NotificationManagerCompat.areNotificationsEnabled () .
Sufian

17
@Stavros_S Vous devez utiliserNotificationManagerCompat.from(ctx).areNotificationsEnabled()
AlexAndro

39

La réponse de @blundell est correcte mais il y a un changement mineur dans les versions plus récentes.

NotificationManagerCompat.from(context).areNotificationsEnabled()

38

En fait, c'est assez facile à faire:

/**
 * 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
Au moment où la question a été publiée, Android 4.1 était à jour, il s'agit uniquement d'Android 4.4+ et semble utiliser la réflexion et la documentation ne recommande pas de l'utiliser pour une application non système.
Guillaume Perrot

@GuillaumePerrot en fait, vous avez raison sur la réflexion, mais encore une fois, la documentation et les déclarations officielles d'Android disent que vous ne pouvez pas le faire, vous pouvez également vous en tenir à cela. Désolé pour le problème de version, je ne peux pas vous aider avec cela. Si votre client / solution l'exige, eh bien, vous pouvez envisager d'augmenter un peu la version requise car c'est le SDK qui vous limite à ce stade. Faites-moi savoir si vous trouvez un autre moyen.
desgraci

1
Assez juste, mais vous devez supposer que return true si vous ne pouvez pas obtenir les informations. Au moins dans mon cas d'utilisation, cela a plus de sens. Ou ayez la valeur par défaut comme paramètre dans la fonction statique pour la rendre plus réutilisable.
Guillaume Perrot

1
@Rahul Matte, GlobalContext est juste une classe utilitaire que j'utilise pour garder une référence à un contexte, vous pouvez passer un contexte à travers la méthode si vous n'utilisez pas / ou ne souhaitez pas utiliser cette structure. J'espère que cela t'aides!
desgraci

1
J'espère que non: p mais venant de google XD, puisque cela utilise la réflexion, l'OP_POST_NOTIFICATION lisait le code sur le grep après s'être retrouvé aux prises avec le même problème.
desgraci

5

Si vous utilisez Xamarin et que vous avez besoin de cette réponse, vous pouvez utiliser ce code:

//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 () a été ajouté à l'API 24 developer.android.com/reference/android/app/…
Sune Kjærgård

Vous avez raison, vous devez l'avoir mal lu auparavant. J'ai supprimé mon commentaire d'origine, afin de ne confondre personne.
Adam Pedley

5

Il semble qu'il n'y ait aucun moyen d'interroger l'état de notification.

Je recommande ceci:

  • Concevez votre application avec des notifications.
  • Permettez à l'utilisateur de désactiver les notifications des paramètres de l'application.
  • Vérifiez si les notifications sont cliquées. Si l'utilisateur clique sur la notification, enregistrez-la dans les préférences.
  • Dans votre application, si le paramètre de notification est activé et si l'utilisateur est Android 4.1+ (API 16), mais si l'utilisateur ne clique pas sur la notification pendant quelques jours / semaines, supposez que l'utilisateur a désactivé les notifications.

Pas 100% correct. Mais cela donne un avis.
Par exemple, si l'utilisateur ne clique sur aucune notification d'application pendant 10 à 15 jours, il l'a probablement désactivée


1
C'est une approche très large et abstraite.
IgorGanapolsky

C'est la meilleure approche! Nous faisons cela dans notre application et vous pouvez dire précisément si les notifications sont désactivées. PendingIndent pour CHAQUE action et sauvegarde dans les préférences. N'oubliez pas de réinitialiser si le smartphone a redémarré.
JacksOnF1re

2

J'utilise cette méthode pour vérifier si les notifications sont activées ou non, les méthodes mentionnées ci-dessus fonctionneront pour vérifier si les notifications sont activées ou non. Mais à partir d' Android 8 pour créer des notifications, nous devons d'abord créer un canal , donc à partir d'Oreo, nous devons vérifier si votre canal de notification est activé ou non .

    /**
     * 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;
    }
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.