介绍
本文主要实现:
- 判断是否开启通知权限;
- 发送通知;
- 点击通知跳转页面;
- 关闭通知;
实现效果
用小米手机(Android12)进行测试;
点击发送通知按钮,判断是否开启通知权限
|
开启相关通知权限,如悬浮通知权限等
|
悬浮通知和通知栏中都显示了通知的信息
|
点击悬浮通知或通知栏中的通知,跳转到了首页
|
底部的通知类别中也显示了配置的通知渠道的信息
|
通知渠道中可以统一的管理响应的通知
|
概念
NotificationManager:是状态栏通知的管理类,负责发通知、清除通知等操作。 NotificationChannel: Android O 引入了 通知渠道(Notification Channels),以提供统一的系统来帮助用户管理通知,如果是针对 android O 为目标平台时,必须实现一个或者多个通知渠道,以向用户显示通知。比如聊天软件,为每个聊天组设置一个通知渠道,指定特定声音、灯光等配置。 NotificationChannelGroup:对通知渠道进行分组,但是本文没有实现 。 Notification:通知信息类,它里面对应了通知栏的各个属性。 PendingIntent:一种特殊的 Intent ,字面意思可以解释为延迟的 Intent ,用于在某个事件结束后执行特定的 Action 。如:带 Action 的通知,当用户点击通知时,才会执行。
代码
布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/btn_sendNotification"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发送通知" />
<Button
android:id="@+id/btn_cancelNotification"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="取消通知" />
</LinearLayout>
NotificationSetUtil 文件判断是否开启消息通知,没有开启的话跳转到手机系统设置界面; 一般情况下,Api 19 以前是没有通知管理的,默认都是开启,不用管。 Api 19 – 24 虽加入了通知管理功能,但没有开放检测是否开启了通知的接口,开发者只能用反射来获取权限值。 Api 24 以上,NotificationManager 提供了 areNotificationsEnabled()方法检测通知权限。
public class NotificationSetUtil {
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public static boolean isOpenNotificationSetting(Context context) {
if (!isNotificationEnabled(context)) {
String message = "通知权限未开启,需要开启权限!";
showDialog(context,message);
return false;
} else {
return true;
}
}
private static void showDialog(Context context,String message){
AlertDialog.Builder builder = new AlertDialog.Builder(context);
AlertDialog alert = builder.setIcon(R.mipmap.ic_dog)
.setTitle("系统提示:")
.setMessage(message)
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(context, "你点击了取消按钮~", Toast.LENGTH_SHORT).show();
}
})
.setPositiveButton("去设置", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(context, "你点击了确定按钮~", Toast.LENGTH_SHORT).show();
gotoSet(context);
}
}).create();
alert.show();
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public static boolean isNotificationEnabled(Context context) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
return NotificationManagerCompat.from(context).areNotificationsEnabled();
}else if (Build.VERSION.SDK_INT >= 19) {
String CHECK_OP_NO_THROW = "checkOpNoThrow";
String OP_POST_NOTIFICATION = "OP_POST_NOTIFICATION";
AppOpsManager mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
ApplicationInfo appInfo = context.getApplicationInfo();
String pkg = context.getApplicationContext().getPackageName();
int uid = appInfo.uid;
try {
Class<?> appOpsClass = Class.forName(AppOpsManager.class.getName());
Method checkOpNoThrowMethod = appOpsClass.getMethod(CHECK_OP_NO_THROW, Integer.TYPE, Integer.TYPE,
String.class);
Field opPostNotificationValue = appOpsClass.getDeclaredField(OP_POST_NOTIFICATION);
int value = (Integer) opPostNotificationValue.get(Integer.class);
return ((Integer) checkOpNoThrowMethod.invoke(mAppOps, value, uid, pkg) == AppOpsManager.MODE_ALLOWED);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}else {
return true;
}
}
}
activity文件
public class NotificationActivity extends AppCompatActivity {
Button btn_sendNotification;
Button btn_cancelNotification;
String channel_id = "notificationChannelId";
String channel_name = "notificationChannel的名称";
String channel_desc = "notificationChannel的描述";
String notification_title = "notification的标题";
String notification_text = "notification的内容";
int notificationId = 10086;
NotificationManager notificationManager;
private Context context;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.notification_layout);
context = this;
btn_sendNotification = findViewById(R.id.btn_sendNotification);
btn_cancelNotification = findViewById(R.id.btn_cancelNotification);
createNotificationChannel();
btn_sendNotification.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (NotificationSetUtil.isOpenNotificationSetting(context)){
Toast.makeText(context, "已开启通知权限", Toast.LENGTH_SHORT).show();
sendNotification();
}
}
});
btn_cancelNotification.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
notificationManager.cancel(notificationId);
}
});
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel channel = new NotificationChannel(channel_id, channel_name, importance);
channel.setDescription(channel_desc);
channel.setSound(null, null);
channel.enableLights(true);
channel.setLightColor(Color.RED);
channel.enableVibration(true);
channel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
channel.setSound(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.biaobiao),Notification.AUDIO_ATTRIBUTES_DEFAULT);
notificationManager = (NotificationManager)
getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(channel);
} else {
notificationManager = (NotificationManager)
getSystemService(Context.NOTIFICATION_SERVICE);
}
}
private void sendNotification() {
Intent it = new Intent(this, MainActivity.class);
PendingIntent pit = PendingIntent.getActivity(this, 0, it, PendingIntent.FLAG_IMMUTABLE);
Notification notification = new NotificationCompat.Builder(this, channel_id)
.setContentTitle(notification_title)
.setContentText(notification_text)
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_dog))
.setDefaults(Notification.DEFAULT_LIGHTS | Notification.DEFAULT_VIBRATE)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setAutoCancel(true)
.setContentIntent(pit)
.build();
notificationManager.notify(notificationId, notification);
Toast.makeText(context, "发送通知成功!", Toast.LENGTH_SHORT).show();
}
}
遇到的问题
- PendingIntent遇到了报错,并根据提示使用了FLAG_IMMUTABLE;
PendingIntent pit = PendingIntent.getActivity(this, 0, it, PendingIntent.FLAG_IMMUTABLE);
java.lang.IllegalArgumentException: com.example.helloworld: Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent. Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if some functionality depends on the PendingIntent being mutable, e.g. if it needs to be used with inline replies or bubbles.
本文参考
菜鸟教程:Notification(状态栏通知)详解 Android Notification 详解 如何自定义Android推送提示音,让你的应用与众不同 Android O(8.0) Notification解决方案 NotificationSetUtilDemo【判断APP通知栏权限是否开启,以及如何跳转到应用程序设置界面】
|