Android 8.0 Oreo 形为变更之 Notification Channels

最近(2018年11月15日)在上传App升级包至Google Play时,遇到了如下问题:

Android 8.0 Oreo 形为变更之 Notification Channels_第1张图片

即:当前App的Target API Level 为25(Android 7.1.1 Nougat),要求将App的Target API Level提升到26(Android 8.0 Oreo)或以上。

查阅资料发现,Google开发者在持续提高 Android 应用的安全性与性能一文中提到:

为了提升 App 安全性和性能,确保每个用户都能够获取最佳体验,探索和安装自己喜欢的 App 和游戏,Google对Android 开发者提出了一些变更。从 2018 年下半年开始,Google Play 管理中心将要求 App 设定target API Level为近期版本:

  • 2018 年 8 月:新 App 需要将 target API 等级设定为 26(Android 8.0)或者更高

  • 2018 年 11 月,现有 App 的更新包需要将 target API 等级设定为 26 或者更高

  • 2019 年之后:每年 targetSdkVersion 会提出新的要求。Android 新版本系统发布一年内,App 的开发和更新都需要将 API 调整到相应或者更高等级。

现有但不再更新的 App 并不受影响。开发者可以自行选择是否使用 minSdkVersion,依旧可以进行基于旧版本 Android 系统的 App 开发。

 

  • 问题

为了能够提交Google Play ,只得将App Target Level提升至26。然后打包、测试、提交市场。测试过程中发现无法接收到Push推送,并且是在Android8.0及以上的设备上无法接收到push,抓取到如下log:

11-15 19:01:05.794  1603  3283 E NotificationService: No Channel found for pkg=com.xxxxxxx.xxxxxx, channelId=null, id=1627843789, tag=null, opPkg=com.xxxxxxx.xxxxxx, callingUid=10719, userId=0, incomingUserId=0, notificationUid=10719, notification=Notification(channel=null pri=0 contentView=null vibrate=default sound=default defaults=0xffffffff flags=0x11 color=0x00000000 category=msg groupKey=com.xxxxxxxx.xxxxxx.notifygrp vis=PUBLIC)

查看创建Notification的代码,如下(Demo):

private void onLaunchNotificationBtnClick() {
        String textTitle = "This is Title";
        String textContent = "This is Content";
        
        //创建Notification
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_launcher_foreground)
                .setContentTitle(textTitle)
                .setContentText(textContent)
                .setPriority(NotificationCompat.PRIORITY_DEFAULT);

        //Launch Notification
        NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(getApplicationContext());
        notificationManagerCompat.notify(NOTIFICATION_ID, builder.build());
    }

Log 如下:

11-17 16:06:51.670 13096-13096/com.example.cxc.fullscreendemo E/NotificationManager: notifyAsUser: tag=null, id=888, user=UserHandle{0}
11-17 16:06:51.678 1272-1875/? E/NotificationService: No Channel found for pkg=com.example.cxc.fullscreendemo, channelId=null, id=888, tag=null, opPkg=com.example.cxc.fullscreendemo, callingUid=10487, userId=0, incomingUserId=0, notificationUid=10487, notification=Notification(channel=null pri=0 contentView=null vibrate=null sound=null defaults=0x0 flags=0x0 color=0x00000000 vis=PRIVATE)

关于Notification的介绍与使用可以参考: Notifications Overview

  • 定位

参考 Android Developers https://developer.android.com/guide/topics/ui/notifiers/notifications
Starting in Android 8.0 (API level 26), all notifications must be assigned to a channel or it will not appear. By categorizing notifications into channels, users can disable specific notification channels for your app (instead of disabling all your notifications), and users can control the visual and auditory options for each channel—all from the Android system settings (figure 11). Users can also long-press a notification to change behaviors for the associated channel.

即:从Android 8.0 (API level 26)开始,所有的notification必须关联一个channel,否则将不会显示。通过将Notification分到各个不同的Channel中,用户可以禁掉App某个Channel中的通知(而不是禁止App的所有Notification),并且用户可以在系统设置中控制各个Channel通知的形式,如是否有声音。

关于Notification Channel的介绍及深入理解可以参考:Exploring Android O: Notification Channels

  • 解决

先创建一个Notification Channel,然后将通知关联到该Channel。

package com.example.cxc.fullscreendemo.notification;

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Build;

public class NotificationUtils {
    private static final String CHANEL_ID = "com.example.cxc.fullscreendeme.channelId";
    private static final String CHANEL_DESCRIPTION = "Channel描述";
    private static final String CHANEL_NAME = "Channel名称";


    public static String createNotificationChannel(Context context) {

        // NotificationChannels are required for Notifications on O (API 26) and above.
        if (context != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

            // Initializes NotificationChannel.
            NotificationChannel notificationChannel =
                    new NotificationChannel(CHANEL_ID,
                            CHANEL_NAME,
                            NotificationManager.IMPORTANCE_DEFAULT);
            notificationChannel.setDescription(CHANEL_DESCRIPTION);

            // Adds NotificationChannel to system. Attempting to create an existing notification
            // channel with its original values performs no operation, so it's safe to perform the
            // below sequence.
            NotificationManager notificationManager =
                    (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
            notificationManager.createNotificationChannel(notificationChannel);

            return CHANEL_ID;
        } else {
            // Returns null for pre-O (26) devices.
            return null;
        }
    }
}
    private void onLaunchNotificationBtnClick() {
        String textTitle = "This is Title";
        String textContent = "This is Content";

        //创建Notification Channel
        String channelId = NotificationUtils.createNotificationChannel(getApplicationContext());

        //创建Notification并与Channel关联
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId)
                .setSmallIcon(R.drawable.ic_launcher_foreground)
                .setContentTitle(textTitle)
                .setContentText(textContent)
                .setPriority(NotificationCompat.PRIORITY_DEFAULT);

        //Launch Notification
        NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(getApplicationContext());
        notificationManagerCompat.notify(NOTIFICATION_ID, builder.build());
    }

最后运行,可以正常显示Notification:

Android 8.0 Oreo 形为变更之 Notification Channels_第2张图片

关于每一个发布的Android版本,Android Developers上都对新功能及形为变更做了详细的介绍,具体可以参考 Android Releases Versions.

Android 8.0 Oreo 形为变更之 Notification Channels_第3张图片

 

最后,总结一下教训,幸亏在提升target API Level至26后,测试发现了该问题,否则后果还是很严重的。2019年之后Google Play要求新发布或者更新的App必须是一年内发布的Android版本,未来可能更多的应用发布渠道(如应用宝)会跟进,所以提升targetSdkVersion势在必行,也请各个应用开发者赶紧跟上步伐。

完整代码请参考:https://github.com/cxcbupt/FullscreenDemo.git

References:

  1. 持续提高 Android 应用的安全性与性能
  2. Notifications Overview
  3. Exploring Android O: Notification Channels

你可能感兴趣的:(Android)