安卓8.0起对通知图标、桌面图标都有了要求。若不符合要求就会出现奇怪的问题。

一、图标问题

如下是UI给的一组图:

android 使用系统自带图标 安卓自带图标_安卓图标适配


把这组图放到安卓对应的资源目录后跑了一下发现不同手机上表现效果是不同的。

  • google的 pixel2 手机模拟器上(android 8.0)
  • vivo z1 (android 9.0)
  • 红米 note6(android 8.0)

发现问题:

  • google的pixel2 上图标适配有问题
  • 安卓9.0上图标显示有问题

二、图标问题解决

1、显示默认安卓图标的解决方案

先看看安卓的mipmap目录:

android 使用系统自带图标 安卓自带图标_安卓图标适配_02


其他的目录我们都知道了,那么这个v26 是啥呢?

其实Android 8.0或以上系统的手机,都会使用这个目录下的ic_launcher来作为图标。

知道为啥我们9.0手机为啥显示默认图片了吧,即你指定设置了app的图标。

解决方案

  • 方案1直接删除v26文件夹,这样自己指定的就生效(简单粗暴)
  • 方案2适配一套v26的xxx.xml资源(参考下文图标适配方案)
2、图标适配

android 使用系统自带图标 安卓自带图标_android8.0_03

安卓8.0以后google规定了app图标组成

  • 前景foreground,如上图中的白色安卓机器人。
  • 背景background,需要我们自己提供。如上图中的蓝色网格背景。
  • mask,手机厂商提供。如上图中的透明覆盖物即为面具,不同厂商面具可能不同,有圆的,方的等等。

所以我们只需要提供前景背景即可,这里 Android Studio 提供了image Assets,mac 双击shift 搜索即可:

android 使用系统自带图标 安卓自带图标_安卓桌面图标_04

如下图:

  • 红色标记1可为文件命名
  • 红色标记2这里可为对应图层命名(这里为 foreground layer 命名)
  • 红色标记3这里可选择要操作的本地图片

    如上图从桌面选择一张图片,前景就是这张图片,然后设置Background 为白色:

android 使用系统自带图标 安卓自带图标_安卓通知图标_05


点击finish

android 使用系统自带图标 安卓自带图标_安卓桌面图标_06


生成结果

android 使用系统自带图标 安卓自带图标_安卓桌面图标_07

这时我们设置为生成的my_icon就行了

结果:

android 使用系统自带图标 安卓自带图标_android 使用系统自带图标_08

可见“图标适配方案”也能解决默认图标显示问题,因为图标适配方案在v26中也会生成对应的xml

三 、通知栏Small Icon 不适配问题

最近在开发中碰到一个问题,公司领导反馈 国外的同事pixel 6 pro 上通知的small icon 显示有问题:显示为小白块、显示不出来,真是奇怪了?然后让测试同事帮忙在看了遍,手头上的测试机,三星、小米,一加等都没问题。最终自己在模拟器上复现了。

android 使用系统自带图标 安卓自带图标_安卓通知图标_09


如上图:

  • 红色框框框住的为修改后的正常通知icon
  • 蓝色框框框住的为非正常通知icon

原因是啥呢?这个可能Framework的同学们好探究一些,我也是通过一些文章找到的:

setSmallIcon api对图片有要求。google原生的手机通过setSmallIcon()方法设置的图片背景必须是透明的,所有不透明的点最终都会显示为白色。

国内手机基本都是通过底层修改过的,通过setSmallIcon()设置的图片没有任何显示,而且也是彩色的。所以暂时不修改此问题,因为像Pixel等的原生手机毕竟不多。

其实有一个地方可以验证,还记得上面的 “Image Assets” 工具吗?

android 使用系统自带图标 安卓自带图标_android8.0_10


可以看到有一项“Notification Icons” 专门用来处理 通知通标的,我们通过“Clip Art” 随便选中个系统提供的图标看左面预览图发现直接帮我们处理了~

好了想要适配Google 原生手机 就按要求搞个 背景全透明的图片吧。

通知栏Small icon 不生效问题

先写个通知工具类,方便测试~

/**
     * 发送通知
     */
    public static void sendNotification(Context context) {
        NotificationManager mNotificationManager;
        NotificationCompat.Builder mBuilder;
        final String channel_id = "chat";
        // click Notification to open SecActivity page
        Intent intent = new Intent(context, SecActivity.class);
        PendingIntent pi = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
        mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

        //Android 8.0开始要设置通知渠道
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(channel_id,
                    "chat message", NotificationManager.IMPORTANCE_DEFAULT);
            mNotificationManager.createNotificationChannel(channel);
        }

        mBuilder = new NotificationCompat.Builder(context, channel_id)
                .setContentTitle("this is title")
                .setContentText("this is content")
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.drawable.cart) // small icon
                .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher))
                .setContentIntent(pi)
                .setAutoCancel(true);

        mNotificationManager.notify(1, mBuilder.build());
    }

有的同学可能会发现一个神奇的问题:
(1) 通过setSmallIcon icon指定一个自定义icon
(2) 自己手机上进行测试时他竟然不生效,具体表现为通知图标为app icon的那个图案。

  • 测试机型 :Red mi k30 pro
  • 安卓版本: Android 12

奇怪了,国内的手机的bug??? 至少Rea mi k30 pro是这样。应该是国内手机厂商修改底层源码的缘故吧~ 底层实现目前还未探究过。

这个bug代码是啥样的呢?如何复现呢?简单模拟下在红米手机上通知的bug:

.setSmallIcon(R.drawable.cart)

android 使用系统自带图标 安卓自带图标_android8.0_11

发现:

  • 通过通知api setSmallIcon随便指定自定义的图标,只要manifest文件中 android:icon这不更改就永远不生效。通知的small icon永远表现为 android:icon的值。
  • Google原生手机上(Pixel)通过setSmallIcon设置一个bg位全透明的icon 就能正常生效。

end