Skip to content

Latest commit

 

History

History
562 lines (368 loc) · 25.5 KB

通知.md

File metadata and controls

562 lines (368 loc) · 25.5 KB

通知

简介

Android 的通知系统是一种用于在应用程序以外的位置通知用户的重要信息的方式。通知可以是声音、图标、振动、弹窗、LED灯等,通知可以显示在锁屏上、通知中心、状态栏、悬浮窗等。

以下是一些与 Android 通知相关的知识点:

  1. 通知的组成
    • Icon: 通知的图标。
    • Title: 通知的标题。
    • Text: 通知的内容。
    • Priority: 通知的优先级。
    • Actions: 通知的操作,比如可以在通知上添加按钮,当用户点击按钮时可以触发某些操作。

  1. 通知频道 (Notification Channels): 从 Android O(8.0)开始,所有的通知都必须分配到一个通知频道。通知频道是一种你可以向用户展示的用户可自定义通知的方法。
  2. 通知样式: 你可以自定义通知的样式,例如展示大图片、多行文字等。你可以使用 NotificationCompat.BigTextStyleNotificationCompat.BigPictureStyle 等。
  3. 通知操作: 可以在通知上添加操作按钮,当用户点击这个按钮时可以触发某些操作。
  4. 通知优先级和打断模式: 可以设置通知的优先级,从而影响通知的展示方式。
  5. 进度指示器: 通知上可以显示进度指示器,这对于展示一个后台任务的进度很有用。
  6. 全局的通知设置: 可以在设置中全局设置通知的行为,例如是否允许通知显示、是否允许通知震动等。

普通通知的代码示例

package com.open.notifygo;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.widget.TextView;

import com.open.notifygo.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {

    private static final String CHANNEL_ID = "channel_id";
    private static final int NOTIFICATION_ID = 1;


    // Used to load the 'notifygo' library on application startup.
    static {
        System.loadLibrary("notifygo");
    }

    private ActivityMainBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        // Example of a call to a native method
        TextView tv = binding.sampleText;
        tv.setText(stringFromJNI());

        createNotificationChannel();

        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setSmallIcon(R.drawable.ic_launcher_foreground)
                .setContentTitle("Sample Notification")
                .setContentText("This is a sample notification")
                .setPriority(NotificationCompat.PRIORITY_DEFAULT);

        NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
        if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        notificationManager.notify(NOTIFICATION_ID, builder.build());
    }

    /**
     * A native method that is implemented by the 'notifygo' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            CharSequence name = "Sample Channel";
            String description = "This is a sample notification channel";
            int importance = NotificationManager.IMPORTANCE_DEFAULT;
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
            channel.setDescription(description);
            NotificationManager notificationManager = getSystemService(NotificationManager.class);
            notificationManager.createNotificationChannel(channel);
        }
    }
}

分析代码

用于创建 Notification 对象

        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setSmallIcon(R.drawable.ic_launcher_foreground)
                .setContentTitle("Sample Notification")
                .setContentText("This is a sample notification")
                .setPriority(NotificationCompat.PRIORITY_DEFAULT);
  1. NotificationCompat.Builder(this, CHANNEL_ID):这将创建一个 NotificationCompat.Builder 对象。构造函数需要两个参数:
    • this: 这是上下文。
    • CHANNEL_ID: 这是通知渠道的 ID。通知将归纳到这个通知渠道。
  2. setSmallIcon(R.drawable.ic_launcher_foreground):这将设置通知的小图标。这是必需的。
  3. setContentTitle("Sample Notification"):这将设置通知的标题。
  4. setContentText("This is a sample notification"):这将设置通知的文本。
  5. setPriority(NotificationCompat.PRIORITY_DEFAULT):这将设置通知的优先级。这将决定通知的显示方式。例如,PRIORITY_DEFAULT 将使通知以正常方式显示。(Android8之后的优先级就不是在这个地方进行设置的了,是在通知的渠道当中设置的,这里设置没有用,也可以直接删了)

通知渠道和通知渠道ID

我们来看看这个,CHANNEL_ID,这是一个什么东西

假设你有一个新闻应用程序,这个应用程序发送两种类型的通知:一种是重要的新闻更新(例如,突发新闻),另一种是次要的新闻更新(例如,娱乐新闻)。

在这种情况下,你可以创建两个通知渠道:

  1. 一个用于重要的新闻更新。你可以为这个通知渠道设置一个高的重要性级别,这将使这些通知在用户的设备上更加突出。
  2. 另一个用于次要的新闻更新。你可以为这个通知渠道设置一个低的重要性级别,这将使这些通知在用户的设备上不那么突出。

Android 8.0没有通知渠道之前,我们是,每一个通知都要单独的,设置他们的各个属性,并且程序一旦设置了,就没有办法修改。现在我们不需要为每一个通知设置属性,只需要,给一类通知设置属性,然后将各个不同的通知,分成不同的类。

通知渠道可以用于管理应用程序的以下通知设置:(简单来说就是通知的各种属性)

  1. 重要性:这将决定通知的显示方式。例如,高重要性的通知可能会以对话框的形式显示,而低重要性的通知可能只会在通知栏中显示。
  2. 声音:这将决定通知的声音。
  3. 振动:这将决定通知是否会使设备振动。
  4. 指示灯:这将决定通知是否会使设备的指示灯闪烁。
  5. 锁屏显示:这将决定通知是否在锁屏上显示。
  6. 显示角标:这将决定通知是否显示应用程序图标上的角标。
  7. 优先级:这将决定通知在通知栏中的位置。高优先级的通知将显示在通知栏的顶部,而低优先级的通知将显示在通知栏的底部。
  8. 干扰:这将决定通知是否会干扰用户。例如,你可以设置一个通知渠道为“紧急”级别,这将使通知播放声音,并显示为一个弹出的对话框。

我们看看设置渠道的代码

    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            CharSequence name = "Sample Channel";
            String description = "This is a sample notification channel";
            int importance = NotificationManager.IMPORTANCE_UNSPECIFIED;
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
            channel.setDescription(description);
            // 设置渠道的通知灯光颜色
            channel.setLightColor(Color.RED);
            // 设置是否应显示通知灯
            channel.enableLights(true);
            // 设置是否应该振动
            channel.enableVibration(true);
            // 设置振动模式。此处示例为:延迟 0ms,然后振动 500ms,再延迟 500ms,再振动 500ms
            channel.setVibrationPattern(new long[]{0, 500, 500, 500});
            // 设置是否绕过“请勿打扰”模式
            channel.setBypassDnd(true);
            // 设置显示在锁屏上的通知的可见性
            channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
            NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
            notificationManager.createNotificationChannel(channel);
        }
    }
  1. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {: 这行代码检查设备的 Android 版本是否是 8.0 或更高。因为通知渠道是在 Android 8.0 中引入的,所以只有在 Android 8.0 或更高版本的设备上才需要创建通知渠道。
  2. CharSequence name = "Sample Channel";: 这行代码定义了通知渠道的名字。这个名字是用户可读的,会显示在设备的设置中。
  3. String description = "This is a sample notification channel";: 这行代码定义了通知渠道的描述。这个描述也是用户可读的,会显示在设备的设置中。
  4. int importance = NotificationManager.IMPORTANCE_UNSPECIFIED;: 这行代码定义了通知渠道的重要性。这个重要性会影响通知的显示方式。例如,高重要性的通知会显示在屏幕的顶部,并且可能会发出声音。
  5. NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);: 这行代码创建了一个新的 NotificationChannel 对象。这个对象需要三个参数:通知渠道的 ID、名字和重要性。
  6. channel.setDescription(description);: 这行代码设置了通知渠道的描述。
  7. NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);: 这行代码获取了 NotificationManager 服务。这个服务用于管理所有的通知。
  8. notificationManager.createNotificationChannel(channel);: 这行代码使用 NotificationManager 服务创建了通知渠道。

发送指定的通知ID的通知

NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
    return;
}

notificationManager.notify(NOTIFICATION_ID, builder.build());

这一段代码就是用来发送的代码了

  1. 通过NotificationManagerCompat.from(this)获得了NotificationManagerCompat的一个实例。
  2. 使用ActivityCompat.checkSelfPermission检查了当前应用是否具有发送通知的权限。POST_NOTIFICATIONS是一个权限,但它实际上不是一个常规用户可以授权的权限,而是一个保护级别为“正常”的权限,不需要在清单中声明也不需要在运行时请求。如果没有这个权限,方法会返回,不会继续执行。
  3. 使用notificationManager.notify方法发送通知。NOTIFICATION_ID是一个唯一标识通知的整数,builder.build()构建出一个Notification对象。如果应用程序希望更新、取消或检索稍后的通知,可以通过相同的ID来操作。

更新通知

他这里的更新的意思:

发送一个通知,并且隔一段时间再发一次,就是,更新通知

// Build the initial notification
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setContentTitle("Initial Title")
        .setContentText("Initial Text")
        .setSmallIcon(R.drawable.ic_launcher_foreground)
        .build();

// Show the initial notification
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(NOTIFICATION_ID, notification);

// ... later ...

// Build the updated notification
Notification updatedNotification = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setContentTitle("Updated Title")
        .setContentText("Updated Text")
        .setSmallIcon(R.drawable.ic_launcher_foreground)
        .build();

// Show the updated notification
// This will update the existing notification with ID NOTIFICATION_ID
notificationManager.notify(NOTIFICATION_ID, updatedNotification);

取消通知

取消通知:

关键就是 cancel 这个函数,给这个函数一个制定的 NOTIFICATION_ID ,就能够取消相应的通知。

// Build a notification
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setContentTitle("Sample Title")
        .setContentText("Sample Text")
        .setSmallIcon(R.drawable.ic_launcher_foreground)
        .build();

// Show the notification
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(NOTIFICATION_ID, notification);

// ... later ...

// Cancel the notification
notificationManager.cancel(NOTIFICATION_ID);

总结

简单来说,就是,一个通知的创建,到发送,大致可以分为三个部分

  1. 创建一个通知的渠道,在这个里面确定通知的属性,比方说优先级,通知的声音,通知的震动等等。
  2. 创建一个通知的 builder 属性【通过 NotificationCompat 和 Notification 的方式】,比方说,通知的内容,图标,文本等等
  3. 获取一个 notificationManager ,这个通过这个通知管理器,对通知进行发送

需要注意:

NotificationManager 和 NotificationManagerCompat 不一样的部分

NotificationManagerCompat 是一个能够兼容老版本的一个类,来自 androidx,能够自动的识别,老版本的型号,做一些针对的处理。

NotificationManager 就是一个字面意思的通知管理器。

他们获取对象的方式不一样

NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
NotificationManager notificationManager = getSystemService(NotificationManager.class);

Notification 和 NotificationCompat

Notification

但是他们创建对象的方式一样

Notification.Builder builder = new Notification.Builder(context, CHANNEL_ID)
        .setSmallIcon(R.drawable.ic_notification)  // 请替换为你的应用中的图标资源 ID
        .setContentTitle(title)
        .setContentText(message)
        .setPriority(Notification.PRIORITY_DEFAULT)
        .setAutoCancel(true);  // 点击后自动移除通知

一般来说还需在前面加上一个版本的判定才决定,是不是使用通知频道

Notification.Builder builder;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    builder = new Notification.Builder(context, CHANNEL_ID);
} else {
    builder = new Notification.Builder(context);
}

NotificationCompat

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.ic_launcher_foreground)
        .setContentTitle("Sample Notification")
        .setContentText("This is a sample notification")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT);

NotificationCompat.Builder 的属性的设置

Notification.Builder 和 NotificationCompat.Builder 有不同的地方,这里分开介绍

我们知道 NotificationCompat.Builder 有很多的属性,最基础的就是设置一些图标,标题,内容等等

    NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
            .setSmallIcon(R.drawable.ic_launcher_foreground)
            .setContentTitle("Sample Notification")
            .setContentText("This is a sample notification")
            .setPriority(NotificationCompat.PRIORITY_DEFAULT);

但是实际上能够设备的内容还很多

  • setWhen(notification.when):设置通知显示的时间。

  • setSmallIcon(notification.icon, notification.iconLevel):设置通知的小图标和图标级别。

  • setContent(notification.contentView):设置通知的内容视图

  • setTicker(notification.tickerText):设置通知首次到达时在状态栏中显示的文本。【Ticker 本身就是在新闻广播或其他屏幕显示中,"ticker" 可以指的是屏幕底部滚动的一行文本,通常显示最新的新闻、股票价格或其他实时信息】Android5 之后已经被弃用

  • setVibrate(notification.vibrate):设置通知到达时的震动模式。【Vibrate 本身就是震动的意思】

  • setLights(notification.ledARGB, notification.ledOnMS, notification.ledOffMS):设置通知的灯光颜色、亮灯时长和熄灯时长。

  • setOngoing(true)表示该通知是持续性的,用户不能通过滑动来清除它。【ongoing 本身就是事情正在进行当中的意思】

  • setOnlyAlertOnce 是 Android 开发中用于控制通知的声音、振动、提示等是否只在通知首次出现时触发的方法。如果你设置 setOnlyAlertOnce(true),那么无论在同一个通知中收到多少新消息,声音、振动、提示等只会在第一次收到消息时触发。例如,如果在同一个聊天中连续收到了3条消息,那么只有在收到第一条消息时会触发声音、振动、提示等,后面两条消息到来时,即使通知的内容更新了,也不会再次触发声音、振动、提示等。【Alert 本身就是就是警觉警告的意思】

  • setAutoCancel(true) 用于设置通知是否在用户点击它后自动取消。也就是双击之后,是否自动消失,但是需要注意的是,如果在你的设置当中还添加了 setOngoing 的函数没那么这个函数将会失效,并且,如果你直接设置这个函数为 true 也是没有效果的,必须搭配 setContentIntent 一起使用。因为当你点击之后,必须有一个关联的组件(比方说,activityserviceBroadcast,注意没有内容提供者这个组件)也就是说,通知,他会自己退场,新的组件登场

  • setContentIntent(pendingIntent) 当你创建一个通知时,你通常想在用户点击这个通知时执行一些操作,比如打开一个界面(Activity),启动一个服务(Service)或发送一个广播(Broadcast)。

    setContentIntent 方法允许你将一个 PendingIntent 关联到通知。这个 PendingIntent 描述了用户点击通知时要执行的操作。

  • setDeleteIntent(pendingDeleteIntent) 这个其实跟上面的是对应的,也是在 touch 了通知之后做一个操作,上面的是,当我们双击通知的时候,会产生的一些操作,我们这个是,当我们滑动关闭通知之后,我的的一些操作,也就是,删除掉这个通知之后的一些操作。比方说,你一样的可以在我们划掉这个通知之后,打开一个 activity,但是这个不符合用户的预期,所以不建议,一般来说,是开启一个 service 或者是发送一个 广播

  • setDefaults(notification.defaults) 用于设置通知的默认设置

    • Notification.DEFAULT_SOUND: 使用默认的通知声音。

    • Notification.DEFAULT_VIBRATE: 使用默认的震动模式。

    • Notification.DEFAULT_LIGHTS: 使用默认的灯光模式。

    • Notification.DEFAULT_ALL: 使用所有的默认设置(声音、震动、灯光)

    • NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
          .setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE)
  • setContentInfo 这个信息文本通常显示在通知的右侧。 但是不推荐使用,因为有时候有效,有时候没有效果

  • setFullScreenIntent(PendingIntent) 这个 PendingIntent 会在通知首次到达时触发。如果设备当前是锁定状态,这个 PendingIntent 会以全屏的方式显示。

    这个方法通常用于高优先级的通知,比如来电通知或者闹钟通知,这种通知需要用户立即看到并作出响应。如果屏幕是打开的状态,setFullScreenIntent设置的Activity将不会显示。只有当设备是锁定状态时,setFullScreenIntent设置的Activity才会以全屏的方式显示。

    • 注意:从 Android 11 开始,全屏通知的行为发生了变化。如果你的应用目标 API 等级是 30 或者更高,全屏的 Intent 不会启动。取而代之的是,通知会以 "泡泡" 的形式显示,用户可以点击泡泡来打开 Activity。这个泡泡通知在后面做介绍
  • setLargeIcon 加载一个大图,并且是 Bitmap 的数据类型

    • Bitmap largeIcon = BitmapFactory.decodeStream(new URL("https://example.com/icon.png").openStream());
      NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
              .setSmallIcon(R.drawable.ic_small_icon)
              .setLargeIcon(largeIcon)
              .setContentTitle("New Message")
              .setContentText("You have a new message from Jane.");

      在这个例子中,大图标是从一个网络URL加载的

  • setNumberNotificationCompat.Builder类的一个方法,它用于设置通知上显示的数字。

    这个数字通常用于表示未读消息的数量或者其他需要用户注意的数量。

  • setProgressNotification.Builder的一个方法,用于设置通知的进度条。

    这个方法有三个参数:

    1. max:进度条的最大值。
    2. progress:进度条的当前值。
    3. indeterminate:一个布尔值,表示进度条是确定的还是不确定的。【indeterminate 本身就是不确定的,不明确的】
      1. 这个参数什么意思呢?
        1. 如果进度条是确定的,那么进度条会显示具体的进度,比如50%。通常在你知道操作的总进度和当前进度时,你会设置一个确定的进度条。
        2. 如果进度条是不确定的,那么进度条会显示一个循环的动画
        3. 那么如果,那么我后面设置了不确定,前面设置了 max:进度条的最大值。 progress:进度条的当前值。这个时候,就会当前面的设置不存在,会忽略前面的设置
  • setSubText 用于设置通知的子文本。

  • setUsesChronometer用于设置通知上是否显示一个计时器。如果你调用setUsesChronometer(true),通知上将会显示一个计时器,显示的是一个每一秒钟都在变化的,时时刻刻在变化的,秒表时钟【Chronometer 通常指的是一个精确的计时器或计时设备】

比较难以理解的几个函数

setContent

其中 setContent 这个是一个仅存在于 Notification.Builder 的一个方法,并且不推荐使用,他的作用是高度自定义一个通知的形式,他接受 RemoteViews 的参数

RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.custom_notification);
remoteViews.setImageViewResource(R.id.image, R.drawable.notification_icon);
remoteViews.setTextViewText(R.id.title, "Custom notification");
remoteViews.setTextViewText(R.id.text, "This is a custom layout");

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.ic_launcher_foreground)
        .setContent(remoteViews)
        .setPriority(NotificationCompat.PRIORITY_DEFAULT);

NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(NOTIFICATION_ID, builder.build());

逆向当中比较重要的几个函数

setContentIntent

这个从功能就知道,他决定了,你的通知跳转的 activity 或者其他的组件

setDeleteIntent

这个从功能就知道,他决定了,你的通知跳转的 activity 或者其他的组件

setFullScreenIntent

这个从功能就知道,他决定了,你的通知跳转的 activity 或者其他的组件


特殊通知

泡泡通知

在 Android 11(API 等级 30)及以上版本中,Google 引入了一种新的通知类型,叫做“泡泡”通知(Bubble Notification)。泡泡通知是一种特殊的通知,它可以将一个 Activity 以浮动窗口的形式显示在其他应用的上方。

如果你没有用过 android 的原生系统,一直使用的国内的系统,你一定对这个气泡通知比较的陌生 气泡通知API介绍

在这里,你能看见一个气泡通知的演示

action

悬浮通知

flag