Android 4.1: ¿Cómo comprobar que las notificaciones están deshabilitadas para la aplicación?

98

Android 4.1 ofrece al usuario una casilla de verificación para deshabilitar las notificaciones para una aplicación específica.

Sin embargo, como desarrollador, no tenemos forma de saber si una llamada para notificar fue efectiva o no.

Realmente necesito verificar si las notificaciones están deshabilitadas para la aplicación actual, pero no puedo encontrar ninguna configuración para eso en la API.

¿Hay alguna forma de verificar esta configuración en el código?

Guillaume Perrot
fuente
1
Realmente no deberías preocuparte por eso. Simplemente asuma que su notificación fue exitosa. Si el usuario ha desactivado explícitamente sus notificaciones, entonces probablemente tuvo una buena razón para hacerlo, y a su aplicación no le debería importar si la notificación se mostró o no.
Kevin Coppock
Expliqué la razón en los comentarios de la primera respuesta.
Guillaume Perrot
1
Aquí está el problema de star / track code.google.com/p/android/issues/detail?id=38482 Realmente necesito esto ...
brandall

Respuestas:

147

No puedes 100% no puedes.

Se pregunta en este video de Google I / O 2012 y el líder del proyecto para las nuevas notificaciones declara que no puede.


Editar

Actualización de 2016: ahora puede verificarlo, como se dice en este video de Google I / O 2016 .

Use NotificationManagerCompat.areNotificationsEnabled(), desde la biblioteca de soporte, para verificar si las notificaciones están bloqueadas en API 19+. Las versiones por debajo de API 19 devolverán verdadero (las notificaciones están habilitadas).

ingrese la descripción de la imagen aquí

Blundell
fuente
2
No hay nada en el video que muestre que no podemos leer esta configuración. Para que quede claro: solo quiero poder leer el estado actual de la casilla de verificación, no alterarlo. Me temo que no entendió mi pregunta.
Guillaume Perrot
2
Necesitamos esto porque mostramos 1 notificación a la vez (que puede estar en la aplicación o en la barra del sistema). Si se muestra una notificación del sistema, no mostramos un banner en la aplicación y viceversa. Si no podemos saber si se muestra una notificación o no, ya no podemos administrar su ciclo de vida. Supongo que tenemos que cambiar por completo la forma en que administramos las notificaciones ahora ...
Guillaume Perrot
9
Para su información, la pregunta se hace (y responde) a las 48:05 en el video (durante la sesión de preguntas y respuestas) con una palabra corta ... No. youtube.com/…
Devunwired
2
@Stavros_S respuesta actualizada con el enlace completo. NotificationManagerCompat.areNotificationsEnabled () .
Sufian
17
@Stavros_S Necesitas usarNotificationManagerCompat.from(ctx).areNotificationsEnabled()
AlexAndro
38

En realidad, esto es bastante fácil de hacer:

/**
 * 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;
    }
}
desgraci
fuente
3
En el momento en que se publicó la pregunta, Android 4.1 estaba actualizado, esto es solo para Android 4.4+ y parece usar la reflexión y la documentación no recomienda usarlo para una aplicación que no sea del sistema.
Guillaume Perrot
@GuillaumePerrot en realidad, tienes razón sobre la reflexión, pero nuevamente, la documentación y las declaraciones oficiales de Android dicen que no puedes hacerlo, también puedes ceñirte a eso. Perdón por el problema de la versión, no puedo ayudarte con eso. Si su cliente / solución lo requiere, entonces es posible que desee considerar aumentar un poco la versión requerida, ya que es el SDK el que lo está limitando en ese momento. Avísame si encuentras una forma alternativa.
desgraci
1
Es bastante justo, pero debe asumir que la devolución es verdadera si no puede obtener la información. Al menos en mi caso de uso tiene más sentido. O tenga un valor predeterminado como parámetro en la función estática para que sea más reutilizable.
Guillaume Perrot
1
@Rahul Matte, GlobalContext es solo una clase de utilidad que uso para mantener una referencia a un contexto, puede pasar un contexto a través del método si no está usando / o no está dispuesto a usar esa estructura. ¡Espero que esto ayude!
desgraci
1
Espero que no: p, pero viniendo de Google XD, ya que esto usa reflexión, OP_POST_NOTIFICATION estaba leyendo el código en el grep después de encontrarme luchando con el mismo problema.
desgraci
38

La respuesta de @blundell es correcta, pero hay un cambio menor en las versiones más nuevas.

NotificationManagerCompat.from(context).areNotificationsEnabled()
Prakash
fuente
5

Si está usando Xamarin y necesita esta respuesta, puede usar este código:

//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;
    }
}
user3030630
fuente
@AdamPedley AreNotificationsEnabled () se agregó en API 24 developer.android.com/reference/android/app/…
Sune Kjærgård
Tienes razón, debes haberlo leído mal previamente. Eliminé mi comentario original para no confundir a nadie.
Adam Pedley
5

Parece que no hay forma de consultar el estado de notificación.

Recomiendo esto:

  • Diseña tu aplicación con notificaciones.
  • Permita que el usuario desactive las notificaciones desde la configuración de la aplicación.
  • Compruebe si se hace clic en las notificaciones. Si el usuario hace clic en la notificación, guárdelo en las preferencias.
  • En su aplicación, si la configuración de notificación está activada, y si el usuario es Android 4.1+ (API 16), pero si el usuario no hace clic en la notificación durante algunos días / semanas, asuma que el usuario deshabilitó las notificaciones.

No es 100% correcto. Pero esto da una opinión.
Por ejemplo, si el usuario no hace clic en ninguna notificación de la aplicación durante 10-15 días, probablemente la desactivó

trante
fuente
1
Este es un enfoque muy amplio y abstracto.
IgorGanapolsky
¡Este es el mejor enfoque! Estamos haciendo esto en nuestra aplicación y puede decir con precisión si las notificaciones están deshabilitadas. PendingIndent para CADA acción y guárdelo según sus preferencias. No olvide restablecer si el teléfono inteligente se reinició.
JacksOnF1re
2

Utilizo este método para verificar si las notificaciones están habilitadas o no, los métodos mencionados anteriormente funcionarán para verificar si las notificaciones están habilitadas o no. Pero a partir de Android 8 para crear notificaciones tenemos que crear un canal primero , por lo que desde Oreo, tenemos que comprobar si tu canal de notificaciones está habilitado o no .

    /**
     * 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;
    }
sai Pavan Kumar
fuente