Android -- 通知栏微技巧,8.0系统中通知栏的适配

1、前言

Android 8.0系统最主要需要进行适配的地方有两处:应用图标通知栏
Android 8.0系统应用图标的适配 请看 Android应用图标微技巧,8.0系统中应用图标的适配 。

本篇文章,讲的是 Android 8.0系统的通知栏适配。

其实在8.0系统之前,还有一次通知栏变动比较大的版本,就是5.0系统。关于5.0系统需要对通知栏进行适配的内容,请看 Android – 通知栏微技巧,5.0系统中通知栏的适配。

2、Android 8.0系统的通知栏适配

2.1 为什么要进行通知栏适配?

不得不说,通知栏真是一个让人又爱又恨的东西。

通知栏是Android系统原创的一个功能,虽说乔布斯一直认为Android系统是彻彻底底抄袭iOS的一个产品,但是通知栏确实是Android系统原创的,反而苹果在iOS 5之后也加入了类似的通知栏功能。

通知栏的设计确实非常巧妙,它默认情况下不占用任何空间,只有当用户需要的时候用手指在状态栏上向下滑动,通知栏的内容才会显示出来,这在智能手机发展的初期极大地解决了手机屏幕过小,内容展示区域不足的问题。

可是随着智能手机发展的逐渐成熟,通知栏却变得越来越不讨人喜欢了。各个App都希望能抢占通知栏的空间,来尽可能地宣传和推广自己的产品。现在经常是早上一觉醒来拿起手机一看,通知栏上全是各种APP的推送,不胜其烦。

现在每当我安装一个新的App时,我都会先到设置里面去找一找有没有推送开关,如果有的话我会第一时间把它关掉。而如果一个App经常给我推送垃圾信息却又无法关闭时,我会直接将它的通知总开关给关掉,如果还不是什么重要的App的话,那么我可能就直接将它卸载掉了。

为什么一个很好的通知栏功能现在却变得这么遭用户讨厌?很大一部分原因都是因为开发者没有节制地使用导致的。就好像App保活一样,直到今天还是不断有人问我该如何保活App,试想如何每个人都能保活自己的App,那么最终受害的人是谁?还不是使用Android手机的用户。大家的手机只会越来越卡,最后只想把手机丢掉,变成iPhone用户了。也是因为开发者没节制地使用,Android现在的每个版本都会不断收缩后台权限。

回到通知栏上也是一样,每个开发者都只想着尽可能地去宣传自己的App,最后用户的手机就乱得跟鸡窝一样了。但是通知栏又还是有用处的,比如我们收到微信、短信等消息的时候,确实需要通知栏给我们提醒。因此分析下来,通知栏目前最大的问题就是,无法让用户对感兴趣和不感兴趣的消息进行区分。就比如说,我希望淘宝向我推送卖家发货和物流的相关消息,但是我不想收到那些打折促销或者是让我去买衣服的这类消息。那么就目前来说,是没有办法对这些消息做区分的,我要么同意接受所有消息,要么就屏蔽所有消息,这是当前通知栏的痛点。

那么在Android 8.0系统中,Google也是从这个痛点开始下手的。

2.2 8.0系统的通知栏适配

从Android 8.0系统开始,Google引入了通知渠道这个概念。

什么是通知渠道呢?
顾名思义,就是每条通知都要属于一个对应的渠道。每个App都可以自由地创建当前App拥有哪些通知渠道,但是这些通知渠道的控制权都是掌握在用户手上的。用户可以自由地选择这些通知渠道的重要程度,是否响铃、是否振动、或者是否要关闭这个渠道的通知。

拥有了这些控制权之后,用户就再也不用害怕那些垃圾推送消息的打扰了,因为用户可以自主地选择自己关心哪些通知、不关心哪些通知。举个具体的例子,我希望可以即时收到支付宝的收款信息,因为我不想错过任何一笔收益,但是我又不想收到支付宝给我推荐的周围美食,因为我没钱只吃得起公司食堂。这种情况,支付宝就可以创建两种通知渠道,一个收支,一个推荐,而我作为用户对推荐类的通知不感兴趣,那么我就可以直接将推荐通知渠道关闭,这样既不影响我关心的通知,又不会让那些我不关心的通知来打扰我了。

对于每个App来说,通知渠道的划分是非常需要仔细考究的,因为通知渠道一旦创建之后就不能再修改了,因此开发者需要仔细分析自己的App一共有哪些类型的通知,然后再去创建相应的通知渠道。这里我们来参考一下Twitter的通知渠道划分:
Android -- 通知栏微技巧,8.0系统中通知栏的适配_第1张图片
可以看到,Twitter就是根据自己的通知类型,对通知渠道进行了非常详细的划分,这样用户的自主选择性就比较高了,也就大大降低了用户不堪其垃圾通知的骚扰而将App卸载的概率。

一定要适配吗?

Google这次对于8.0系统通知渠道的推广态度还是比较强硬的。
首先,如果你升级了appcompat库,那么所有使用appcompat库来构建通知的地方全部都会进行废弃方法提示,如下所示:
在这里插入图片描述
上图告诉我们,此方法已废弃,需要使用带有通知渠道的方法才行。

当然,Google也并没有完全做绝,即使方法标为了废弃,但还是可以正常使用的。可是如果你将项目中的targetSdkVersion指定到了26或者更高,那么Android系统就会认为你的App已经做好了8.0系统的适配工作,当然包括了通知栏的适配。这个时候如果还不使用通知渠道的话,那么你的App的通知将完全无法弹出。因此这里给大家的建议就是,一定要适配。

创建通知渠道

首先我们使用Android Studio来新建一个项目,就叫它 NotificationTest 吧。

创建好项目之后,打开 app/build.gradle 文件检查一下,确保 targetSdkVersion 已经指定到了26或者更高,如下所示:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 26
    defaultConfig {
        applicationId "com.example.notificationtest"
        minSdkVersion 15
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
}

可以看到,这里我在创建新项目的时候默认 targetSdkVersion 就是26,如果你是低于26的话,说明你的 Android SDK 有些老了,最好还是更新一下。当然如果你懒得更新也没关系,手动把它改成26就可以了。

接下来修改MainActivity中的代码,如下所示:

public class MainActivity extends AppCompatActivity {
  
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //8.0 Notification适配,SDK>=26
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            //渠道ID
            String channelId = "chat";
            //渠道名称
            String channelName = "聊天消息";
            //等级
            int importance = NotificationManager.IMPORTANCE_HIGH;
            createNotificationChannel(channelId, channelName, importance);

            channelId = "subscribe";
            channelName = "订阅消息";
            importance = NotificationManager.IMPORTANCE_DEFAULT;
            createNotificationChannel(channelId, channelName, importance);
        }
    }

    @TargetApi(Build.VERSION_CODES.O)
    private void createNotificationChannel(String channelId, String channelName, int importance) {
        NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);
        NotificationManager notificationManager = (NotificationManager) getSystemService(
                NOTIFICATION_SERVICE);
        notificationManager.createNotificationChannel(channel);
    }
}

这里在 MainActivity 中创建了两个通知渠道,并做了系统版本检测,因为系统版本必须是Android 8.0系统或者更高以上才具有通知渠道的功能,而低版本的手机系统并没有通知渠道这个功能,不做系统版本检查的话会在低版本手机上造成崩溃。

createNotificationChannel() 方法为创建一个通知渠道,创建一个渠道必须要有的元素:

  • 渠道ID:随便定义,只要保证全局唯一性
  • 渠道名称:给用户看的,需要能够表达清楚这个渠道的用途
  • 重要等级:决定通知的行为。当然这里只是初始状态下的重要等级,用户可以随时手动更改某个渠道的重要等级,App是无法干预的

上述代码模拟了这样一个场景。想象一下我们正在开发一个类似于微信的App,其中App通知主要可以分为两类,一类是我和别人的聊天消息,这类消息非常重要,因此重要等级我设为了IMPORTANCE_HIGH。另一类是公众号的订阅消息,这类消息不是那么重要,因此重要等级我设为了IMPORTANCE_DEFAULT。除此之外,重要等级还可以设置为IMPORTANCE_LOW、IMPORTANCE_MIN,分别对应了更低的通知重要程度。

现在就可以运行一下代码了,运行成功之后我们关闭App,进入到设置 -> 应用 -> 通知当中,查看NotificationTest这个App的通知界面,如下图所示:
Android -- 通知栏微技巧,8.0系统中通知栏的适配_第2张图片
刚才我们创建的两个通知渠道这里已经显示出来了。可以看到,由于这两个通知渠道的重要等级不同,通知的行为也是不同的,聊天消息可以发出提示音并在屏幕上弹出通知,而订阅消息只能发出提示音。

当然,用户还可以点击进去对该通知渠道进行任意的修改,比如降低聊天消息的重要等级,甚至是可以完全关闭该渠道的通知。

至于创建通知渠道 createNotificationChannel() 的这部分代码,你可以写在MainActivity中,也可以写在Application中,实际上可以写在程序的任何位置,只需要保证在通知弹出之前调用就可以了。并且创建通知渠道的代码只在第一次执行的时候才会创建,以后每次执行创建代码系统会检测到该通知渠道已经存在了,因此不会重复创建,也并不会影响任何效率。

让通知显示出来

首先修改activity_main.xml中的代码,如下所示:




    

这里我们在布局文件中加入了两个按钮,很显然,一个是用于触发聊天消息渠道通知的,一个是用于触发订阅消息渠道通知的。

修改MainActivity中的代码,如下所示:

public class MainActivity extends AppCompatActivity {

    ...

    public void sendChatMsg(View view) {
        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        Notification notification = new NotificationCompat.Builder(this, "chat")
                .setContentTitle("收到一条聊天消息")
                .setContentText("今天中午吃什么?")
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.drawable.icon)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.icon))
                .setAutoCancel(true)
                .build();
        manager.notify(1, notification);
    }

    public void sendSubscribeMsg(View view) {
        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        Notification notification = new NotificationCompat.Builder(this, "subscribe")
                .setContentTitle("收到一条订阅消息")
                .setContentText("地铁沿线30万商铺抢购中!")
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.drawable.icon)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.icon))
                .setAutoCancel(true)
                .build();
        manager.notify(2, notification);
    }
}

触发通知的代码和之前版本基本是没有任何区别的,只是在构建通知对象的时候,需要多传入一个通知渠道ID,表示这条通知是属于哪个渠道的

现在重新运行一下代码,并点击发送聊天消息按钮,效果如下图所示:
Android -- 通知栏微技巧,8.0系统中通知栏的适配_第3张图片
由于这是一条 重要等级高( NotificationManager.IMPORTANCE_HIGH )的通知,因此会使用这种屏幕弹窗的方式来通知用户有消息到来。

然后下拉展开通知栏,这里也能查看到通知的详细信息:
Android -- 通知栏微技巧,8.0系统中通知栏的适配_第4张图片
用户可以通过快速向左或者向右滑动来关闭这条通知。

接下来点击发送订阅消息按钮,你会发现现在屏幕上不会弹出一条通知提醒了,只会在状态栏上显示一个小小的通知图标:
在这里插入图片描述
因为订阅消息通知的重要等级是默认级别( NotificationManager.IMPORTANCE_DEFAULT ),这就是默认级别通知的展示形式。

不过上面演示的都是通知栏的传统功能,接下来我们看一看Android 8.0系统中通知栏特有的功能。

刚才提到了,快速向左或者向右滑动可以关闭一条通知,但如果你缓慢地向左或者向右滑动,就会看到这样两个按钮:
Android -- 通知栏微技巧,8.0系统中通知栏的适配_第5张图片
其中,左边那个时钟图标的按钮可以让通知延迟显示。比方说这是一条比较重要的通知,但是我暂时没时间看,也不想让它一直显示在状态栏里打扰我,我就可以让它延迟一段后时间再显示,这样我就暂时能够先将精力放在专注的事情上,等过会有时间了这条通知会再次显示出来,我不会错过任何信息。如下所示:
Android -- 通知栏微技巧,8.0系统中通知栏的适配_第6张图片
而右边那个设置图标的按钮就可以用来对通知渠道进行屏蔽和配置了,用户对每一个App的每一个通知渠道都有绝对的控制权,可以根据自身的喜好来进行配置和修改。如下所示:
Android -- 通知栏微技巧,8.0系统中通知栏的适配_第7张图片
比如说我觉得订阅消息老是向我推荐广告,实在是太烦了,我就可以将订阅消息的通知渠道关闭掉。这样我以后就不会再收到这个通知渠道下的任何消息,而聊天消息却不会受到影响,这就是8.0系统通知渠道最大的特色。

另外,点击上图中的所有类别就可以进入到当前应用程序通知的完整设置界面。

2.2 管理通知渠道

在前面的内容中我们已经了解到,通知渠道一旦创建之后就不能再通过代码修改了。既然不能修改的话那还怎么管理呢?
为此,Android赋予了开发者读取通知渠道配置的权限,如果我们的某个功能是必须按照指定要求来配置通知渠道才能使用的,那么就可以提示用户去手动更改通知渠道配置。

只讲概念总是不容易理解,我们还是通过具体的例子来学习一下。想一想我们开发的是一个类似于微信的App,聊天消息是至关重要的,如果用户不小心将聊天消息的通知渠道给关闭了,那岂不是所有重要的信息全部都丢了?为此我们一定要保证用户打开了聊天消息的通知渠道才行。

修改MainActivity中的代码,如下所示:

public class MainActivity extends AppCompatActivity {

    ...

    public void sendChatMsg(View view) {
        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = manager.getNotificationChannel("chat");
            if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
                Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
                intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());
                intent.putExtra(Settings.EXTRA_CHANNEL_ID, channel.getId());
                startActivity(intent);
                Toast.makeText(this, "请手动将通知打开", Toast.LENGTH_SHORT).show();
            }
        }

        Notification notification = new NotificationCompat.Builder(this, "chat")
                ...
                .build();
        manager.notify(1, notification);
    }

    ...

}

这里我们对 sendChatMsg() 方法进行了修改,通过 getNotificationChannel() 方法获取到了 NotificationChannel 对象,然后就可以读取该通知渠道下的所有配置了。这里我们判断如果通知渠道的 importance 等于 IMPORTANCE_NONE,就说明用户将该渠道的通知给关闭了,这时会跳转到通知的设置界面提醒用户手动打开。

现在重新运行一下程序,效果如下图所示:
在这里插入图片描述
可以看到,当我们将聊天消息的通知渠道关闭后,下次再次发送聊天消息将会直接跳转到通知设置界面,提醒用户手动将通知打开。

删除通知渠道

除了以上管理通知渠道的方式之外,Android 8.0还赋予了我们删除通知渠道的功能,只需使用如下代码即可删除:

NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.deleteNotificationChannel(channelId);

但是这个功能非常不建议大家使用。因为Google为了防止应用程序随意地创建垃圾通知渠道,会在通知设置界面显示所有被删除的通知渠道数量,如下图所示:
Android -- 通知栏微技巧,8.0系统中通知栏的适配_第8张图片
这样是非常不美观的,所以对于开发者来说最好的做法就是仔细规划好通知渠道,而不要轻易地使用删除功能。

2.3 实现通知栏显示多个notification

问题一:

上面的代码,使用 manager.notify(1, notification) 设置通知栏,多推送几条数据后,会发现 通知栏只显示一条通知,后一条会顶掉前一条,最后只显示一条最新的 notification。

这是因为我们把 manager.notify(int id, Notification notification) 里的 id 设置成了一个固定值,为1;所以最新的 notify 会覆盖之前的 notify。

要想 notifcation 显示多条,只需设置 NotificationManager.notify( id, notify) 中的 id 不一样。代码如下:

int notifyId = (int) System.currentTimeMillis();
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Notification notification = new NotificationCompat.Builder(this, "chat")
 ...
.build();

 manager.notify(notifyId, notification);

这里使用的是时间戳定义 notifyId,也可以使用其他方法定义 notifyId,只要保持每个 notification 的 notifyId 不一样即可。

问题二:

点击 notification 进入到 activity,使用到 pendingIntent 类方法:

PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

当通知栏显示多条数据时,点击通知栏数据,如果弹窗的话,显示的总是最新的那条数据信息 。这是因为我们把 PendingIntent.getActivity() 的第二个参数推送 id 总是设置为1,实际上是通过该参数来区别不同的 Intent 的,如果 id 相同,就会覆盖掉之前的 Intent 了。

这里给 PendingIntent.getActivity() 的第二个参数推送 id 设置不同的值,以对应不同的推送信息。代码如下:

int notifyId = (int) System.currentTimeMillis();
PendingIntent pendingIntent = PendingIntent.getActivity(context, notifyId, intent,
                PendingIntent.FLAG_UPDATE_CURRENT);

3、显示未读角标

前面我们提到过,苹果是从iOS 5开始才引入了通知栏功能,那么在iOS 5之前,iPhone都是怎么进行消息通知的呢?
使用的就是未读角标功能,效果如下所示:
在这里插入图片描述
实际上Android系统之前是从未提供过这种类似于iOS的角标功能的,但是由于很多国产手机厂商都喜欢跟风iOS,因此各种国产手机ROM都纷纷推出了自己的角标功能。

可是国产手机厂商虽然可以订制ROM,但是却没有制定API的能力,因此长期以来都没有一个标准的API来实现角标功能,很多都是要通过向系统发送广播来实现的,而各个手机厂商的广播标准又不一致,经常导致代码变得极其混杂。

值得高兴的是,从8.0系统开始,Google制定了Android系统上的角标规范,也提供了标准的API,长期让开发者头疼的这个问题现在终于可以得到解决了。

那么下面我们就来学习一下如何在 Android 系统上实现未读角标的效果。

修改MainActivity中的代码,如下所示:

public class MainActivity extends AppCompatActivity {

    ...

    @TargetApi(Build.VERSION_CODES.O)
    private void createNotificationChannel(String channelId, String channelName, int importance) {
        NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);
        channel.setShowBadge(true);
        NotificationManager notificationManager = (NotificationManager) getSystemService(
                NOTIFICATION_SERVICE);
        notificationManager.createNotificationChannel(channel);
    }

    public void sendSubscribeMsg(View view) {
        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        Notification notification = new NotificationCompat.Builder(this, "subscribe")
                ...
                .setNumber(2)
                .build();
        manager.notify(2, notification);
    }
}

这里我们主要修改了两个地方:
1、在创建通知渠道的时候,调用了 NotificationChannel 的 setShowBadge(true) 方法,表示允许这个渠道下的通知显示角标。
2、在创建通知的时候,调用了 setNumber() 方法,并传入未读消息的数量。

现在重新运行一下程序,并点击发送订阅消息按钮,然后在 Launcher 中找到 NotificationTest 这个应用程序,如下图所示:
Android -- 通知栏微技巧,8.0系统中通知栏的适配_第9张图片
可以看到,在图标的右上角有个绿色的角标,说明我们编写的角标功能已经生效了。

需要注意的是,即使我们不调用 setShowBadge(true) 方法,Android 系统默认也是会显示角标的,但是如果你想禁用角标功能,那么记得一定要调用 setShowBadge(false) 方法。

但是未读数量怎么没有显示出来呢?这个功能还需要我们对着图标进行长按才行,效果如下图所示:
Android -- 通知栏微技巧,8.0系统中通知栏的适配_第10张图片
可能有些朋友习惯了iOS上的那种未读角标,觉得Android上这种还要长按的方式很麻烦。这个没有办法,因为这毕竟是Android原生系统,Google没有办法像国内手机厂商那样可以肆无忌惮地模仿iOS,要不然可能会吃官司的。但是我相信国内手机厂商肯定会将这部分功能进行定制,风格应该会类似于iOS。不过这都不重要,对于我们开发者来说,最好的福音就是有了统一的API标准,不管国内手机厂商以后怎么定制ROM,都会按照这个API的标准来定制,我们只需要使用这个API来进行编程就可以了。

3、总结

综合以上内容,封装了一个Notification工具类:

public class NotificationUtil {
    public static void showNotification(Context context, String channelID, String title, String content){
        int notifyId = (int) System.currentTimeMillis();
        NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

        //8.0 Notification适配,SDK>=26
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            //渠道ID
            String channelId = "chat";
            //渠道名称
            String channelName = "聊天消息";
            //等级
            int importance = NotificationManager.IMPORTANCE_HIGH;
//            int importance = NotificationManager.IMPORTANCE_MAX;
            createNotificationChannel(context, manager, channelId, channelName, importance);

            channelId = "subscribe";
            channelName = "订阅消息";
            importance = NotificationManager.IMPORTANCE_DEFAULT;
            createNotificationChannel(context, manager, channelId, channelName, importance);

            openNotificationChannel(context, manager, channelID);
        }

        NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channelID);
        Notification notification = builder.setContentTitle(title)
                .setContentText(content)
                //通知首次出现在通知栏,带上升动画效果的
                //在 api 21 后不再显示,仅用于辅助服务
                .setTicker("通知来啦")
                //通知产生的时间,会在通知信息里显示,一般是系统获取到的时间
                .setWhen(System.currentTimeMillis())
                //设置通知小ICON,适配6.0右下角小图标
                .setSmallIcon(R.mipmap.ic_smile)
                //适配6.0右下角小图标背景颜色
                .setColor(Color.parseColor("#26A69A"))
                .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher))
                .setDefaults(Notification.DEFAULT_ALL)
                .setContentIntent(getDefalutIntent(context, content, notifyId))
                //通知栏点击后取消
                .setAutoCancel(true)
                //设置该通知优先级
                .setPriority(Notification.PRIORITY_DEFAULT)
                .setOngoing(false)
                .setNumber(2)
                .build();
//        manager.notify(1, notification);
        manager.notify(notifyId, notification);
    }

    private static PendingIntent getDefalutIntent(Context context, String content, int notifyId){
        Intent intent = new Intent(context, IndexActivity.class);
        intent.putExtra("data", content);
        PendingIntent pendingIntent = PendingIntent.getActivity(context, notifyId, intent,
                PendingIntent.FLAG_UPDATE_CURRENT);
        return pendingIntent;
    }

    /**
     * 创建通知渠道
     * 创建通知渠道的代码只在第一次执行的时候才会创建,以后每次执行创建代码系统会检测到该通知渠道已经存在了,因此不会重复创建,也并不会影响任何效率
     * 创建一个通知渠道至少需要渠道ID、渠道名称以及重要等级这三个参数
     * @param context  上下文
     * @param channelId  渠道ID  随便定义,确保全局唯一性
     * @param channelName  渠道名称  给用户看的,需要能够表达清楚这个渠道的用途
     * @param importance 等级
     */
    @RequiresApi(api = Build.VERSION_CODES.O)
    private static void createNotificationChannel(Context context, NotificationManager manager,
                                                  String channelId, String channelName, int importance){
        NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);
        //设置显示桌面角标
        channel.setShowBadge(true);
//        NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        manager.createNotificationChannel(channel);
    }

    /**
     * 管理通知渠道
     * 如果用户不小心将聊天消息的通知渠道给关闭了,那岂不是所有重要的信息全部都丢了?为此我们一定要保证用户打开了聊天消息的通知渠道才行
     * @param context 上下文
     * @param manager NotificationManager
     * @param channelId 渠道ID
     */
    @RequiresApi(api = Build.VERSION_CODES.O)
    private static void openNotificationChannel(Context context, NotificationManager manager, String channelId){
        NotificationChannel channel = manager.getNotificationChannel(channelId);
        if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE){
            Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
            intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName());
            intent.putExtra(Settings.EXTRA_CHANNEL_ID, channel.getId());
            context.startActivity(intent);
            Toast.makeText(context, "请手动将通知打开", Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * 删除通知渠道
     * 不建议使用,因为Google为了防止应用程序随意地创建垃圾通知渠道,会在通知设置界面显示所有被删除的通知渠道数量
     * @param context  上下文
     * @param channelId 渠道ID
     */
    @RequiresApi(api = Build.VERSION_CODES.O)
    private static void deleteNotificationChannel(Context context, String channelId){
        NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        manager.deleteNotificationChannel(channelId);
    }
}

调用:

public class MainActivity extends AppCompatActivity {

    ...

    public void sendChatMsg(View view) {
        NotificationUtil.showNotification(this, "chat", "聊天消息", "今天中午吃什么?");
    }

    public void sendSubscribeMsg(View view) {
        NotificationUtil.showNotification(this, "subscribe", "订阅消息", "地铁沿线30万商铺抢购中!");
    }
}

你可能感兴趣的:(Android)