Android 15 将禁止NotificationListenerService 读取 OTP

今天介绍一个在国内没什么用的 Android 15 更新,主要是看到了,就顺带介绍一下 NotificationListenerService

相信大家对于 NotificationListenerService 应该不会陌生吧,例如在「微信红包通知」、「消息防撤回」、「短信增强通知」、「通知栏管理」等插件都可能会看到过它的身影,而 NotificationListenerService 是在 Android 4.3 的时候被引入,可以说是一个长期存在的 API。

简单介绍一下,首先你可以通过继承 NotificationListenerService 实现一个监听服务,通过 onListenerConnected 你可以快速判断服务是否成功启用,通过 onNotificationPosted 可以读取系统通知栏的消息。

java 复制代码
public class NotificationListener extends NotificationListenerService {
  @Override
  public void onNotificationPosted(StatusBarNotification nf) {
    super.onNotificationPosted(nf);

      Notification notification = nf.getNotification();
      Bundle extras = notification.extras;
      if (extras != null) {
          String title = extras.getString(Notification.EXTRA_TITLE, "");
          String content = extras.getString(Notification.EXTRA_TEXT, "");
          Log.e("notification", "title: " + title + " content: " + content);
      }
  }
  @Override
  public void onNotificationRemoved(StatusBarNotification nf) {
    super.onNotificationRemoved(nf);
  }

    @Override
    public void onListenerConnected() {
        super.onListenerConnected();
    }
}

之后通过在 AndroidManifest 声明服务,就可以使用对应的通知栏内容监听能力。

xml 复制代码
     <service
            android:name=".view.NotificationListener"
            android:exported="true"
            android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
            <intent-filter>
                <action android:name="android.service.notification.NotificationListenerService" />
            </intent-filter>
        </service>

当然, 由于通知内容可能包含某些敏感数据,所以一般情况下应用除非获得用户手动允许,否则 App 无法直接使用该 API。

而在原生系统下,开启权限的路径在一般在 "Settings-> Notifications -> Notification read, reply & control " ,开启时也会有对应的提示:

不过这个位置在很多第三方 OS 上面可能不一致,而且不好找,所以一般推荐可以通过 ACTION_NOTIFICATION_LISTENER_SETTINGS 来实现调整打开:

java 复制代码
      Intent intent = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS");
      intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
      context.startActivity(intent);

事实上根据 NotificationListenerService 的能力,它在国产系统里都会被定义为高危权限,正常情况下系统都不会建议用户开启它:

甚至有时候你还会看到下面这样的情况,例如左侧小米上出现受限的场景,另外右侧在我的华为上看到「平安好车主」也有对应权限描述在,也是有趣:

而且这个支持有时候很诡异,例如有时候在小米上无法触发,需要重启手机才可以正常 connected ,一般情况下可以通过 adb shell dumpsys notification 来确认 Live notification listeners 里是否包含了你定义的监听:

而在成功加入监听之后,通过这个 API App 就可以获取到各种通知的数据,例如包名、title、content 等内容,剋看到此时 App 已经拥有了极高的权限,也可以监听到你微信的通知:

可以看到当拥有 NotificationListenerService 权限之后, App 其实可以很方便地获取到需求用户的隐私内容,其中就包括 OTP 推送:

所以在 Android 15 之前,具有通知访问权限的应用能够读取所有传入的通知,甚至是带有 OTP 代码的通知,而Android 15 之后,系统会阻止不受信任的应用读取敏感通知,即使它们有权读取所有通知也是如此,gif 展示了 14 和 15 上收到 OTP 推送时系统的不同反应:

但是这个支持主要是通过 Android System Intelligence(ASI) 来完成 ,ASI 会在将所有通知发送到 NotificationListenerService 之前对通知进行处理,如果 ASI 检测到通知中包含如身份验证代码,它会告诉系统将其标记为"敏感内容",并停止将通知发送到不受信任的 NotificationListenerService

不受信任的 NotificationListenerService 属于在 Android 15 中没有 RECEIVE_SENSITIVE_NOTIFICATIONS 权限的应用。

这个权限只会赋予使用系统证书签名的应用或拥有特定角色的应用,大多数情况下,赋予RECEIVE_SENSITIVE_NOTIFICATIONS 权限的角色只能由系统应用持有,另外一些特定角色可以由第三方应用持有,例如 COMPANION_DEVICE_WATCHCOMPANION_DEVICE_GLASSES 等。

这些特定角色分别被赋予手表配套应用、智能眼镜配套应用和默认启动器等,换句话说,在 Android 15 上唯一可以读取带有身份验证代码的通知的第三方应用:连接到智能手表的应用、连接到智能眼镜的应用或默认主屏幕启动器应用。

另外,在调试时可以通过 adb 命令来做授权处理,这个调整可以保证用户在使用 NotificationListenerService 带来的便捷时能更好保护自己的深度隐私,避免 OTP 代码泄漏,当然这个调整在国内又显得不是很有用。

sh 复制代码
adb shell cmd appops set --user 0 <PACKAGE> RECEIVE_SENSITIVE_NOTIFICATIONS allow

因为这个功能依赖于 Android System Intelligence(ASI) 来完成,Android System Intelligence 作为 Private Compute Core 中的一个系统组件,它主要是在保持数据私密性的同时为 Android 中的智能功能提供支持。

曾经在 Android 12 上还出现过 Android System Intelligence 反复崩溃的问题。

而 ASI 主要依赖于安装了 Google 服务,甚至一些深度功能是 Pixel 独有,所以大多数情况下,你的手机里一般是没有 ASI 的,在没有 ASI 的情况下,就会 API 35 的模拟器场景一样, NotificationListenerService 依然拥有很高的读取能力,所以国内 ROM 厂商是否最终会同样支持 NotificationListenerService 的 OTP 隐私过滤能力还不好说,这也是为什么说这个更新有点鸡肋的原因。

后续只能坐等国内的 android 15 版更新来测试最终效果了。

相关推荐
来吧~3 分钟前
vue3使用video-player实现视频播放(可拖动视频窗口、调整大小)
前端·vue.js·音视频
江上清风山间明月8 分钟前
flutter bottomSheet 控件详解
android·flutter·底部导航·bottomsheet
鎈卟誃筅甡16 分钟前
Vuex 的使用和原理详解
前端·javascript
呆呆小雅21 分钟前
二、创建第一个VUE项目
前端·javascript·vue.js
m0_7482393327 分钟前
前端(Ajax)
前端·javascript·ajax
Fighting_p31 分钟前
【记录】列表自动滚动轮播功能实现
前端·javascript·vue.js
前端Hardy32 分钟前
HTML&CSS:超炫丝滑的卡片水波纹效果
前端·javascript·css·3d·html
技术思考者36 分钟前
HTML速查
前端·css·html
缺少动力的火车37 分钟前
Java前端基础—HTML
java·前端·html
Domain-zhuo1 小时前
Git和SVN有什么区别?
前端·javascript·vue.js·git·svn·webpack·node.js