16

我有一个 android 应用程序正在尝试使用 api 18 中的新 NotificationListenerService 类。我创建了自己的服务类,该类继承自该类并覆盖了 onNotificationPosted 和 onNotificationRemoved 事件,尽管我的服务似乎启动得很好,但这两个事件从来没有当我收到或删除通知时似乎被调用。

有没有人在这个类上取得了任何成功,或者他们可能会分享任何源代码来准确地展示如何使用这个类?

4

9 回答 9

31

根据我的经验,几乎所有这些答案都非常接近正确的解决方案!

CORE问题似乎发生在开发过程中;在您开发代码时,当您在调试会话之间更新应用程序时,“通知访问”设置将不再受到尊重。

如果您的 APK/二进制文件发生更改并且 NotificationListenerService 停止:

  • 重新启动修复它。
  • 回到“通知访问”并禁用并重新启用您的应用程序即可修复它。

希望通过 Google Play 更新您的应用时这不是问题。

作为最佳实践,我为我的应用添加了一个溢出菜单选项,该选项仅显示在非发布版本中,让我可以轻松访问设置:

NotificationListener.java:

public class NotificationListener
    extends NotificationListenerService
    implements RemoteController.OnClientUpdateListener
{
    private static final int VERSION_SDK_INT = VERSION.SDK_INT;

    public static boolean supportsNotificationListenerSettings()
    {
        return VERSION_SDK_INT >= 19;
    }

    @SuppressLint("InlinedApi")
    @TargetApi(19)
    public static Intent getIntentNotificationListenerSettings()
    {
        final String ACTION_NOTIFICATION_LISTENER_SETTINGS;
        if (VERSION_SDK_INT >= 22)
        {
            ACTION_NOTIFICATION_LISTENER_SETTINGS = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
        }
        else
        {
            ACTION_NOTIFICATION_LISTENER_SETTINGS = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS";
        }

        return new Intent(ACTION_NOTIFICATION_LISTENER_SETTINGS);
    }

    ...
}

menu_my_activity.xml:

<menu
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".MyActivity"
    >

    <item
        android:id="@+id/action_application_info"
        android:title="@string/action_application_info"
        app:showAsAction="never"
        />

    <item
        android:id="@+id/action_notification_settings"
        android:title="Notification Settings"
        app:showAsAction="never"
        />

</menu>

我的活动.java:

@Override
public boolean onCreateOptionsMenu(Menu menu)
{
    getMenuInflater().inflate(R.menu.menu_my_activity, menu);
    return super.onCreateOptionsMenu(menu);
}

@Override
public boolean onPrepareOptionsMenu(Menu menu)
{
    MenuItem menuItem;
    menuItem = menu.findItem(R.id.action_application_info);
    if (menuItem != null)
    {
        menuItem.setVisible(BuildConfig.DEBUG);
    }
    menuItem = menu.findItem(R.id.action_notification_settings);
    if (menuItem != null)
    {
        menuItem.setVisible(BuildConfig.DEBUG && NotificationListener.supportsNotificationListenerSettings());
    }
    return super.onPrepareOptionsMenu(menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item)
{
    switch (item.getItemId())
    {
        case R.id.action_application_info:
            startActivity(new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + getPackageName())));
            return true;
        case R.id.action_notification_settings:
            startActivity(NotificationListener.getIntentNotificationListenerSettings());
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}
于 2016-05-06T20:45:07.400 回答
17

安装正确配置的应用程序后,您应该授予它。

您可以在“设置 > 安全 > 通知访问”中找到应用程序的名称,然后确保选中该复选框。:)

于 2013-07-29T04:40:37.423 回答
8

更新:https ://gist.github.com/xinghui/b2ddd8cffe55c4b62f5d8846d5545bf9

private void toggleNotificationListenerService() {
    PackageManager pm = getPackageManager();
    pm.setComponentEnabledSetting(new ComponentName(this, com.xinghui.notificationlistenerservicedemo.NotificationListenerServiceImpl.class),
            PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);

    pm.setComponentEnabledSetting(new ComponentName(this, com.xinghui.notificationlistenerservicedemo.NotificationListenerServiceImpl.class),
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);

}

在此处输入图像描述

adb shell dumpsys 通知

检查哪个服务正在运行。

com.android.server.notification.ManagedServices#rebindServices

toggleNotificationListenerService()触发系统调用此方法。

于 2016-07-28T12:21:45.487 回答
4

我遇到了这个错误:

https://code.google.com/p/android/issues/detail?id=59044

只有在我重新启动手机后,通知才开始出现在我的服务中。

于 2014-09-08T18:03:03.833 回答
2

经过数小时的研究,我终于找到了实际有效的示例代码:

https://github.com/yihongyuelan/NotificationListenerServiceDemo

于 2015-05-08T19:35:44.390 回答
1

在对设备进行多次调试后,重命名 NotificationListener 类有助于解决问题。将其重命名为什么并不重要,只需将其更改为与以前名称不同的名称即可。我总是不得不一遍又一遍地这样做。

于 2018-04-12T18:11:48.780 回答
0

NLService will be working all the time as per android docs but in some cases it will be unbind from your specific app and may restarting your phone it will bind again . But in safer side you can have this check whenever your starts ,

// check NLsettings
private void checkNLSettings() {
    //check notification access
    if (!NotificationUtils.isNotificationServiceEnabled(this)) {
        //start NLsetting activity
        Intent intent = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS");
        startActivityForResult(intent, REQUEST_ACCESSIBLITYCODE);
        finish();
    }
    //check isNLservice running
    if (!isNLServiceRunning()) {
        enableNotificationListenerService(this);
    }

    Toast.makeText(this, "NLS == " + isNLServiceRunning(), Toast.LENGTH_SHORT).show();
}

private boolean isNLServiceRunning() {
    ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    for (ActivityManager.RunningServiceInfo service :
            manager.getRunningServices(Integer.MAX_VALUE)) {
        if (NLService.class.getName().equals(service.service.getClassName())) {
            return true;
        }
    }
    return false;
}

/**
 * enable notification service.
 *
 * @param context context
 */
public static void enableNotificationListenerService(Context context) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        NotificationListenerService.requestRebind(new ComponentName(context.getPackageName(),
                COMPONENT_NLSERVICE));
    } else {
        PackageManager pm = context.getPackageManager();
        pm.setComponentEnabledSetting(new ComponentName(context.getPackageName(),
                        COMPONENT_NLSERVICE),
                PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                PackageManager.DONT_KILL_APP);
    }
}
于 2018-09-21T09:01:06.937 回答
0

有时删除构建和重建源可能是问题。

我挣扎了3天,这就是我所做的:

AndroidManifest.xml

仅从类示例更改服务名称:

<service
          android:name=".NotificationListener"
          android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
          <intent-filter>
              <action android:name="android.service.notification.NotificationListenerService" />
          </intent-filter>
      </service>

 <service
          android:name="com.mypackage.example.NotificationListener"
          android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
          <intent-filter>
              <action android:name="android.service.notification.NotificationListenerService" />
          </intent-filter>
      </service>

导航到您的根目录 > android ,然后删除构建文件夹,让您的项目重新构建。

于 2017-03-19T02:04:09.997 回答
-2

我刚刚遇到了这个类的一个很好的小例子:

http://www.kpbird.com/2013/07/android-notificationlistenerservice.html

我从这个示例中学到的一件事是,当通过新的通知访问屏幕授予权限时,我创建的通知服务会自动启动,这意味着我的应用程序不必手动启动该服务。

于 2013-08-03T05:54:55.137 回答