安卓 O - 通知渠道和 NotificationCompat

28

我无法改变这种感觉:安卓开发人员再次推出了新功能,并让所有人对如何使用该功能感到茫然。

我说的是安卓 O 中的通知渠道。

多年来,我一直在使用兼容性支持库来避免处理特定平台细节,即:NotificationCompat。

现在,Builder 要求我提供一个通知渠道 ID,这很好,但完全让我自己创建这样的渠道。 我找不到任何用于创建渠道的兼容性支持,也找不到在正确时间创建它们的合理方法。

文档简单地说明应该在“某个地方”进行创建,而且“可能不是在发布通知时”。 但我应该做什么?我讨厌为简单的任务编写特定版本的代码 - 这就是我使用兼容性库的原因。

有人有处理它的建议吗?每次想要显示通知时创建它们是否“昂贵”?


我也找不到一个合理的方法在正确的时候创建它们 - 我会在您的应用程序第一次运行时执行此操作,或者根据需要进行懒惰创建(如果它们尚不存在)。"每次我想要显示通知时都创建它们是否“昂贵”?" - 每次创建相同的通道最多只会浪费时间,或者在最坏的情况下会给您N组通道,因为没有更新机制。"我找不到任何兼容支持来创建通道" - v26库处于beta版本;也许他们会添加它。 - CommonsWare
6个回答

16

这是我在Android O上生成通知并保持向后兼容的解决方案:

        String idChannel = "my_channel_01";
        Intent mainIntent;

        mainIntent = new Intent(context, LauncherActivity.class);

        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, mainIntent, 0);

        NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

        NotificationChannel mChannel = null;
        // The id of the channel.

        int importance = NotificationManager.IMPORTANCE_HIGH;

        NotificationCompat.Builder builder = new NotificationCompat.Builder(context, null);
        builder.setContentTitle(context.getString(R.string.app_name))
                .setSmallIcon(getNotificationIcon())
                .setContentIntent(pendingIntent)
                .setContentText(context.getString(R.string.alarm_notification) + ManagementDate.getIstance().hourFormat.format(getAlarm(context, 0)));

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            mChannel = new NotificationChannel(idChannel, context.getString(R.string.app_name), importance);
            // Configure the notification channel.
            mChannel.setDescription(context.getString(R.string.alarm_notification));
            mChannel.enableLights(true);
            mChannel.setLightColor(Color.RED);
            mChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
            mNotificationManager.createNotificationChannel(mChannel);
        } else {
            builder.setContentTitle(context.getString(R.string.app_name))
                    .setPriority(NotificationCompat.PRIORITY_HIGH)
                    .setColor(ContextCompat.getColor(context, R.color.transparent))
                    .setVibrate(new long[]{100, 250})
                    .setLights(Color.YELLOW, 500, 5000)
                    .setAutoCancel(true);
        }
        mNotificationManager.notify(1, builder.build());

5

这并不像你想象的那么昂贵!你需要做的就是创建一个通知渠道并将其绑定到通知上。

有两种方法可以解决这个问题,但无论哪种方法,你都需要创建一个具有特定通道ID的通知渠道。

NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
String id = "my_channel_01";
int importance = NotificationManager.IMPORTANCE_LOW;
NotificationChannel mChannel = new NotificationChannel(id, name,importance);
mChannel.enableLights(true);
mNotificationManager.createNotificationChannel(mChannel);

第一种方法是在构造函数中设置通知渠道:

Notification notification = new Notification.Builder(MainActivity.this , id).setContentTitle("Title");
mNotificationManager.notify("your_notification_id", notification);

第二种方式是通过Notificiation.Builder.setChannelId()设置通道。

Notification notification = new Notification.Builder(MainActivity.this).setContentTitle("Title").
setChannelId(id);
mNotificationManager.notify("your_notification_id", notification);

希望这能有所帮助。

6
这是用于通知,而不是用于 NotificationCompat。 - Arnaldo
如果我已经为应用程序设置了通知渠道,是否可以通过该渠道获取我为特定应用程序更改的声音URI。 - Sagar

3

如果您想要支持 Android 的旧版本(< Oreo),我们可以使用 NotificationHelper 来包装 NotificationManager,并创建和构建 Notification.Builder 实例,如下所示:

/**
 * Helper class to manage notification channels, and create notifications.
 * <p>
 * Created by teocci.
 *
 * @author teocci@yandex.com on 2018-Oct-02
 */
public class NotificationHelper extends ContextWrapper
{
    public static final String NOTIFICATION_CHANNEL_PRIMARY = "notification_channel_primary";
    public static final int NOTIFICATION_ID_PRIMARY = 1100;

    private NotificationManager manager;

    /**
     * Registers notification channels, which can be used later by individual notifications.
     *
     * @param ctx The application context
     */
    public NotificationHelper(Context ctx)
    {
        super(ctx);

        // For API 26+ create notification channels
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_PRIMARY,
                    getString(R.string.channel_name),
                    NotificationManager.IMPORTANCE_DEFAULT
            );
            channel.setLightColor(Color.BLUE);
            channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
            channel.setDescription(getString(R.string.channel_description));
            getManager().createNotificationChannel(channel);
        }
    }
    /**
     * Cancel a previously shown notification.  If it's transient, the view
     * will be hidden.  If it's persistent, it will be removed from the status
     * bar.
     *
     * @param id    The ID of the notification
     */
    public void remove(int id){
        manager.cancel(id);
    }

    /**
     * Get a notification of type 1
     * <p>
     * Provide the builder rather than the notification it's self as useful for making notification
     * changes.
     *
     * @return the builder as it keeps a reference to the notification (since API 24)
     */
    public Notification getNotification()
    {
        return getNotification(getTitle(), getBody()).build();
    }

    /**
     * Get a notification of type 1
     * <p>
     * Provide the builder rather than the notification it's self as useful for making notification
     * changes.
     *
     * @param title the title of the notification
     * @param body  the body text for the notification
     * @return the builder as it keeps a reference to the notification (since API 24)
     */
    public Notification.Builder getNotification(String title, String body)
    {
        Notification.Builder builder = new Notification.Builder(getApplicationContext())
                .setOngoing(true)  // Persistent notification!
                .setAutoCancel(true)
                .setTicker(title)
                .setContentTitle(title)
                .setContentText(body)
                .setSmallIcon(getSmallIcon());

        // Set the Channel ID for Android O.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            builder.setChannelId(NOTIFICATION_CHANNEL_PRIMARY); // Channel ID
        }

        return builder;
    }

    /**
     * Send a notification.
     *
     * @param id           The ID of the notification
     * @param notification The notification object
     */
    public void notify(int id, Notification.Builder notification)
    {
        getManager().notify(id, notification.build());
    }

    /**
     * Get the notification manager.
     * <p>
     * Utility method as this helper works with it a lot.
     *
     * @return The system service NotificationManager
     */
    private NotificationManager getManager()
    {
        if (manager == null) {
            manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        }

        return manager;
    }

    /**
     * Get the small icon for this app
     *
     * @return The small icon resource id
     */
    private int getSmallIcon()
    {
        return R.drawable.ic_smart_audio_noti_icon;
    }

    /**
     * Get the notification title for this app
     *
     * @return The notification title as string
     */
    private String getTitle()
    {
        return getString(R.string.notification_title);
    }

    /**
     * Get the notification content for this app
     *
     * @return The notification content as string
     */
    private String getBody()
    {
        return getString(R.string.notification_content);
    }
}

然后我们可以像这样轻松使用它:
@Override
public void onCreate()
{
    ...
    notificationHelper = new NotificationHelper(this);
    notificationHelper.notify(NotificationHelper.NOTIFICATION_ID_PRIMARY, "App is running");
    ...
}

@Override
public void onDestroy()
{
    notificationHelper.remove(NotificationHelper.NOTIFICATION_ID_PRIMARY)
}

2

这里有一种替代方案,使用反射创建通知渠道,因此您可以将compileSdkVersion设置为低于26的版本。

   private void createNotificationChannel(NotificationManager notificationManager) {
        // Channel details
        String channelId = "myChannelId";
        String channelName = "Notifications";

        // Channel importance (3 means default importance)
        int channelImportance = 3;

        try {
            // Get NotificationChannel class via reflection (only available on devices running Android O or newer)
            Class notificationChannelClass = Class.forName("android.app.NotificationChannel");

            // Get NotificationChannel constructor
            Constructor<?> notificationChannelConstructor = notificationChannelClass.getDeclaredConstructor(String.class, CharSequence.class, int.class);

            // Instantiate new notification channel
            Object notificationChannel = notificationChannelConstructor.newInstance(channelId, channelName, channelImportance);

            // Get notification channel creation method via reflection
            Method createNotificationChannelMethod =  notificationManager.getClass().getDeclaredMethod("createNotificationChannel", notificationChannelClass);

            // Invoke method on NotificationManager, passing in the channel object
            createNotificationChannelMethod.invoke(notificationManager, notificationChannel);

            // Log success to console
            Log.d("MyApp", "Notification channel created successfully");
        }
        catch (Exception exc) {
            // Log exception to console
            Log.e("MyApp", "Creating notification channel failed", exc);
        }
    }

当您构建通知时,只需调用NotificationCompat.Builder.setChannelId()方法:

builder.setChannelId("myChannelId");

注意: 您需要在 build.gradle 文件中将你的 appcompat-v7 库更新到版本 26.x.x:

compile 'com.android.support:appcompat-v7:26.1.0'

0
如果你的通知代码每次都有相同的结构,那么你应该创建一个静态方法,并将想要传递的所有内容都传递进去,并把检查API级别的代码放在这个方法里。

-2

使用NotificationChannel非常简单。

NotificationChannel实际上将多个通知分组到通道中。它基本上为用户提供了更多的通知行为控制。您可以在使用示例 | Working with Notification Channel中了解有关Notification Channel及其实现的更多信息。

创建Notification Channel

 // This is the Notification Channel ID. More about this in the next section
public static final String NOTIFICATION_CHANNEL_ID="channel_id";

//User visible Channel Name
public static final String CHANNEL_NAME="Notification Channel";

// Importance applicable to all the notifications in this Channel
int importance=NotificationManager.IMPORTANCE_DEFAULT;

//Notification channel should only be created for devices running Android 26
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

      NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, CHANNEL_NAME, importance);

      //Boolean value to set if lights are enabled for Notifications from this Channel
      notificationChannel.enableLights(true);

      //Boolean value to set if vibration is enabled for Notifications from this Channel
      notificationChannel.enableVibration(true);

      //Sets the color of Notification Light
      notificationChannel.setLightColor(Color.GREEN);

      //Set the vibration pattern for notifications. Pattern is in milliseconds with the format {delay,play,sleep,play,sleep...}
      notificationChannel.setVibrationPattern(new long[]{500,500,500,500,500});

      //Sets whether notifications from these Channel should be visible on Lockscreen or not
      notificationChannel.setLockscreenVisibility( 
 Notification.VISIBILITY_PUBLIC);
}
// Creating the Channel
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(notificationChannel);

现在,在创建通知时,只需将频道 ID 传递给如下所示的通知构建器构造函数即可

//We pass the unique channel id as the second parameter in the constructor
NotificationCompat.Builder notificationCompatBuilder=new NotificationCompat.Builder(this,NOTIFICATION_CHANNEL_ID);

//Title for your notification
notificationCompatBuilder.setContentTitle("This is title");

//Subtext for your notification
notificationCompatBuilder.setContentText("This is subtext");

//Small Icon for your notificatiom
notificationCompatBuilder.setSmallIcon(R.id.icon);

//Large Icon for your notification 
notificationCompatBuilder.setLargeIcon(  BitmapFactory.decodeResource(getResources(),R.id.icon));

notificationManager.notify( NOTIFICATION_ID,notificationCompatBuilder.build());

通过这个通知,它将成为在第一步创建的通知渠道的一部分,并且其行为现在将与渠道设置相关。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接