Android 深入理解 Notification 机制

本文详细探讨了Android Notification的发送和接收逻辑,从app创建Notification到系统如何显示。通过源码分析,解释了NotificationManager、NotificationListenerService的角色,以及如何通过监听器模式实现通知的传递。同时解答了如何拦截并获取Notification信息的问题。
摘要由CSDN通过智能技术生成
本文预计阅读时间为20分钟

本文需要解决的问题

笔者最近正在做一个项目,里面需要用到 Android Notification 机制来实现某些特定需求。我正好通过这个机会研究一下 Android Notification 相关的发送逻辑和接收逻辑,以及整理相关的笔记。我研究 Notification 机制的目的是解决以下我在使用过程中所思考的问题:

  1. 我们创建的 Notification 实例最终以什么样的方式发送给系统?
  2. 系统是如何接收到 Notification 实例并显示的?
  3. 我们是否能拦截其他 app 的 Notification 并获取其中的信息?

什么是 Android Notification 机制?

Notification,中文名翻译为通知,每个 app 可以自定义通知的样式和内容等,它会显示在系统的通知栏等区域。用户可以打开抽屉式通知栏查看通知的详细信息。在实际生活中,Android Notification 机制有很广泛的应用,例如 IM app 的新消息通知,资讯 app 的新闻推送等等。

源码分析

本文的源码基于 Android 7.0。

Notification 的发送逻辑

一般来说,如果我们自己的 app 想发送一条新的 Notification,可以参照以下代码:

NotificationCompat.Builder mBuilder =
        new NotificationCompat.Builder(this)
        .setSmallIcon(R.drawable.notification_icon)
        .setWhen(System.currentTimeMillis())
        .setContentTitle("Test Notification Title")
        .setContentText("Test Notification Content!");
Intent resultIntent = new Intent(this, ResultActivity.class);

PendingIntent contentIntent =
        PendingIntent.getActivity(
            this, 
            0, 
            resultIntent, 
            PendingIntent.FLAG_UPDATE_CURRENT
        );
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// mId allows you to update the notification later on.
mNotificationManager.notify(mId, mBuilder.build());

可以看到,我们通过 NotificationCompat.Builder 新建了一个 Notification 对象,最后通过 NotificationManager#notify() 方法将 Notification 发送出去。

NotificationManager#notify()
public void notify(int id, Notification notification)
{
   
    notify(null, id, notification);
}

// 省略部分注释
public void notify(String tag, int id, Notification notification)
{
   
    notifyAsUser(tag, id, notification, new UserHandle(UserHandle.myUserId()));
}

/**
 * @hide
 */
public void notifyAsUser(String tag, int id, Notification notification, UserHandle user)
{
   
    int[] idOut = new int[1];
    INotificationManager service = getService();
    String pkg = mContext.getPackageName();
    // Fix the notification as best we can.
    Notification.addFieldsFromContext(mContext, notification);
    if (notification.sound != null) {
   
        notification.sound = notification.sound.getCanonicalUri();
        if (StrictMode.vmFileUriExposureEnabled()) {
   
            notification.sound.checkFileUriExposed("Notification.sound");
        }
    }
    fixLegacySmallIcon(notification, pkg);
    if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
   
        if (notification.getSmallIcon() == null) {
   
            throw new IllegalArgumentException("Invalid notification (no valid small icon): "
                    + notification);
        }
    }
    if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
    final Notification copy = Builder.maybeCloneStrippedForDelivery(notification);
    try {
   
        // !!!
        service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
                copy, idOut, user.getIdentifier());
        if (localLOGV && id != idOut[0]) {
   
            Log.v(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
        }
    } catch (RemoteException e) {
   
        throw e.rethrowFromSystemServer();
    }
}

我们可以看到,到最后会调用 service.enqueueNotificationWithTag() 方法,这里的是 service 是 INotificationManager 接口。如果熟悉 AIDL 等系统相关运行机制的话,就可以看出这里是代理类调用了代理接口的方法,实际方法实现是在 NotificationManagerService 当中。

NotificationManagerService#enqueueNotificationWithTag()
@Override
public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
         Notification notification, int[] idOut, int userId) throws RemoteException {
   
    enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
            Binder.getCallingPid(), tag, id, notification, idOut, userId);
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值