oreo - punto de notificacion android
¿Los mensajes de notificación de FCM no se reciben en la versión de Android Oreo? (7)
He enviado la notificación FCM del servidor a los usuarios. Funciona bien (hasta la api 25) pero en Oreo cuando la aplicación no está en segundo plano (los servicios están cerrados) (o) completamente cerrado. No recibo ninguna notificación de FCM en este escenario pero en Whatsapp funciona bien. Aquí he adjuntado el código FCM
Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fcm">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".MyFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_stat_ic_notification" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/colorAccent" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="fcm"/>
<meta-data android:name="firebase_messaging_auto_init_enabled"
android:value="false" />
<meta-data android:name="firebase_analytics_collection_enabled"
android:value="false" />
</application>
</manifest>
app / gradle
apply plugin: ''com.android.application''
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.fcm"
minSdkVersion 16
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile(''proguard-android.txt''), ''proguard-rules.pro''
}
}
}
dependencies {
implementation fileTree(dir: ''libs'', include: [''*.jar''])
implementation ''com.android.support.constraint:constraint-layout:1.1.2''
testImplementation ''junit:junit:4.12''
androidTestImplementation ''com.android.support.test:runner:1.0.2''
androidTestImplementation ''com.android.support.test.espresso:espresso-core:3.0.2''
implementation ''com.google.firebase:firebase-messaging:17.1.0''
}
apply plugin: ''com.google.gms.google-services''
MyFirebaseMessagingService.java
package com.fcm;
import android.app.Service;
import android.util.Log;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
public class MyFirebaseMessagingService extends FirebaseMessagingService
{
@Override
public void onNewToken(String s)
{
super.onNewToken(s);
}
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
Log.e("FCM Message Received","You Have FCM Message");
}
}
MainActivity.java
package com.nexge.fcm;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.InstanceIdResult;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener( this, new OnSuccessListener<InstanceIdResult>() {
@Override
public void onSuccess(InstanceIdResult instanceIdResult) {
String newToken = instanceIdResult.getToken();
Log.e("newToken",newToken);
}
});
}
}
Cuando se dirige a Android 8.0 (nivel de API 26) , debe implementar uno o más canales de notificación. Si su targetSdkVersion se establece en 25 o inferior, cuando su aplicación se ejecuta en Android 8.0 (nivel de API 26) o superior, se comporta de la misma manera que en dispositivos con Android 7.1 (nivel de API 25) o inferior.
Nota: Si se dirige a Android 8.0 (nivel de API 26) y publica una notificación sin especificar un canal de notificación, la notificación no aparece y el sistema registra un error.
Nota: puede activar una nueva configuración en Android 8.0 (nivel de API 26) para mostrar una advertencia en pantalla que aparece como un brindis cuando una aplicación dirigida a Android 8.0 (nivel de API 26) intenta publicar sin un canal de notificación. Para activar la configuración de un dispositivo de desarrollo con Android 8.0 (nivel de API 26), vaya a Configuración> Opciones de desarrollador y active Mostrar avisos de canal de notificación .
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
String id = "id_product";
// The user-visible name of the channel.
CharSequence name = "Product";
// The user-visible description of the channel.
String description = "Notifications regarding our products";
int importance = NotificationManager.IMPORTANCE_MAX;
NotificationChannel mChannel = new NotificationChannel(id, name, importance);
// Configure the notification channel.
mChannel.setDescription(description);
mChannel.enableLights(true);
// Sets the notification light color for notifications posted to this
// channel, if the device supports this feature.
mChannel.setLightColor(Color.RED);
notificationManager.createNotificationChannel(mChannel);
}
Creando una Notificación Push en Android Oreo
Para crear una notificación, utilizará la clase NotificationCompat.Builder. El constructor que se usó antes tomó solo Contexto como parámetro, pero en Android O, el constructor se ve así:
NotificationCompat.Builder(Context context, String channelId)
El siguiente fragmento de código le mostrará cómo crear una notificación:
Intent intent1 = new Intent(getApplicationContext(), Ma
inActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 123, intent1, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(getApplicationContext(),"id_product")
.setSmallIcon(R.drawable.flatpnicon) //your app icon
.setBadgeIconType(R.drawable.flatpnicon) //your app icon
.setChannelId(id)
.setContentTitle(extras.get("nt").toString())
.setAutoCancel(true).setContentIntent(pendingIntent)
.setNumber(1)
.setColor(255)
.setContentText(extras.get("nm").toString())
.setWhen(System.currentTimeMillis());
notificationManager.notify(1, notificationBuilder.build());
Android O te ofrece algunas funciones más para personalizar tu notificación.
setNumber () : le permite establecer el número que se muestra en el menú de pulsación larga setChannelId () : le permite establecer el Id. de canal explícitamente si está usando el antiguo constructor setColor () : permite que un valor RGB coloque un tema de color para su notificación setBadgeIconType () : le permite configurar un icono para que se muestre en el menú de larga duración
para más información ver ejemplo aquí
En la versión oreo no se puede agregar una notificación sin el canal, por lo que debe agregar el siguiente código en la clase de servicio de notificación de base de fuego para la notificación de oreo sin que el canal no pueda enviar la notificación:
private void sendMyNotification(String message,String title) {
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
Uri soundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
@SuppressLint("WrongConstant")
NotificationChannel notificationChannel=new NotificationChannel("my_notification","n_channel",NotificationManager.IMPORTANCE_MAX);
notificationChannel.setDescription("description");
notificationChannel.setName("Channel Name");
notificationManager.createNotificationChannel(notificationChannel);
}
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.listlogo)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.tlogo))
.setContentTitle(title)
.setContentText(message)
.setAutoCancel(true)
.setSound(soundUri)
.setContentIntent(pendingIntent)
.setDefaults(Notification.DEFAULT_ALL)
.setPriority(NotificationManager.IMPORTANCE_MAX)
.setOnlyAlertOnce(true)
.setChannelId("my_notification")
.setColor(Color.parseColor("#3F5996"));
//.setProgress(100,50,false);
notificationManager.notify(0, notificationBuilder.build());
}
Entonces estás enviando notificaciones sin data{}
objeto en tu json. Eso es un viejo bicho (?) O como se supone que funciona así. Si no tiene ningún dato en su notificación, no activará las notificaciones mientras su aplicación esté en primer plano.
Ejemplo json:
"notification":
{
"title": "notification_title",
"body": "notification_body"
},
"data":
{
"example":"hey",
"example2":"you need me."
},
"priority" : "high",
"registration_ids":
[
"crYjxvFkASE:APA91bGv4GWj9erJ6LsblEzpag5ObkcESEsBthxsJObJ38DhZ3GbSMLlGQK3qS_qvUvrcrg_cqBgCWhBeq1X2wgxO7gmcc_gW0jM4qZYYugF5wraTHwvDKNnjQwn8dpyGEbFMXLOCvE9"
]
Puede usar la clase inferior para generar notificaciones en las versiones inferior y superior de Android (Probado desde 4.2 (Jelly Bean) a 8.1.1 (Oreo)).
public final class NotificationHelper extends Thread {
private Context context;
private NotificationManager notifManager;
private NotificationCompat.Builder notification_compact;
private Notification.Builder notification_builder;
private int OREO_NOTIFICATION_TYPE = 2; //setting default notificaiton type 2, as 1 is not for constant updating
//put string channel name and id in **<>**
private static final String CHANNEL_ONE_ID = "<Your_channel_string_ID>";
private static final String CHANNEL_ONE_NAME = "<Your channel_String_NAME>";
private static final String CHANNEL_TWO_ID = "<Your_channel_string_ID_TWO>";
private static final String CHANNEL_TWO_NAME = "<Your channel_String_NAME_TWO>";
private String title = "", message = "";
/**
* @param context content of activity
* @param title title for notification_compact
* @param message message to show in notification_compact
*/
public NotificationHelper(Context context, String title, String message) {
this.context = context;
this.title = title;
this.message = message;
notifManager = getManager();
}
@Override
public void run() {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) {
//do stuff for oreo
createChannels();
postNotificationAboveV25(OREO_NOTIFICATION_TYPE, title);
} else {
//do stuff for other versions
postNotificationUptoV25();
}
}
//method to show notificaiton above nougat
private void postNotificationAboveV25(int id, String title) {
notification_builder = getNotificatonBuilder(id, title);
if (notification_builder != null) {
getManager().notify(id, notification_builder.build());
}
}
//get pending intent to launch activity
private PendingIntent getPendingIntent() {
Intent startActivity = context.getPackageManager()
.getLaunchIntentForPackage(context.getPackageName())
.setPackage(null)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
return PendingIntent.getActivity(context, 0, startActivity, 0);
// Intent resultIntent = new Intent(context, ActionActivity.class);
// return PendingIntent.getActivity(context, AppHelper.NOTIFICATION_ID, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
}
//method to get notification builder above nougat
private Notification.Builder getNotificatonBuilder(int id, String title) {
switch (id) {
case 1:
return notification_builder = getNotification1(title, message);
case 2:
return notification_builder = getNotification2(title, message);
default:
return notification_builder = getNotification2(title, message);
}
}
//Create the notification_compact that’ll be posted to Channel One
//use this one if your notification is a type of push notificaiton
// or
//if you are not updating it in continues intervals like every 4 or 5 seconds(ex. Timer)
@SuppressLint("NewApi")
private Notification.Builder getNotification1(String title, String body) {
return new Notification.Builder(context, CHANNEL_ONE_ID)
.setContentTitle(title)
.setContentText(body)
.setSmallIcon(R.drawable.app_icon)
.setAutoCancel(true)
.setTicker(title + AppHelper.getMessage(R.string.started))
.setColor(AppHelper.getColor(context, R.color.colorPrimary))
.setContentIntent(getPendingIntent());
}
//Create the notification_compact that’ll be posted to Channel Two
//use this for continues intervals or updating continuesly
@SuppressLint("NewApi")
private Notification.Builder getNotification2(String title, String body) {
return new Notification.Builder(context, CHANNEL_TWO_ID)
.setContentTitle(title)
.setContentText(body)
.setTicker(title + AppHelper.getMessage(R.string.started))
.setSmallIcon(R.drawable.app_icon)
.setAutoCancel(true)
.setColor(AppHelper.getColor(context, R.color.colorPrimary))
.setContentIntent(getPendingIntent());
}
//method to post notification upto Nougat i.e., below api level 26
@SuppressLint("NewApi")
private void postNotificationUptoV25() {
notification_compact = new NotificationCompat.Builder(context);
notification_compact.setAutoCancel(true);
notification_compact.setSmallIcon(R.drawable.app_icon);
notification_compact.setTicker(title + AppHelper.getMessage(R.string.started));
notification_compact.setContentTitle(title);
notification_compact.setContentText(message);
notification_compact.setColor(AppHelper.getColor(context, R.color.colorPrimary));
notification_compact.setContentIntent(getPendingIntent());
// notification_compact.setWhen(1506067106762L);
getManager().notify(AppHelper.NOTIFICATION_ID, notification_compact.build());
}
//method to update notification
public void updateNotification(String time) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) {
//update above NOUGAT V25
if (notification_builder != null) {
notification_builder.setContentText(message + " " + time);
getManager().notify(AppHelper.NOTIFICATION_ID, notification_builder.build());
}
} else {
//update below NOUGAT V25
if (notification_compact != null) {
notification_compact.setContentText(message + " " + time);
getManager().notify(AppHelper.NOTIFICATION_ID, notification_compact.build());
}
}
}
//method to update remainting notification
public void updateRemainingNotification(String time) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) {
//update above NOUGAT V25
if (notification_builder != null) {
notification_builder.setContentText(time + AppHelper.getMessage(R.string.remaining));
getManager().notify(AppHelper.NOTIFICATION_ID, notification_builder.build());
}
} else {
//update below NOUGAT V25
if (notification_compact != null) {
notification_compact.setContentText(time + AppHelper.getMessage(R.string.remaining));
getManager().notify(AppHelper.NOTIFICATION_ID, notification_compact.build());
}
}
}
//method to create channels which is necessary above Nougat(API - 25) i.e., at Oreo(API - 26)
@SuppressLint("NewApi")
private void createChannels() {
NotificationChannel notificationChannel = new NotificationChannel(CHANNEL_ONE_ID,
CHANNEL_ONE_NAME, notifManager.IMPORTANCE_DEFAULT);
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.setShowBadge(true);
notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
getManager().createNotificationChannel(notificationChannel);
NotificationChannel notificationChannel2 = new NotificationChannel(CHANNEL_TWO_ID,
CHANNEL_TWO_NAME, notifManager.IMPORTANCE_DEFAULT);
notificationChannel2.enableLights(false);
notificationChannel2.enableVibration(true);
notificationChannel2.setLightColor(Color.RED);
notificationChannel2.setShowBadge(false);
getManager().createNotificationChannel(notificationChannel2);
}
//method to get Object of Notification Manager
private NotificationManager getManager() {
if (notifManager == null)
notifManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
return notifManager;
}
/**
* call this method to destroy notification
*/
public void destroyNotification() {
if (notifManager != null)
notifManager.cancel(AppHelper.NOTIFICATION_ID);
}
}
Simplemente llame a esta clase desde FCM, con contexto y msg. Como es una clase de subproceso, también puede actualizar la notificación constantemente.
No olvides llamar al método destroyNotification () cuando tu trabajo termine.
Puedes descubrir y hacer cambios en él, como quieras.
"A partir de Android 8.0 (nivel de API 26), todas las notificaciones deben asignarse a un canal o no aparecerá".
Las notificaciones individuales ahora se deben poner en un canal específico. ( Reference )
Opción 1 [simple] Cambie la versión de Android de destino 7.1 (nivel API 25) o inferior.
compileSdkVersion 25
defaultConfig {
applicationId "com.fcm"
minSdkVersion 16
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
Opción 2 Si no desea cambiar la versión de destino, siga el siguiente método
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
NotificationChannel nc = new NotificationChannel(“[enter your product id]”, “[Name]”,NotificationManager.IMPORTANCE_MAX);
nc.setDescription(“[your description for the notification]”);
nc.enableLights(true);
nc.setLightColor(Color.GREEN);
nm.createNotificationChannel(nc);
}
Utilice el siguiente constructor de constructor
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(appContext, [id you mentioned above in constructor of NotificationChannel])
Crear la notificación desde el generador.
nm.notify("0", notificationBuilder.build())
private void generateNotification(String message, String title) {
Intent intent = new Intent(getApplicationContext(), ActitivtyNotification.class);
intent.setFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.stkfood_logo) //a resource for your custom small icon
.setContentTitle(title) //the "title" value you sent in your notification
.setContentText(message) //ditto
.setAutoCancel(true) //dismisses the notification on click
.setSound(defaultSoundUri);
//Setting up Notification channels for android O and above
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel notificationChannel = new NotificationChannel("3", "CHANNEL_NAME", importance);
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.enableVibration(true);
notificationChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
assert mNotificationManager != null;
notificationBuilder.setChannelId("3");
mNotificationManager.createNotificationChannel(notificationChannel);
}
PendingIntent contentIntent = PendingIntent.getActivity(this, 3, intent, PendingIntent.FLAG_UPDATE_CURRENT);
notificationBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(3, notificationBuilder.build());
}
notification = new NotificationCompat.Builder(this, ANDROID_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_small_logo)
.setLargeIcon(picture)
.setContentTitle("Title")
.setContentText("Body")
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.build();
-
ANDROID_CHANNEL_ID = "CHANNEL_ID"
-
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
-
intent = new Intent(getApplicationContext(), HomeActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);