Android O - каналы уведомлений и NotificationCompat

Я не могу изменить это чувство: снова разработчики Android придумали что-то новое и оставили всех в темноте о том, как они думают, что функция используется.

Я говорю о Каналах уведомлений в Android O.

В течение многих лет я использую библиотеки поддержки совместимости, чтобы не обращаться к конкретным деталям платформы. А именно: NotificationCompat.

Теперь Builder требует от меня указать идентификатор канала уведомлений, что приятно, но полностью оставляет меня наедине с созданием такого канала. Я не могу найти поддержку совместимости для создания каналов. Я также не могу найти разумный способ создать их в нужном месте.

Документы просто утверждают, что это должно быть сделано "где-то" и "возможно, не при выпуске уведомления". Но что именно я должен делать? Я ненавижу писать конкретные статьи для простых задач - поэтому я использую библиотеки совместимости.

Есть ли у кого-нибудь предложение о том, как с ним справиться? "Дороже" делать создание каждый раз, когда я хочу, чтобы уведомление отображалось?

Ответ 1

Это мое решение для создания уведомлений на 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());

Ответ 2

Это не так дорого, как вы думаете! Все, что вам нужно сделать, это создать канал уведомлений и связать его с уведомлением.

Вы можете решить это двумя способами, но для них вы должны создать канал уведомлений с определенным идентификатором канала.

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);

Надеюсь, что это поможет

Ответ 3

Вот альтернативное решение, которое использует отражение для создания канала Notification Channel, чтобы вы могли установить 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);
        }
    }

Затем, когда вы создаете свои уведомления, просто вызовите метод .setChannelId() NotificationCompat.Builder:

builder.setChannelId("myChannelId");

Примечание. Вам необходимо обновить библиотеку appcompat-v7 до версии 26.x.x в build.gradle:

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

Ответ 4

Если вы хотите поддерживать предыдущие версии Android (<Oreo). Мы можем обернуть NotificationManager для создания и сборки экземпляра Notification.Builder в NotificationHelper следующим образом:

/**
 * Helper class to manage notification channels, and create notifications.
 * <p>
 * Created by teocci.
 *
 * @author [email protected] 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 transient, the view
     * will be hidden.  If it 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 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 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)
}

Ответ 5

Если ваш код уведомления имеет одинаковую структуру каждый раз, поэтому вы должны создать статический метод и передать все, что вы хотите, и поместить код, который проверяет уровень API, внутри этого метода.

Ответ 6

Следующий код работает нормально на моей стороне, надеюсь, это поможет вам

private void sendNotification(Context ctx, String title, int notificationNumber, String message, String subtext, Intent intent) {
        try {

            PendingIntent pendingIntent = PendingIntent.getActivity(ctx, notificationNumber, intent,
                    PendingIntent.FLAG_UPDATE_CURRENT);
            Uri url = your sound file from raw;
            NotificationCompat.Builder notificationBuilder = null;
            try {
                if (Build.VERSION.SDK_INT >= 26) {

                    try{
                        NotificationManager notificationManager = (NotificationManager)getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
                        notificationManager.deleteNotificationChannel(CHANNEL_ID_1);
                        notificationManager.deleteNotificationChannel(CHANNEL_ID_2);

                        if(!intent.getStringExtra("type").equalsIgnoreCase(""+TYPE_RIDE_REQUEST)){
                            NotificationChannel breaking = new NotificationChannel(CHANNEL_ID_1, CHANNEL_ID_1_NAME, NotificationManager.IMPORTANCE_HIGH);
                            breaking.setShowBadge(false);
                            breaking.enableLights(true);
                            breaking.enableVibration(true);
                            breaking.setLightColor(Color.WHITE);
                            breaking.setVibrationPattern(new long[]{100, 200, 100, 200, 100, 200, 100});
                            breaking.setSound(url,new AudioAttributes.Builder().build());

                            notificationBuilder = new NotificationCompat.Builder(this,CHANNEL_ID_1)
                                    .setSmallIcon(R.mipmap.ic_launcher);
                            notificationManager.createNotificationChannel(breaking);

                        }else{

                            NotificationChannel politics = new NotificationChannel(CHANNEL_ID_2,CHANNEL_ID_2_NAME, NotificationManager.IMPORTANCE_DEFAULT);
                            politics.setShowBadge(false);
                            politics.enableLights(true);
                            politics.enableVibration(true);
                            politics.setLightColor(Color.BLUE);
                            politics.setVibrationPattern(new long[]{100, 200, 100, 200, 100});
                            politics.setSound(url,new AudioAttributes.Builder().build());

                            notificationBuilder = new NotificationCompat.Builder(this,CHANNEL_ID_2)
                                    .setSmallIcon(R.mipmap.ic_launcher);
                            notificationManager.createNotificationChannel(politics);
                        }
                    }catch (Exception e){
                        e.printStackTrace();
                    }

                } else {
                    notificationBuilder = new NotificationCompat.Builder(ctx)
                            .setSmallIcon(R.mipmap.ic_launcher);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

            if (notificationBuilder == null) {
                notificationBuilder = new NotificationCompat.Builder(ctx)
                        .setSmallIcon(R.mipmap.ic_launcher);
            }


            notificationBuilder.setContentTitle(title);
            notificationBuilder.setSubText(subtext);
            notificationBuilder.setAutoCancel(true);

            notificationBuilder.setContentIntent(pendingIntent);
            notificationBuilder.setNumber(notificationNumber);
            NotificationManager notificationManager =
                    (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);

            notificationManager.notify(notificationNumber, notificationBuilder.build());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Ответ 7

Я знаю, что этот ответ опоздал, но лучше поздно, чем никогда!
Я только что выпустил библиотеку уведомлений channel-compat, которая обеспечивает поддержку Notification Channel, начиная с OS 4.0. Поскольку разработчикам в любом случае приходится проектировать каналы, они теперь могут использовать преимущества каналов для всех устройств, и им не нужно разрабатывать отдельно для старых устройств.
Библиотека использует встроенные классы каналов для устройств OS 8. 0+ и имитирует его для более старых устройств. Все, что нужно, это использовать наши классы NotificationChannelCompat, NotificationChannelGroupCompat и NotificationChannelManagerHelper и добавить одну строку кода. Вы можете увидеть больше на GitHub. Пожалуйста, проверьте это и дайте мне знать о любых проблемах.
Спасибо,
Lionscribe

Ответ 8

Работать с NotificationChannnel довольно просто.

NotificationChannel фактически группирует несколько уведомлений в каналы. Это в основном дает больше контроля над поведением уведомлений пользователю. Вы можете узнать больше о Канале Уведомления и его реализации в Работе с Каналом Уведомления | С примером

Создание канала уведомлений

 // 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);

Теперь при создании уведомления просто передайте идентификатор канала конструктору Notification Builder, как показано ниже

//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());

При этом вышеупомянутое уведомление становится частью канала уведомлений, созданного на первом этапе, и теперь его поведение будет соответствовать настройкам канала.