IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android Notification状态栏通知 -> 正文阅读

[移动开发]Android Notification状态栏通知

介绍

本文主要实现:

  1. 判断是否开启通知权限;
  2. 发送通知;
  3. 点击通知跳转页面;
  4. 关闭通知;

实现效果

用小米手机(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; //有通知权限
        }
    }

    /**
     * 显示设置开启通知权限的dialog
     */
    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();             //创建AlertDialog对象
        alert.show();                    //显示对话框
    }


    //判断该app是否打开了通知
    /**
     * 可以通过NotificationManagerCompat 中的 areNotificationsEnabled()来判断是否开启通知权限。NotificationManagerCompat 在 android.support.v4.app包中,是API 22.1.0 中加入的。而 areNotificationsEnabled()则是在 API 24.1.0之后加入的。
     * areNotificationsEnabled 只对 API 19 及以上版本有效,低于API 19 会一直返回true
     * */
    @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;

            /* Context.APP_OPS_MANAGER */
            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"; //NotificationChannel的ID
    String channel_name = "notificationChannel的名称";  //NotificationChannel的名称
    String channel_desc = "notificationChannel的描述"; //NotificationChannel的描述
    String notification_title = "notification的标题";
    String notification_text = "notification的内容";
    int notificationId = 10086;

    NotificationManager 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) {
                //除了可以根据ID来取消Notification外,还可以调用cancelAll();关闭该应用产生的所有通知
                notificationManager.cancel(notificationId);  //取消Notification
            }
        });
    }


    /**
     * 创建通知渠道
     */
    private void createNotificationChannel() {
        //Android8.0(API26)以上需要调用下列方法,但低版本由于支持库旧,不支持调用
        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);
            // 设置通知出现时的闪灯(如果 android 设备支持的话)
            channel.enableLights(true);
            channel.setLightColor(Color.RED);
            // 设置通知出现时的震动(如果 android 设备支持的话)
            channel.enableVibration(true);
            channel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
            //设置自定义的提示音
            //注意:通知渠道需要设置NotificationManager.IMPORTANCE_DEFAULT以上级别,才能设置铃声
            channel.setSound(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.biaobiao),Notification.AUDIO_ATTRIBUTES_DEFAULT);
            //获得NotificationManager对象
            notificationManager = (NotificationManager)
                    getSystemService(Context.NOTIFICATION_SERVICE);
            //在 notificationManager 中创建该通知渠道
            notificationManager.createNotificationChannel(channel);
        } else {//Android8.0(API26)以下
            notificationManager = (NotificationManager)
                    getSystemService(Context.NOTIFICATION_SERVICE);
        }
    }

    /**
     * 发送通知
     */
    private void sendNotification() {
        //定义一个PendingIntent点击Notification后启动一个Activity
        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)  //设置PendingIntent
                .build();
        //用于显示通知,第一个参数为id,每个通知的id都必须不同。第二个参数为具体的通知对象
        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通知栏权限是否开启,以及如何跳转到应用程序设置界面】

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-04-15 00:12:54  更:2022-04-15 00:15:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 20:44:48-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码