可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have send FCM notification from server to users. It works fine(until api 25) but in Oreo when the application have not in background(services are closed) (or) completely closed .I am not getting any FCM notifications at this scenario but in Whatsapp works fine.
here i have attached FCM code
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);
}
});
}
}
回答1:
When you target Android 8.0 (API level 26), you must implement one or more notification channels. If your targetSdkVersion is set to 25 or lower, when your app runs on Android 8.0 (API level 26) or higher, it behaves the same as it would on devices running Android 7.1 (API level 25) or lower.
Note:
If you target Android 8.0 (API level 26) and post a notification without specifying a notification channel, the notification does not appear and the system logs an error.
Note: You can turn on a new setting in Android 8.0 (API level 26) to display an on-screen warning that appears as a toast when an app targeting Android 8.0 (API level 26) attempts to post without a notification channel. To turn on the setting for a development device running Android 8.0 (API level 26), navigate to Settings > Developer options and enable Show notification channel warnings.
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);
}
Creating a Push Notification on Android Oreo
To create a notification, you will use the NotificationCompat.Builder class. The constructor which was used before took only Context as a parameter, but in Android O, the constructor looks like this –
NotificationCompat.Builder(Context context, String channelId)
The following code snippet will show you how to create a notification –
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 gives you a few more functions to customize your notification –
setNumber() – allows you to set the number displayed in the
long-press menu
setChannelId() – allows you set the Channel Id explicitly if you are using the old constructor
setColor() – allows a RGB value to put a color theme for your notification
setBadgeIconType() – allows you to set an icon to be displayed in the long-press menu
for more info check example here
回答2:
"Starting in Android 8.0 (API level 26), all notifications must be assigned to a channel or it will not appear."
Individual notifications must now be put in a specific channel. (Reference)
Option 1 [simple]
Change the target android version Android 7.1 (API level 25) or lower.
compileSdkVersion 25
defaultConfig {
applicationId "com.fcm"
minSdkVersion 16
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
Option 2
If you don't want to change the target version then follow the following method
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);
}
Use following Builder constructor
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(appContext, [id you mentioned above in constructor of NotificationChannel])
Create the notification from the Builder
nm.notify("0", notificationBuilder.build())
回答3:
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);
回答4:
You can use below class for generating notification in lower and upper version of android(Tested from 4.2(Jelly Bean) to 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);
}
}
Just call this class from FCM, with context and msg.
As its a thread class you can update the notification constantly also.
Don't forget to call destroyNotification() method, when your work ends.
You can discover and make changes in it, as you like
回答5:
In oreo version can not add a notification without Channel so need to add following code in firebase notification Service class for oreo notification without channel can not send notification :
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());
}
回答6:
Then you are sending notifications without data{}
object in your json. That's an old bug(?) or like supposed to work like that. If you don't have any data in your notification, then you won't trigger notifications while your app is on foreground.
Example json:
"notification":
{
"title": "notification_title",
"body": "notification_body"
},
"data":
{
"example":"hey",
"example2":"you need me."
},
"priority" : "high",
"registration_ids":
[
"crYjxvFkASE:APA91bGv4GWj9erJ6LsblEzpag5ObkcESEsBthxsJObJ38DhZ3GbSMLlGQK3qS_qvUvrcrg_cqBgCWhBeq1X2wgxO7gmcc_gW0jM4qZYYugF5wraTHwvDKNnjQwn8dpyGEbFMXLOCvE9"
]
回答7:
only data notifications is handled on android Oreo
try to remove the notification
`
remove this key notification
{"notification":
{
"title": "notification_title",
"body": "notification_body"
},
// keep only the data key
"data":
{
"example":"hey",
"example2":"you need me."
},
"priority" : "high",
"registration_ids":
[]
`
when the app is in background .. the onRecievedMessage will not called if the payload is contains both notification key and data key ..
so remove the notification .. and only keep the data key .. and it will work well
回答8:
You need to to ad permission and to create a notification channel
public static void createChannelAndHandleNotifications(Context context) {
ctx = context;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
NOTIFICATION_CHANNEL_ID,
NOTIFICATION_CHANNEL_NAME,
NotificationManager.IMPORTANCE_HIGH);
channel.setDescription(NOTIFICATION_CHANNEL_DESCRIPTION);
channel.setShowBadge(true);
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
回答9:
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());
}