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());
При этом вышеупомянутое уведомление становится частью канала уведомлений, созданного на первом этапе, и теперь его поведение будет соответствовать настройкам канала.