为什么要进行通知栏适配?
现在经常是早上一觉醒来拿起手机一看,通知栏上全是各种APP的推送,烦。随着智能手机发展的成熟,通知栏搞得越来越不讨人喜欢了。各个App都希望抢占通知栏的空间,来尽可能地销售自己的产品。
通知栏是Android系统原创的,虽说乔布斯一直认为Android系统是彻底抄袭iOS的一个产品,苹果在iOS 5之后也抄袭了Android的通知栏。
通知栏的设计巧妙,它不占用屏幕空间,只有当用户需要的时候用手指在状态栏上向下滑动,通知栏的内容才会显示出来,在智能手机发展的初期解决了手机屏幕小,内容展示不足的问题。
从Android 8.0系统开始,Google引入了通知渠道这个概念。
什么是通知渠道呢?顾名思义,就是每条通知都要属于一个对应的渠道。每个App自由创建通知渠道,但这些通知渠道的控制权都是掌握在用户手上。用户随便设置通知渠道的重要程度,是否响铃、是否振动、或者是否要关闭这个渠道的通知。
举个例子,我希望立马收到支付宝的收款信息,因为不想错过每笔钱,但是又不想收到支付宝给我推荐的周围美食,因为我没钱去大饭店。这种情况,支付宝就可以创建两种通知渠道,一个收支,一个推荐,而我作为用户对推荐类的通知讨厌,那么我直接把推荐通知渠道关闭,这样不影响我关心的通知,又不会让那些我不关心的通知来打扰我了。
我一定要搞适配吗?
Google这次对于8.0系统通知渠道的态度硬硬的。如果你升级了AppCompat库,所有使用AppCompat库来构建通知的地方全部会进行废弃方法提示,如下所示:
Google也并没做绝,即使方法标为废弃,还是可以凑合用。可是如果你将项目中的targetSdkVersion指定到了26或者更高,Android系统认为APP已经做好了8.0系统的适配工作,当然包括了通知栏的适配。这个时候不使用通知渠道,你App的通知将不弹出。
那么现在开始我们就正式来学习一下如何进行8.0系统中通知栏的适配。
创建通知渠道
首先我们使用Android Studio来新建一个项目,就叫它NoticationChannel
创建好项目,打开app/build.gradle文件检查一下,targetSdkVersion已经指定到了26或者更高,如下:
android {
compileSdkVersion 28
buildToolsVersion "28.0.0"
defaultConfig {
applicationId "com.example.noticationchannel"
minSdkVersion 21
targetSdkVersion 28
versionCode 100
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void sendChatMsg(View view) {
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
String channelId = "chat";
String channelName = "聊天消息";
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(channel);
}
Notification notification = new NotificationCompat.Builder(this, "chat")
.setContentTitle("来了吧,小伙子 聊天消息")
.setContentText("中午吃点啥呢?")
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)
.setAutoCancel(true)
.build();
manager.notify(1, notification);
}
public void sendSubscribeMsg(View view) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
String channelId = "subscribe";
String channelName = "订阅消息";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(channel);
}
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Notification notification = new NotificationCompat.Builder(this, "subscribe")
.setContentTitle("来了吧,小伙子 订阅消息")
.setContentText("房子便宜卖啦,有要买的吗!")
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher_round)
.setAutoCancel(true)
.build();
manager.notify(2, notification);
}
public void cancelChatMsg(View view) {
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.cancel(1);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
manager.deleteNotificationChannel("chat");
}
}
public void cancelSubscribeMsg(View view) {
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.cancel(2);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
manager.deleteNotificationChannel("chat");
}
}
}
下面我们就来让通知显示出来首先修改activity_main.xml中的代码,如下所示:
想象一下我们正在开发类似于微信的APP,其中APP通知主要分为两类,一类是聊天消息,这类消息非常重要,因此重要等级设为了IMPORTANCE_HIGH。另一类公众号订阅消息,这类消息不那么重要,重要等级+我设为了IMPORTANCE_DEFAULT。当然,重要等级还可以设置为IMPORTANCE_LOW、+IMPORTANCE_MIN,分别对应更低的通知重要程度。
代码不长,要确保的是当前手机的系统版本必须是Android 8.0系统或者更高,低版本的手机系统没有通知渠道功能,不做系统版本检查会在低版本手机上造成崩溃。
创建通知渠道很简单,需要注意的是,创建一个通知渠道需要渠道ID、渠道名称以及重要等级这三个参数,其中渠道ID随便写,只要保证全局独一份就可以。渠道名称是给用户看的,要能够表达清楚这个渠道的用途。等级不同决定通知行为不同,这里只是初始状态下的等级,用户随时更改渠道的等级,APP 无法干预。
现在运行一下代码了,运行成功之后,点击发送聊天消息,点击发送订阅消息,状态栏上会有通知小图标,用手指在状态栏上向下滑动,如下图所示:
刚才我们创建两个通知渠道已经显示出来了。由于这两个通知渠道的重要等级不同,通知的行为也是不同的,聊天消息可以发出在屏幕上弹出通知,而订阅消息不会弹出通知。
进入到设置 -> 应用 -> 通知当中,查看NoticationChannel这个APP的通知界面,如下图所示:
当然,用户还可以点击进去对该通知渠道进行任意的修改,比如降低聊天消息的重要等级,甚至是可以完全关闭该渠道的通知。
管理通知渠道
通知渠道一旦创建就不能再通过代码修改了。为此,Android赋予了开发者读取通知渠道配置的权限,如果某个功能必须配置通知渠道才能使用,可以提示用户手动更改通知渠道配置。
概念总是抽象,我们还是通过具体例子来实象。想象我们开发的是一个类似于微信的APP,聊天消息是重要地,如果用户将聊天消息的通知渠道关闭了,所有重要聊天通知全部都丢了,为此我们一定要保证用户打开了聊天消息通知渠道才行。
修改MainActivity中的代码
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 != null && 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();
}
}
......
}
这里我们对sendChatMsg()方法进行了修改,通过getNotificationChannel()方法获取到了NotificationChannel对象,如果为null,没有设置通知渠道,否则就可以读取该通知渠道下的所有配置了。这里我们判断如果通知渠道的importance等于IMPORTANCE_NONE,就说明用户将该渠道的通知给关闭了,这时会跳转到通知的设置界面提醒用户手动打开。
1 当聊天消息的通知渠道关闭后,下次再次发送聊天消息直接跳转到通知设置界面,提醒用户手动将通知打开。
2 除了以上管理通知渠道的方式之外,Android 8.0还赋予了我们删除通知渠道的功能,只需使用如下代码即可删除:
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.deleteNotificationChannel(channelId);
文章中的示例源码点击 https://github.com/githubwwj/NoticationChannel下载