Android 4.1: Como verificar se as notificações estão desabilitadas para o aplicativo?

98

O Android 4.1 oferece ao usuário uma caixa de seleção para desabilitar notificações para um aplicativo específico.

No entanto, como desenvolvedor, não temos como saber se uma chamada para notificar foi eficaz ou não.

Eu realmente preciso verificar se as notificações estão desabilitadas para o aplicativo atual, mas não consigo encontrar nenhuma configuração para isso na API.

Existe uma maneira de verificar essa configuração no código?

Guillaume Perrot
fonte
1
Você realmente não deveria se preocupar com isso. Suponha que sua notificação foi bem-sucedida. Se o usuário desativou explicitamente suas notificações, ele provavelmente teve um bom motivo para fazê-lo, e seu aplicativo não deve se importar se a notificação foi exibida ou não.
Kevin Coppock
Expliquei o motivo nos comentários da primeira resposta.
Guillaume Perrot
1
Aqui está o problema para marcar / rastrear code.google.com/p/android/issues/detail?id=38482 Realmente preciso disso ....
brandall

Respostas:

147

Você não pode 100% não pode.

É solicitado neste vídeo do Google I / O 2012 e o líder do projeto para as novas notificações declara que você não pode.


Editar

Atualização de 2016: Agora você pode conferir, como disse neste vídeo do Google I / O 2016 .

Use NotificationManagerCompat.areNotificationsEnabled(), na biblioteca de suporte, para verificar se as notificações estão bloqueadas na API 19+. As versões abaixo da API 19 retornarão verdadeiras (as notificações são ativadas).

insira a descrição da imagem aqui

Blundell
fonte
2
Não há nada no vídeo mostrando que não possamos ler esta configuração. Só para deixar claro: desejo apenas ler o estado atual da caixa de seleção, sem alterá-lo. Receio que você não tenha entendido minha pergunta.
Guillaume Perrot
2
Precisamos disso porque mostramos uma notificação por vez (que pode ser no aplicativo ou na barra do sistema). Se uma notificação do sistema for exibida, não mostramos um banner no aplicativo e vice-versa. Se não podemos saber se uma notificação é exibida ou não, não podemos gerenciar seu ciclo de vida mais. Acho que temos que mudar totalmente a maneira como gerenciamos as notificações agora ...
Guillaume Perrot
9
Para sua informação, a pergunta é feita (e respondida) às 48:05 no vídeo (durante o Q&A) com uma palavra curta ... Não. youtube.com/…
Devunwired de
2
@Stavros_S atualizou a resposta com o link completo. NotificationManagerCompat.areNotificationsEnabled () .
Sufian
16
@Stavros_S Você precisa usarNotificationManagerCompat.from(ctx).areNotificationsEnabled()
AlexAndro
38

Na verdade, isso é muito fácil de fazer:

/**
 * 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
fonte
3
No momento em que a pergunta foi postada, o Android 4.1 era atual, isso é apenas para Android 4.4+ e parece usar reflexão e a documentação não recomenda usá-lo para um aplicativo que não seja do sistema.
Guillaume Perrot
@GuillaumePerrot, na verdade, você está certo sobre reflexão, mas, novamente, a documentação e as declarações oficiais do android dizem que você não pode fazer isso, você também pode se limitar a isso. Desculpe pelo problema da versão, não posso ajudá-lo com isso. Se o seu cliente / solução exigir isso, então você pode querer considerar aumentar um pouco a versão necessária, já que é o SDK que está limitando você nesse ponto. Deixe-me saber se você encontrar uma maneira alternativa.
desgraci
1
É justo, mas você deve presumir que o retorno seja verdadeiro se não conseguir obter as informações. Pelo menos no meu caso de uso, faz mais sentido. Ou tenha o valor padrão como um parâmetro na função estática para torná-la mais reutilizável.
Guillaume Perrot
1
@Rahul Matte, GlobalContext é apenas uma classe de utilitário que utilizo para manter uma referência a um Context, você pode passar um Context através do método se não estiver usando / ou quiser usar essa estrutura. Espero que isto ajude!
desgraci
1
Espero que não: p mas vindo do google XD, já que este usa reflexão, o OP_POST_NOTIFICATION estava lendo o código no grep depois de me encontrar com o mesmo problema.
desgraci
37

A resposta de @blundell está correta, mas há uma pequena alteração nas versões mais recentes.

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

Se você estiver usando o Xamarin e precisar desta resposta, poderá 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
fonte
@AdamPedley AreNotificationsEnabled () foi adicionado na API 24 developer.android.com/reference/android/app/…
Sune Kjærgård
Você está correto, deve ter interpretado mal anteriormente. Excluí meu comentário original, para não confundir ninguém.
Adam Pedley
5

Parece que não há como consultar o estado de notificação.

Eu recomendo isto:

  • Projete seu aplicativo com notificações.
  • Permita que o usuário desative as notificações das configurações do aplicativo.
  • Verifique se as notificações foram clicadas. Se o usuário clicar na notificação, salve-a nas preferências.
  • Em seu aplicativo, se a configuração de notificação estiver ativada e se o usuário for Android 4.1+ (API 16), mas se o usuário não clicar na notificação por alguns dias / semanas, presuma que o usuário desativou as notificações.

Não 100% correto. Mas isso dá uma opinião.
Por exemplo, se o usuário não clicar em nenhuma notificação do aplicativo por 10-15 dias, provavelmente ele o desativou

trante
fonte
1
Esta é uma abordagem muito ampla e abstrata.
IgorGanapolsky
Esta é a melhor abordagem! Estamos fazendo isso em nosso aplicativo e você pode dizer com precisão, se as notificações estão desabilitadas. PendingIndent para CADA ação e salve na preferência. Não se esqueça de redefinir se o smartphone foi reiniciado.
JacksOnF1re
1

Eu uso este método para verificar se as notificações estão habilitadas ou não, os métodos mencionados acima funcionarão para verificar se as notificações estão habilitadas ou não. Mas a partir do Android 8 para a criação de notificações , temos que criar um canal primeiro , então, a partir do Oreo, temos que verificar se seu canal de notificação está ativado ou não .

    /**
     * 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
fonte