使用NotificationListenerService检查通知访问权限

27

我正在使用>=4.3版本的NotificationListenerService访问通知。在第一次启动时,我的应用会将用户带到“访问通知”系统面板,但是当“访问通知”中我的应用的复选框被禁用时,我想每次都将用户带到那里。我没有找到isNotificationAccessEnabled()方法,但我确定这是可能的,因为像Krome这样的应用也可以实现。

4个回答

58

2016年6月15日编辑

我不确定这个功能是在哪个版本的support库中添加的,但现在看起来似乎已经内置该功能了。只需使用以下代码:

NotificationManagerCompat.getEnabledListenerPackages(context); (文档链接)

这将返回一个Set<String>,您可以遍历以找到您的包名称。请注意,我个人并没有测试过这一点。但看起来这可能比我的旧解决方案更好。


旧解决方案

这段代码对我的应用程序有效:

ContentResolver contentResolver = context.getContentResolver();
String enabledNotificationListeners = Settings.Secure.getString(contentResolver, "enabled_notification_listeners");
String packageName = context.getPackageName();

// check to see if the enabledNotificationListeners String contains our package name
if (enabledNotificationListeners == null || !enabledNotificationListeners.contains(packageName))
{
    // in this situation we know that the user has not granted the app the Notification access permission
    throw new Exception();
}
else
{
    doSomethingThatRequiresNotificationAccessPermission();
}

我看到的 enabledNotificationsListeners String 的典型值如下:

  • 用户未授予其任何应用程序通知访问权限
    • null""
  • 用户已授予一个应用程序通知访问权限
    • "com.woodblockwithoutco.remotecontrollerexample/com.woodblockwithoutco.remotecontrollerexample.RemoteControlService"
  • 用户已授予两个应用程序通知访问权限
    • "com.scootrnova.android/com.scootrnova.android.ListenerService:com.woodblockwithoutco.remotecontrollerexample/com.woodblockwithoutco.remotecontrollerexample.RemoteControlService"

这个实现非常直接简单,并且表现出色 :)

P.S. 我从此答案中获得使用硬编码的 "enabled_notification_listeners" 字符串的想法。


2
这对我非常有效。唯一需要更改的是将 String packageName = context.getPackageName(); 更改为 String packageName = MyService.class.getName(); 因为我在我的启动器中进行了检查。 - Nlinscott
1
在我的测试设备(LG G3)上,该字符串包含包名和监听器类名。因此,如果您只有一个NotificationListenerService,则查找任何一个字符串都可以。由“Settings.Secure.getString”返回的字符串是以下格式中类的冒号(:)分隔列表: com.example.myapp/com.example.myapp.mynotificationlistener - Mike
3
在原生的Android 6系统上,如果从未为任何应用启用过通知监听器,则enabledNotificationListeners确实会变为NULL。 - Cumbayah
2
NotificationManagerCompat.getEnabledListenerPackages(context) 是在 SO 上检查的最佳解决方案。感谢您更新答案。 - atapi19
看起来只要通知监听器有 android:enabled="true"NotificationManagerCompat.getEnabledListenerPackages(context) 将包括我的包名,无论用户是否授予访问权限。 - P. B.
显示剩余2条评论

37
Starting with Android 8.1 (SDK 27),您可以在NotificationManager上调用isNotificationListenerAccessGranted。这是正确的API使用方式。旧版本的Android应该将getEnabledListenerPackages作为第二选择。仅依赖于您的监听器回调可能会导致不正确的结果。请参见下面的explanation
我是Krome的开发人员。为了检查服务是否已启用,我添加了一个公共静态变量,该变量在onBind方法中更改为true,并在unbind中更改为false。这就是这个服务的工作方式。
编辑:
public static boolean isNotificationAccessEnabled = false;

@Override
public void onListenerConnected() {
    isNotificationAccessEnabled = true;
}

@Override
public void onListenerDisconnected() {
    isNotificationAccessEnabled = false;
}

嗨,达米安,太棒了,非常感谢你的回答,我从未想过会收到“大人物”本人的回复 :-)! 我会尝试这个方法并让你知道是否可以自己解决。 - Nick
7
只是为了其他有兴趣的人,这是我的代码:`public static boolean isNotificationAccessEnabled = false; @Override public IBinder onBind(Intent mIntent) { IBinder mIBinder = super.onBind(mIntent); isNotificationAccessEnabled = true; return mIBinder; }@Override public boolean onUnbind(Intent mIntent) { boolean mOnUnbind = super.onUnbind(mIntent); isNotificationAccessEnabled = false; return mOnUnbind; }`与在我的主要活动中检查isNotificationAccessEnabled相结合。 - Nick
2
这个解决方案只在第一次检查时有效,因为系统调用onBind回调仅一次用于NotificationListenerService。如果您尝试取消选中(将调用onUnbind),然后再次选中,则不会第二次调用onBind,因此isNotificationAcessAnabled将为false。 - klimat
2
这不是一个可靠的解决方案。Android 大多数情况下会调用 onBind/onUnbind,但根据 Android 框架团队的设计,并非100%可靠:https://groups.google.com/forum/#!msg/android-developers/2IegSgtGxyE/iXP3lBCH5SsJ - Jim Vitek
1
这仍然不是一个可靠的解决方案。有些情况下,用户已经授予了通知的访问权限,但 onListenerConnected() 方法却没有被调用。在调试我的应用程序时,我遇到了这种情况很多次,我的应用程序也使用了 NotificationListenerService。拥有监听器连接和获得通知访问权限并不是同一回事。 - shai tibber
显示剩余4条评论

0

从Android 8.1(SDK 27)开始,您可以在NotificationManager上调用isNotificationListenerAccessGranted。这是正确的API使用方式,而不是接受答案的API。请参见下面的解释。

就像shai tibber已经说过的那样,接受的答案是不正确的。

onListenerConnected()onListenerDisconnect()甚至在没有授予NotificationListener访问权限时也会被调用。因此,依赖于这些回调来设置布尔值将会得到错误的结果。而getEnabledListenerPackages(context‌​)只会返回所有在其AndroidManifest中定义了启用通知监听器(android:enabled=true)的包。它与用户访问权限没有直接关系。文档正是如此说明:

获取具有已启用通知监听器组件的包集合。


0

稍作修改后,@Damians的答案可以很好地运行。

public class NotifyListener extends NotificationListenerService{    
        public static boolean listnerConnected = false;
    @Override
        public IBinder onBind(Intent intent) {
            Log.d(name,"onBind Called");
            listnerConnected = true;
            return super.onBind(intent);
    }   

        @Override
        public void onDestroy()
        {       
            super.onDestroy();        
            Log.e("destroy", "called");
            listnerConnected = false;

        }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接