Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >android学习笔记----解决兼容8.0以上和8.0之前版本通知栏显示、振动、LED呼吸灯闪烁问题(真机验证)

android学习笔记----解决兼容8.0以上和8.0之前版本通知栏显示、振动、LED呼吸灯闪烁问题(真机验证)

作者头像
砖业洋__
发布于 2023-05-06 11:21:48
发布于 2023-05-06 11:21:48
66900
代码可运行
举报
文章被收录于专栏:博客迁移同步博客迁移同步
运行总次数:0
代码可运行

然后开始试验了:

模拟器:

真机(华为荣耀V9,8.0系统),下拉横幅需要手动打开,除非是厂家白名单,比如QQ、微信

我在oppo手机6.0系统测试结果是这样的,需要手动打开设置,点击后会出现这样

然后点击通知管理设置权限,oppo手机默认权限都是关闭的。

设置左上角通知的小图标setSmallIcon()只能使用纯alpha图层的图片进行设置,需要美工实现,具体详解请见这里:

https://blog.csdn.net/guolin_blog/article/details/50945228

activity_main.xml

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?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:onClick="sendChatMsg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="发送聊天消息"/>
    <Button
        android:onClick="sendSubscribeMsg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="发送订阅消息"/>
</LinearLayout>

MainActivity.java

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import android.annotation.TargetApi;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v4.app.NotificationCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;

import static android.provider.Settings.EXTRA_APP_PACKAGE;

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


        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            String channelId = "chat";
            String channelName = "聊天消息";
            int importance = NotificationManager.IMPORTANCE_MAX;
            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);
        channel.enableVibration(true);
        channel.setVibrationPattern(new long[]{0, 100, 100, 100});
        channel.enableLights(true);
        channel.setLightColor(Color.RED);
        NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        notificationManager.createNotificationChannel(channel);
    }


    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(EXTRA_APP_PACKAGE, getPackageName());
                intent.putExtra(Settings.EXTRA_CHANNEL_ID, channel.getId());
                startActivity(intent);
                Toast.makeText(this, "请手动将通知打开", Toast.LENGTH_SHORT).show();
            }
            // Intent intent = new Intent();
            //intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
            /*
            //这种方案适用于 API 26, 即8.0(含8.0)以上可以用
            intent.putExtra(EXTRA_APP_PACKAGE, getPackageName());
            intent.putExtra(EXTRA_CHANNEL_ID, getApplicationInfo().uid);

            //这种方案适用于 API21——25,即 5.0——7.1 之间的版本可以使用
            intent.putExtra("app_package", getPackageName());
            intent.putExtra("app_uid", getApplicationInfo().uid);
            startActivity(intent);*/
            // 小米6 -MIUI9.6-8.0.0系统,是个特例,通知设置界面只能控制"允许使用通知圆点"——然而这个玩意并没有卵用,我想对雷布斯说:I'm not ok!!!
            //  if ("MI 6".equals(Build.MODEL)) {
            //      intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
            //      Uri uri = Uri.fromParts("package", getPackageName(), null);
            //      intent.setData(uri);
            //      // intent.setAction("com.android.settings/.SubSettings");
            //  }
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            if (!NotificationsUtils.isNotificationEnabled(this)) {
                Intent intent = new Intent("android.settings.APPLICATION_DETAILS_SETTINGS");
                /*intent.putExtra(EXTRA_APP_PACKAGE, getPackageName());
                 intent.putExtra("uid", getApplicationInfo().uid);*/
                intent.setData(Uri.fromParts("package",
                        getPackageName(), null));
                startActivity(intent);
                Toast.makeText(this, "请手动将通知打开", Toast.LENGTH_SHORT).show();
            }

        }


        Intent intent = new Intent(this, ChatMessage.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
        Notification notification = new NotificationCompat.Builder(this, "chat")
                .setContentTitle("收到一条聊天消息")
                .setContentText("今天晚上吃点啥?")
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.mipmap.ic_launcher)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(),
                        R.mipmap.ic_launcher_round))
                .setAutoCancel(true)
                // 8.0以前的低版本中,若没有setDefaults,无论多高的优先级,通知都无法弹出横幅
                //.setDefaults(NotificationCompat.DEFAULT_ALL)

                // 这里并非多此一举,channel设置了振动只是为了8.0以上的手机,低版本的振动只能在这里设置
                .setVibrate(new long[]{0, 100, 100, 100})
                .setLights(Color.RED, 1000, 1000)
                .setContentIntent(pendingIntent)
                .build();
        manager.notify(1, notification);
    }


    public void sendSubscribeMsg(View view) {
        Intent intent = new Intent(this, SubscribeMessage.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        Notification notification = new NotificationCompat.Builder(this, "subscribe")
                .setContentTitle("收到一条支付宝消息")
                .setContentText("免费医疗金领取提醒")
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.mipmap.ic_launcher_round)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
                .setAutoCancel(true)
                // 这里并非多此一举,channel设置了振动只是为了8.0以上的手机,低版本的振动只能在这里设置
                .setVibrate(new long[]{0, 100, 100, 100})
                .setLights(Color.RED, 1000, 1000)
                .setContentIntent(pendingIntent)
                .build();
        manager.notify(2, notification);
    }
}

笔记批注:

这里我们在MainActivity中创建了两个通知渠道,首先要确保的是当前手机的系统版本必须是Android 8.0系统或者更高,因为低版本的手机系统并没有通知渠道这个功能,不做系统版本检查的话会在低版本手机上造成崩溃。

这里封装了一个createNotificationChannel()方法,需要注意的是,创建一个通知渠道至少需要渠道ID、渠道名称以及重要等级这三个参数,其中渠道ID可以随便定义,只要保证全局唯一性就可以。渠道名称是给用户看的,需要能够表达清楚这个渠道的用途。重要等级的不同则会决定通知的不同行为,当然这里只是初始状态下的重要等级,用户可以随时手动更改某个渠道的重要等级,App是无法干预的。

关于通知渠道,官方文档说明见这里:https://developer.android.google.cn/about/versions/oreo/features/notification-channels

其中App通知主要可以分为两类,一类是我和别人的聊天消息,这类消息非常重要,因此重要等级设为了IMPORTANCE_HIGH。另一类是公众号的订阅消息,这类消息不是那么重要,因此重要等级设为了IMPORTANCE_DEFAULT。除此之外,重要等级还可以设置为IMPORTANCE_LOW、IMPORTANCE_MIN,分别对应了更低的通知重要程度。

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

通知渠道一旦创建之后就不能再通过代码修改了。只有在将通道提交给NotificationManager.createNotificationChannel(NotificationChannel).方法之前做出的修改才有效,比如是否需要振动、闪光灯、和音效等。如果在提交之前作了修改,请先卸载再重新安装app即可,之前就因为没有重新安装导致始终无法振动。

关于led呼吸灯,在oppo手机上需要手动打开,在华为android8.0系统手机呼吸灯可正常显示,当然这个需要手机支持,有的手机就只有白色的呼吸灯,没有红绿蓝。

在真机上需要手动打开显示横幅的权限,否则设置最大的priority也无效,除非厂家白名单。

这里不用根据api等级手动设置NotificationCompat.Builder参数的个数,8.0以上版本是2个参数,8.0以下是1个参数,在.build()的时候源码里面会自动根据系统的api等级做出相应的判断。如下图:

NotificationsUtils.java(判断通知是否打开,针对8.0以下系统)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import android.annotation.SuppressLint;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class NotificationsUtils {
    private static final String CHECK_OP_NO_THROW = "checkOpNoThrow";
    private static final String OP_POST_NOTIFICATION = "OP_POST_NOTIFICATION";

    @SuppressLint("NewApi")
    public static boolean isNotificationEnabled(Context context) {

        AppOpsManager mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
        ApplicationInfo appInfo = context.getApplicationInfo();
        String pkg = context.getApplicationContext().getPackageName();
        int uid = appInfo.uid;

        Class appOpsClass = null;
        /* Context.APP_OPS_MANAGER */
        try {
            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 (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return false;
    }
}

ChatMessage.java

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ChatMessage extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_chat_message);
    }
}

 activity_chat_message.xml

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?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">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="聊天消息"/>
</LinearLayout>

 SubscribeMessage.java

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class SubscribeMessage extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_subscribe_message);
    }
}

 activity_subscribe_message.xml

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?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">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="订阅消息"/>
</LinearLayout>
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-11-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Android通知栏微技巧,8.0系统中通知栏的适配
之前我们已经讲到了,Android 8.0系统最主要需要进行适配的地方有两处:应用图标和通知栏。在上一篇文章当中,我们学习了Android 8.0系统应用图标的适配,还没有看过这篇文章的朋友可以先去阅读 Android应用图标微技巧,8.0系统中应用图标的适配 。
用户1158055
2019/07/03
3.1K0
Android 8.0无法发送通知栏?通知栏适配通知渠道
  不得不说Andoird的通知栏相比于IOS在使用上有着明显的不足,不仅是体验上的差异,还有大量的非关注通知铺满了通知栏,导致通知栏混乱,杂多。   为什么一个很好的通知栏功能现在却变得这么遭用户讨厌?很大一部分原因都是因为开发者没有节制地使用导致的。每个开发者都只想着尽可能地去宣传自己的App,最后用户的手机就乱得跟鸡窝一样了。但是通知栏又还是有用处的,比如我们收到微信、短信等消息的时候,确实需要通知栏给我们提醒。因此分析下来,通知栏目前最大的问题就是,无法让用户对感兴趣和不感兴趣的消息进行区分。就比如说,我希望淘宝向我推送卖家发货和物流的相关消息,但是我不想收到那些打折促销或者是让我去买衣服的这类消息。那么就目前来说,是没有办法对这些消息做区分的,我要么同意接受所有消息,要么就屏蔽所有消息,这是当前通知栏的痛点。   那么在Android 8.0系统中,Google也是从这个痛点开始下手的。
饮水思源为名
2018/09/06
3.7K0
Android8.0+ 通知适配实战代码
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); //分组(可选) //groupId要唯一
Zachary46
2018/12/06
1K0
Android Notification使用
  在应用的开发中,我们必然会接触到应用通知这个知识,而在通知是随着Android版本进行不断变化,为了能在高版本和低版本中使用,就需要开发者去做适配,也属于查漏补缺。了解之前,先看一个效果图吧。
晨曦_LLW
2022/07/12
2.9K0
Android Notification使用
android之NotificationManager服务
NotificationManager是一个Android系统服务,用于管理和运行所有通知。
李小白是一只喵
2021/02/05
1K0
消息通知Notificatio在8.0上不显示,适配Android8.0
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
黄林晴
2019/08/31
1.2K0
《第一行代码》中遇到的问题
最近刚刚学完郭霖的第一行代码(第二版)这本书,是我选择入门安卓的一本书,看到很多人都推荐这本书,所以就去图书馆借来趁寒假学习下。但是由于技术是不断更新的,而这本书是16年的,虽然也算是市面上比较新的安卓书籍,但是由于技术的更新速度实在是太快,所以楼主学习的时候2020年,已经有点过时了,导致有一些方法和库更新之后有问题,在此记录下来,也希望帮到以后拿这本书来学习的朋友。
wsuo
2020/07/31
1.9K0
Android应用角标适配方法,源码在三星和华为上测试通过
一、应用的角标如下面的红点,提示用户有新的信息更新。角标,英语是badge,也就是“徽章,像章,奖章; 象征,标记”的意思。一般来说,应用的角标是用来标记有多少条提醒(Notification)没读(unread),一旦点击提示进应用阅读了,角标也会消失。
IT工作者
2022/05/20
1.4K0
HooK之hook Notification
第一章:android hook介绍 第二章:hook之替换View.OnClickListener 第三章:HooK之hook Notification
李小白是一只喵
2021/02/05
1.3K0
创建管理通知渠道
创建 和管理 通知渠道 从Android8.0(API26)开始,所有的通知必须分配一个渠道。每一个渠道,你都可以设置渠道中所有通知的视觉和听觉行为。然后,用户能够随意修改这些设置来决定通知的行为。
佛系编码
2018/05/22
9090
【Android 进程保活】提升进程优先级 ( 使用前台 Service 提高应用进程优先级 | 启动相同 id 的第二个前台 Service 关闭通知 )
上一篇博客 【Android 进程保活】提升进程优先级 ( 使用前台 Service 提高应用进程优先级 | 效果展示 | 源码资源 ) 实现了一个前台 Service , 在通知栏 , 存在一个通知 ;
韩曙亮
2023/03/29
2.1K0
【Android 进程保活】提升进程优先级 ( 使用前台 Service 提高应用进程优先级 | 启动相同 id 的第二个前台 Service 关闭通知 )
Android 8.0 简单适配那些事儿
Android 8.0 以发布很长时间了,基于用户设备和市场要求等迟迟没有适配升级;如今适配时遇到一些问题,整理记录一下!官网 对 Android 8.0 新特性以及适配相关的介绍非常清楚,和尚根据官方要求逐步进行适配升级;
阿策小和尚
2019/08/16
1.4K0
Android 8.0 简单适配那些事儿
Android Notification细思极恐的适配
近期项目的迭代版本开发,部门惊喜的申请了一台9.0的机器,是目前部门有史以来第一台8.0以上的机器,满怀喜悦的跑起项目,惊讶地发现Notification的在9.0以上的机器突然不能弹出通知了,惊讶之余发现发通知管理的权限没有开启(就觉得在我的代码怎么会有问题),结果开启了仍然无法接收到通知(打脸了...),马上请教了google大神,发现了毛病
包子388321
2020/06/16
1.4K0
Android通知Notification使用全解析,看这篇就够了
通知是 Android 在您的应用 UI 之外显示的消息,用于向用户提供提醒、来自其他人的通信或来自您的应用的其他及时信息。用户可以点击通知打开您的应用或直接从通知中执行操作。
yechaoa
2022/06/27
6.6K0
Android通知Notification使用全解析,看这篇就够了
客官,聊聊兼容手机角标那点事儿
话说,在某天,正在烦恼某个功能点如何实现更好、更快,老大来了一句,iOS 应用图标有未读提示,这个华为手机怎么没有呢?来,搞一下。
贺biubiu
2019/06/10
1.4K1
【错误记录】前台进程报错 ( Bad notification for startForeground invalid channel for service notification )
Android 8.0 以上不能用空的通知了 , 必须自己创建通知通道 , 创建通知 ;
韩曙亮
2023/03/29
1.8K0
【错误记录】前台进程报错 ( Bad notification for startForeground invalid channel for service notification )
Android6.0到9.0的适配爬坑总结
  大家还记得Android 6.0权限适配的泪水吗?而现在谷歌已经出了Android P的稳定版,而且谷歌粑粑,为了大家能给辛苦熬夜加班,特地的和个大市场合作,要强制推出9.0的适配,而近期在下不才,为了报着多踩坑的心态,做了一下7.0~9.0的适配,脸颊也是老泪两行
用户1269200
2018/12/19
2K0
Android6.0到9.0的适配爬坑总结
创建通知
通知提供了有关应用程序未使用时的事件的简短而及时的信息。这篇文章教你怎么通过Android4.0及以上版本的各种功能去创建一个通知。有关通知怎么在Android上显示,Android 通知
佛系编码
2019/12/11
1.9K0
创建通知
android 实现本地定时推送(兼容)
首先写几点感悟: - 做兼容真的很累很费劲~ - android 8.0 广播部分不再支持动态注册,所以应该用service来实现定时推送功能 - 无论是闹钟还是通知,都得做兼容处理,android 8.0通知必须加channel_id,否则通知无法显示 - 查阅大量资料,发现代码都参差不齐,不过还是有很多值得参考的地方,目前这份代码有很多都是抄字那些博主的文章,然后稍加改动,加以整合而成 - 代码分为三个类,service类、闹钟工具类和通知工具类
陨石坠灭
2018/10/19
3.9K0
【Android 进程保活】提升进程优先级 ( 使用前台 Service 提高应用进程优先级 | 效果展示 | 源码资源 )
上一篇博客 【Android 进程保活】提升进程优先级 ( 1 像素 Activity 提高进程优先级 | taskAffinity 亲和性说明 | 运行效果 | 源码资源 ) 使用了前台 Activity , 提升整个进程的优先级 ;
韩曙亮
2023/03/29
2.8K0
【Android 进程保活】提升进程优先级 ( 使用前台 Service 提高应用进程优先级 | 效果展示 | 源码资源 )
推荐阅读
相关推荐
Android通知栏微技巧,8.0系统中通知栏的适配
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验