Android开发如何监听通知内容呢?
有些时候吧,我们需要知道通知内容,最简单的需求,我们要获取短信验证码,对吧。
以前的话我们可以通过监听内容提供者的变化,监听短信,那换一个思路呢?是不是可以监听通知呢?当然啦,如果禁止掉通知了,那就不有了。不过一般短信电话的通知是不禁止的。
而我需要做一个自己的通知栏。
官方改法,应该是把SystemUI里的通知栏移植一下。
我选择了监听的方式实现,毕竟系统都是我自己的,我想咋改就咋改。
效果

显示通知内容!
实现步骤
- 检查是否有被通知的权限
- 监听通知
- 设置权限
- 默认给权限
编写服务
public class NotificationService extends NotificationListenerService {
    public static final String TAG = "NotificationService";
    //设置的地方要置空
    public static NotificationCallbackListener mCallback = null;
    public interface NotificationCallbackListener {
        void onNotificationAdd(StatusBarNotification sbn);
        void onNotificationRemove(StatusBarNotification sbn);
    }
    @Override
    public IBinder onBind(Intent intent) {
        return super.onBind(intent);
    }
    @Override
    public void onNotificationPosted(StatusBarNotification sbn) {
        Log.d(TAG, "onNotificationPosted mCallback == > " + mCallback);
        if (mCallback != null) {
            mCallback.onNotificationAdd(sbn);
        }
    }
    @Override
    public void onNotificationRemoved(StatusBarNotification sbn) {
        Log.d(TAG, "onNotificationRemoved mCallback == > " + mCallback);
        if (mCallback != null) {
            mCallback.onNotificationRemove(sbn);
        }
    }
    @Override
    public void onListenerConnected() {
        Log.d(TAG, "onListenerConnected...");
    }
    @Override
    public void onListenerDisconnected() {
        Log.d(TAG, "onListenerDisconnected...");
    }
}
注册服务
        <service
            android:name=".data.service.NotificationService"
            android:label="@string/service_name"
            android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
            <intent-filter>
                <action android:name="android.service.notification.NotificationListenerService" />
            </intent-filter>
        </service>
NotificationManager
权限的获取,我们需要打开设置界面进行授权。比如说我这里是在Launcher的首页,那么我就在onCreate的时候去检查是否有权限,如果有则不打开,如果没有就去打开设置界面,授权。
  mNm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
检查是否有被通知的权限
    public boolean isNotificationListenersEnabled() {
        String pkgName = getPackageName();
        final String flat = Settings.Secure.getString(getContentResolver(), "enabled_notification_listeners");
        if (!TextUtils.isEmpty(flat)) {
            final String[] names = flat.split(":");
            for (int i = 0; i < names.length; i++) {
                final ComponentName cn = ComponentName.unflattenFromString(names[i]);
                if (cn != null) {
                    if (TextUtils.equals(pkgName, cn.getPackageName())) {
                        return true;
                    }
                }
            }
        }
        return false;
    }
如果没有,那么就打开权限进行设置。
打开权限设置界面
    protected boolean openNotificationSettings() {
        try {
            Intent intent = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS");
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
            return true;
        } catch (ActivityNotFoundException e) {
            try {
                Intent intent = new Intent();
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                ComponentName cn = new ComponentName("com.android.settings",
                        "com.android.settings.Settings$NotificationAccessSettingsActivity");
                intent.setComponent(cn);
                intent.putExtra(":settings:show_fragment",
                        "NotificationAccessSettings");
                startActivity(intent);
                return true;
            } catch (Exception e1) {
                e1.printStackTrace();
            }
            Toast.makeText(this, getString(R.string.not_support_notification_service), Toast.LENGTH_SHORT).show();
            e.printStackTrace();
            return false;
        }
    }


到这里,就授权了。
到这里就可以拿到通知了,具体的内容可以在回调方法里进行解析。
回调方法说明
  @Override
    public void onNotificationPosted(StatusBarNotification sbn) {
        Log.d(TAG, "onNotificationPosted mCallback == > " + mCallback);
        if (mCallback != null) {
            mCallback.onNotificationAdd(sbn);
        }
    }
有新通知

通知删除
    @Override
    public void onNotificationRemoved(StatusBarNotification sbn) {
        Log.d(TAG, "onNotificationRemoved mCallback == > " + mCallback);
        if (mCallback != null) {
            mCallback.onNotificationRemove(sbn);
        }
    }
服务链接状态回调方法
    @Override
    public void onListenerConnected() {
        Log.d(TAG, "onListenerConnected...");
    }
    @Override
    public void onListenerDisconnected() {
        Log.d(TAG, "onListenerDisconnected...");
    }
到此,基本上就可以获取到通知了,解析出来,然后显示在UI上即可。
但是,如果我们有系统源码,我们怎么可以让用户去设置这个权限呢?
直接让我们的应用拥有这个权限不就可以了吗?
直接让应用有获取通知的权限
思路:
前面我们通过打开权限授权界面,然后点击允许。那我们查找一下允许这个动作做了什么,不就可以了吗?
1. 定位授权界面代码
我们可以搜索“而且还能关闭通知或触发通知中的操作按钮”这个关键字
我们知道它在Settings里,所以可以进入到这个应用的源码里去搜索。

这样子就可以查出字符串了,接着,我们查这个字符串在哪里使用。

到这里,我们就知道在这两个类里使用了,有同学可能会疑问,xml里也可以使用呀,其实前面我们已经搜索了xml了,布局里没有。
还好,文件不多,打开看一下就知道了。
packages\apps\Settings\src\com\android\settings\notification\NotificationAccessConfirmationActivity.java
这个类里面,我们就可以找到这个允许对应的代码了。
 @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mNm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        mComponentName = getIntent().getParcelableExtra(EXTRA_COMPONENT_NAME);
        mUserId = getIntent().getIntExtra(EXTRA_USER_ID, UserHandle.USER_NULL);
        String pkgTitle = getIntent().getStringExtra(EXTRA_PACKAGE_TITLE);
        AlertController.AlertParams p = new AlertController.AlertParams(this);
        p.mTitle = getString(
                R.string.notification_listener_security_warning_title,
                pkgTitle);
        p.mMessage = getString(
                R.string.notification_listener_security_warning_summary,
                pkgTitle);
        p.mPositiveButtonText = getString(R.string.allow);
        p.mPositiveButtonListener = (a, b) -> onAllow();
        p.mNegativeButtonText = getString(R.string.deny);
        p.mNegativeButtonListener = (a, b) -> cancel();
        AlertController
                .create(this, this, getWindow())
                .installContent(p);
    }
从这里就可以知道它创建了一个dialog
有一个允许和取消
我们关注允许,onAllow()这个方法
这个方法做了以下动作
  private void onAllow() {
        String requiredPermission = Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
        try {
            ServiceInfo serviceInfo = getPackageManager().getServiceInfo(mComponentName, 0);
            if (!requiredPermission.equals(serviceInfo.permission)) {
                Slog.e(LOG_TAG,
                        "Service " + mComponentName + " lacks permission " + requiredPermission);
                return;
            }
        } catch (PackageManager.NameNotFoundException e) {
            Slog.e(LOG_TAG, "Failed to get service info for " + mComponentName, e);
            return;
        }
        mNm.setNotificationListenerAccessGranted(mComponentName, true);
        finish();
    }
重点就是这句了
mNm.setNotificationListenerAccessGranted(mComponentName, true);
mNm是这个
mNm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mComponentName是ComponentName
那么也就是给我们前面的service的componentName设置一下就可以了。
最后这样修改就可以了
 public void saveEnabledServices() {
        String requiredPermission = Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
        ComponentName mComponentName = new ComponentName("应用包名", "通知监听服务的全路径名称");
        try {
            ServiceInfo serviceInfo = getPackageManager().getServiceInfo(mComponentName, 0);
            if (!requiredPermission.equals(serviceInfo.permission)) {
                ICLogger.d("Service " + mComponentName + " lacks permission " + requiredPermission);
                return;
            }
        } catch (PackageManager.NameNotFoundException e) {
            ICLogger.d("Failed to get service info for " + mComponentName, e);
            return;
        }
        mNm.setNotificationListenerAccessGranted(mComponentName, true);
    }
okay到此,就讲完了监听系统的通知了。包括权限如何获取,默认就授权某个应用。































