I implemented push notification in my application. They works well when the application is opened or it is in the background but when the the application is closed a pup up message on my screen is displayed saying that a problem occurred in the application.
here there is the piece of code that implements push notifications.
public class GcmIntentService extends IntentService {
public static final int NOTIFICATION_ID = 1;
private NotificationManager mNotificationManager;
NotificationCompat.Builder builder;
FeedReaderDbHelperMessages mDbHelper;
/**
* Tag used on log messages.
*/
static final String TAG = "GCM Intent";
/**
* Db access object
* */
public GcmIntentService() {
super("GcmIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
// The getMessageType() intent parameter must be the intent you received
// in your BroadcastReceiver.
String messageType = gcm.getMessageType(intent);
if (!extras.isEmpty()) { // has effect of unparcelling Bundle
/*
/*
* Filter messages based on message type. Since it is likely that GCM
* will be extended in the future with new message types, just ignore
* any message types you're not interested in, or that you don't
* recognize.
*/
if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
sendNotification(extras);
} else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) {
sendNotification(extras);
// If it's a regular GCM message, do some work.
} else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
// Post notification of received message.
sendNotification(extras);
Intent i = new Intent("android.intent.action.MAIN").putExtras(extras);
this.sendBroadcast(i);
Log.i(TAG, "Received: " + extras.toString());
}
}
// Release the wake lock provided by the WakefulBroadcastReceiver.
GcmBroadcastReceiver.completeWakefulIntent(intent);
}
// Put the message into a notification and post it.
// This is just one simple example of what you might choose to do with
// a GCM message.
private void sendNotification(Bundle msg) {
FacebookSdk.sdkInitialize(getApplicationContext());
Profile userProfile = Profile.getCurrentProfile();
String user_id = userProfile.getId();
mNotificationManager = (NotificationManager)
this.getSystemService(Context.NOTIFICATION_SERVICE);
Intent newIntent = new Intent(this, drawnerActivity.class);
newIntent.setAction("OPEN_NOTIFICATION");
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,newIntent, 0);
mDbHelper = new FeedReaderDbHelperMessages(getApplicationContext());
UpdateMessages updateMessages = new UpdateMessages(mDbHelper);
if(msg.getString("notificationType").equals("question"))
{
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.logo_notifica_domanda_mini)
.setContentTitle("MyApp")
.setStyle(new NotificationCompat.BigTextStyle().bigText("New question"))
.setContentText("New question");
Vibrator v = (Vibrator) getApplicationContext().getSystemService(Context.VIBRATOR_SERVICE);
v.vibrate(400);
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
updateMessages.update(user_id);
}
if(msg.getString("notificationType").equals("answer"))
{
Contact userAnswer = ContactListFragment.findContactById(msg.getString("friendId"));
Timestamp notificationTimestamp = Timestamp.valueOf(msg.getString("timestamp"));
Log.i(TAG, "Answer notification received from: "+ userAnswer.getName() + " timestamp: " + notificationTimestamp.toString());
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.logo_mini_dialog)
.setContentTitle("MyApp")
.setStyle(new NotificationCompat.BigTextStyle().bigText("New answer"))
.setContentText(userAnswer.getName() + " answered");
Vibrator v = (Vibrator) getApplicationContext().getSystemService(Context.VIBRATOR_SERVICE);
long[] pattern = {
0, // Start immediately
100,
100,
100
};
v.vibrate(pattern, -1);
//updateMessages.updateRowWithAnswer(msg.getString("questionId"), msg.getString("answer"));
FeedReaderDbHelperNotification mDbHelperNotifications = new FeedReaderDbHelperNotification(getApplicationContext());
UpdateNotifications updateNotifications = new UpdateNotifications(mDbHelperNotifications, mDbHelper);
updateNotifications.update(user_id);
//NotificationFragment.addNotification(new NotificationImpl(notificationTimestamp, 1, 0, msg.getString("questionId"), ""), getApplication().getApplicationContext());
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
}
}
the problem is a NullPointerException here String user_id = userProfile.getId();. The userProfile cames from com.facebook.Profile class because I use facebook sdk to keep session. Why is it null?
here there is the stacktrace
java.lang.NullPointerException
at com.bellantoni.chetta.lieme.GcmIntentService.sendNotification(GcmIntentService.java:80)
at com.bellantoni.chetta.lieme.GcmIntentService.onHandleIntent(GcmIntentService.java:63)
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.os.HandlerThread.run(HandlerThread.java:61)
If this code block is the first time you are calling FacebookSdk.sdkInitialize then the problem is likely that the user has not logged in yet, so there is no user profile, hence the NullPointerException. I had a similar problem a while back and this was the issue.
Make sure that you are calling the Login callback from the FacebookSDK. Hope this helps.
Related
This is my first question. I have connected my domain into firebase. The push notification is working when I update the post in my Wordpress Blog. Ok, thats good for now. But, i want to save all that notification in a Fragment, and can be clicked from there to start an activity for post id. How to save that Notification?
Here is my Firebase Messaging code:
private static int VIBRATION_TIME = 500; // in millisecond
private SharedPref sharedPref;
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
sharedPref = new SharedPref(this);
if (sharedPref.getNotification()) {
// play vibration
if (sharedPref.getVibration()) {
((Vibrator) getSystemService(Context.VIBRATOR_SERVICE)).vibrate(VIBRATION_TIME);
}
RingtoneManager.getRingtone(this, Uri.parse(sharedPref.getRingtone())).play();
if (remoteMessage.getData().size() > 0) {
Map<String, String> data = remoteMessage.getData();
FcmNotif fcmNotif = new FcmNotif();
fcmNotif.setTitle(data.get("title"));
fcmNotif.setContent(data.get("content"));
fcmNotif.setPost_id(Integer.parseInt(data.get("post_id")));
displayNotificationIntent(fcmNotif);
}
}
}
private void displayNotificationIntent(FcmNotif fcmNotif) {
Intent intent = new Intent(this, ActivitySplash.class);
if (fcmNotif.getPost_id() != -1) {
intent = new Intent(this, ActivityPostDetails.class);
Post post = new Post();
post.title = fcmNotif.getTitle();
post.id = fcmNotif.getPost_id();
boolean from_notif = !ActivityMain.active;
intent.putExtra(ActivityPostDetails.EXTRA_OBJC, post);
intent.putExtra(ActivityPostDetails.EXTRA_NOTIF, from_notif);
}
PendingIntent pendingIntent = PendingIntent.getActivity(this, (int) System.currentTimeMillis(), intent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setContentTitle(fcmNotif.getTitle());
builder.setStyle(new NotificationCompat.BigTextStyle().bigText(fcmNotif.getContent()));
builder.setContentText(fcmNotif.getContent());
builder.setSmallIcon(R.drawable.ic_notification);
builder.setDefaults(Notification.DEFAULT_LIGHTS);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
builder.setPriority(Notification.PRIORITY_HIGH);
}
builder.setContentIntent(pendingIntent);
builder.setAutoCancel(true);
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
int unique_id = (int) System.currentTimeMillis();
notificationManager.notify(unique_id, builder.build());
}
}
yes you can store the your Notification payload in database and create list in fragment and show data from Database and click on any row start activity according to Post ID by getting post id by position
You can save notification message when the notificaton arrived inside
onMessageReceived(RemoteMessage remoteMessage)
method like this
A full example of a notification is like this..
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
/**
* Called when message is received.
*
* #param remoteMessage Object representing the message received from Firebase Cloud Messaging.
*/
// [START receive_message]
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
try {
// [START_EXCLUDE]
// There are two types of messages data messages and notification messages. Data messages are handled
// here in onMessageReceived whether the app is in the foreground or background. Data messages are the type
// traditionally used with GCM. Notification messages are only received here in onMessageReceived when the app
// is in the foreground. When the app is in the background an automatically generated notification is displayed.
// When the user taps on the notification they are returned to the app. Messages containing both notification
// and data payloads are treated as notification messages. The Firebase console always sends notification
// messages. For more see: https://firebase.google.com/docs/cloud-messaging/concept-options
// [END_EXCLUDE]
// TODO(developer): Handle FCM messages here.
Map<String, String> data = remoteMessage.getData();
String value1 = data.get("key_1");
String value2 = data.get("key_2");
String title=data.get("title");
String msg=data.get("body");
Log.d("Backgraound", value1);
Log.d(TAG, "From: " + remoteMessage.getFrom());
// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
}
// Check if message contains a notification payload.
if (remoteMessage.getNotification() != null) {
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
}
// Also if you intend on generating your own notifications as a result of a received FCM
// message, here is where that should be initiated. See sendNotification method below.
sendNotification(title,msg,value1,value2);
}catch (Exception e){
Log.d("Error Line Number",Log.getStackTraceString(e));
}
}
private void sendNotification(String title,String messageBody, String val1,String val2) {
try {
Intent intent = new Intent(this, Notification_activity.class);
//Bundle bundle = getApplicationContext().getExtras();
Bundle basket = new Bundle();
basket.putString("key_1", val1);
basket.putString("key_2", val2);
intent.putExtras(basket);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
String channelId = getString(R.string.default_notification_channel_id);
Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.spacebar_round)
.setContentTitle(title)
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent)
.setColor( getResources().getColor(R.color.colorPrimary))
.setLargeIcon(BitmapFactory.decodeResource(getApplicationContext().getResources(),
R.mipmap.ic_launcher));
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// Since android Oreo notification channel is needed.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(channelId,
"Channel human readable title",
NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channel);
}
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}catch (Exception e){
Log.d("Error Line Number",Log.getStackTraceString(e));
}
}
}
I check it many times using Logs and prevent the notify() method of manager to be called multiple times if not necessary to avoid some overhead. Now I have first notification with a 0% progress then again I create a new notification with a 0% progress again, unfortunately only one notification is shown even their id is unique but later on when the first notification progress gets updated example from 0% to 25% then that's the only time it will show the desired output, a 2 notification with different progress value. I am using only one Notification, Notification Manager, and in Notification Builder since I do not want to create an overlap animation of notification when it gets updated. Is this expected behavior when in the foreground?
public abstract class BaseTaskService extends Service {
private static final String TAG = "BaseTaskService";
private static final String CHANNEL_ID_DEFAULT = "Upload and Download";
private int queue = 0;
private FirebaseFirestore mDatabase;
private final List<Integer> listOfTaskID = new ArrayList<>();
private final SparseIntArray totalUnitList = new SparseIntArray();
private final SparseIntArray completedUnitList = new SparseIntArray();
private Notification notification;
private NotificationManager notificationManager;
private final NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, CHANNEL_ID_DEFAULT);
public void taskStarted(int id, boolean isUpload) {
//Increase the number of task
changeNumberOfTasks(1);
//Check if the task is new or not, if new then start a foreground service using id for it and add it to the list
if (!listOfTaskID.contains(id)){
listOfTaskID.add(id);
startForeground(id, notification);
Log.d(TAG, "Foreground Task Created : ID = " + id);
}
//If called by Upload Service, start the service once as a foreground per post
//If called by Download Service, start the service once as a foreground per file
if (isUpload){
//Set a total unit of files per post since one post could incorporate numerous images or files
totalUnitList.append(id, totalUnitList.get(id, 0) + 1);
Log.d(TAG, "Total Units For " + id + ": (" + totalUnitList.get(id) + ")");
}
}
public void taskCompleted() {
changeNumberOfTasks(-1);
}
private synchronized void changeNumberOfTasks(int delta) {
//Update the queue by adding delta value which could be 1 or -1
//Queue will display the overall upload or download of file from different tasks
queue += delta;
Log.d(TAG, "Overall Number of Remaining Task: " + queue);
//If there are no tasks left in queue, stop the service :)
if (queue <= 0) {
Log.d(TAG, "Stopping...");
//In Upload Service if there is no task in our queue it means that all request was finished
//so we need to reset the list of post's total task and completed task to zero
totalUnitList.clear();
completedUnitList.clear();
//Clear all of the id task
listOfTaskID.clear();
//Stop the foreground and remove all notification
stopForeground(true);
//Stop this service, calling this method will dismiss the very recent notification.
stopSelf();
}
}
#Override
public void onCreate() {
super.onCreate();
mDatabase = FirebaseFirestore.getInstance();
if (!isNotificationChannelEnabled(CHANNEL_ID_DEFAULT))
Toast.makeText(this, "Please turn on the notification in the app settings.", Toast.LENGTH_SHORT).show();
}
/*
We could use this line but unfortunately it will no longer work on Android O and above so we'll use the hashcode below.
This line is suppose to use for separating/detaching the Foreground notification from a Service
so that generating a separated unique id for PendingIntent and Finished notification is no longer needed.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
stopForeground(STOP_FOREGROUND_DETACH);
else
ServiceCompat.stopForeground(this, STOP_FOREGROUND_DETACH);
*/
//For Android O and above
private void createDefaultChannel() {
// Since Android Oreo notification channel is needed.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//If null then initialize the Notification Manager
if (notificationManager == null)
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channel = new NotificationChannel(CHANNEL_ID_DEFAULT,
"Upload and Download",
NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channel);
}
}
public boolean isNotificationChannelEnabled(String channelId){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if(channelId != null) {
NotificationManager manager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channel = manager.getNotificationChannel(channelId);
return channel.getImportance() != NotificationManager.IMPORTANCE_NONE;
}
return false;
} else {
return NotificationManagerCompat.from(this).areNotificationsEnabled();
}
}
/**
* Show notification with a progress bar.
* Updating the progress happens here
* This is for DOWNLOAD SERVICE
*/
void showProgressNotification(String caption, long completedUnits, long totalUnits, int id) {
createDefaultChannel();
//If null then initialize the Notification Manager
if (notificationManager == null)
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
//Compute the progress
int percentComplete = 0;
if (totalUnits > 0) {
percentComplete = (int) (100 * completedUnits / totalUnits);
}
//To update and separate the notification progress according to its task
notification = notificationBuilder
.setProgress(100, percentComplete, false)
.setContentInfo(String.valueOf(percentComplete +"%"))
.setSmallIcon(R.drawable.ic_file_upload_white_24dp)
.setContentTitle(getString(R.string.app_name))
.setContentText(caption)
.setAutoCancel(false)
.setOngoing(true)
.build();
if (!listOfTaskID.contains(id))
Log.d(TAG, "Download Notification Created: ID = " + id);
else
Log.d(TAG, "Download Notification Updated: ID = " + id);
//Notify the manager that we have a new update with notification
notificationManager.notify(id, notification);
}
/**
* Show notification with a progress bar.
* Updating the progress happens here
* This is for UPLOAD SERVICE
*/
void showProgressNotification(String caption, final String path, final int id, boolean isComplete, String title, String desc) {
createDefaultChannel();
//If null then initialize the Notification Manager
if (notificationManager == null)
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
//Increment only if it is a successful task
if (isComplete)
completedUnitList.append(id, completedUnitList.get(id,0) + 1);
//Update and compute the progress
double percentComplete = 0;
if (totalUnitList.get(id, 0) > 0) {
//Perform this line if and only the total task is not equal to zero since dividing a number by zero is Error
percentComplete = (100 / totalUnitList.get(id)) * completedUnitList.get(id, 0);
}
notification = notificationBuilder
.setProgress(100, (int) percentComplete, false)
.setContentInfo(String.valueOf((int) percentComplete +"%"))
.setSmallIcon(R.drawable.ic_file_upload_white_24dp)
.setContentTitle(getString(R.string.app_name))
.setContentText(caption)
.setAutoCancel(false)
.setOngoing(true)
.build();
//This if condition is use to avoid repetitive call of notify() and will be triggered only if new task is created
if (!isComplete && !listOfTaskID.contains(id)){
Log.d(TAG, "Upload Notification Created: ID = " + id);
//Notify the manager that we have a new notification
notificationManager.notify(id, notification);
}
else if (isComplete){
Log.d(TAG, "Upload Notification Updated: ID = " + id);
//Notify the manager that we have a new update with notification
notificationManager.notify(id, notification);
//Check now if the number of completed task is equal to the number of total task if yes then show a finish notification
if (completedUnitList.get(id) == totalUnitList.get(id)){
Map<String, Object> details = new HashMap<>();
details.put(getResources().getString(R.string.Description), desc);
//We will use milliseconds to calculate how long is the post and for query
details.put(getResources().getString(R.string.Time_Posted), String.valueOf(new Date().getTime()));
details.put(getResources().getString(R.string.file), true);
if (title != null){
details.put(getResources().getString(R.string.Title),title);
details.put(getResources().getString(R.string.SU).toLowerCase(), Objects.requireNonNull(FirebaseAuth.getInstance().getCurrentUser()).getUid());
}
else
details.put(getResources().getString(R.string.uid), Objects.requireNonNull(FirebaseAuth.getInstance().getCurrentUser()).getUid());
//Make Intent to MainActivity
final Intent intent = new Intent(BaseTaskService.this, SUMain.class)
.putExtra(UploadService.DATA_COLLECTION, path)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
mDatabase.document(path).set(details).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
showFinishedNotification(getString(R.string.upload_success), intent, true, id, true);
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
showFinishedNotification(getString(R.string.upload_failure), intent, false, id, true);
}
});
}
}
}
/**
* Show notification that the activity finished.
*/
void showFinishedNotification(String caption, Intent intent, boolean isSuccess, int id, boolean isUpload) {
createDefaultChannel();
//Since calling a stopSelf() method will kill the service itself and dismissed the very recent Finished notification which is wrong in our case.
//Create a new id for Finished notification that is not bounded from the id of the progress notification, service, and foreground.
String uri = isUpload ? String.valueOf(intent.getParcelableExtra(UploadService.FILE_URI)) : String.valueOf(intent.getParcelableExtra(DownloadService.DOWNLOAD_URI));
//Use the hashcode of current timestamp mixed with some string to make it unique.
int newID = (uri + System.currentTimeMillis()).hashCode();
//Make PendingIntent for notification with the new generated unique id
PendingIntent pendingIntent = PendingIntent.getActivity(this, newID, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
int icon = isSuccess ? R.drawable.ic_done : R.drawable.ic_error_white_24dp;
notification = notificationBuilder
.setProgress(0, 0, false)
.setContentTitle(getString(R.string.app_name))
.setContentIntent(pendingIntent)
.setContentText(caption)
.setContentInfo(null)
.setAutoCancel(true)
.setSmallIcon(icon)
.setOngoing(false)
.build();
//Remove the first notification that has a incremental id which is the notification with progress
notificationManager.cancel(id);
//Show a new notification after removing the progress notification with the new generated unique id
notificationManager.notify(newID, notification);
Log.d(TAG, "Finished Notification: ID = " + newID);
}}
I am developing an Android application in which I would like to receive a Push notification when application state is both in Foreground and Background.
It was working fine before the click_action is added but after adding it does not make the push notification received when the application is background or killed. After some research, I could understand that I will not be able to receive the Push in Background if the FCM is "notification" message type but only "data" message type.
As FCM provides click_action attribute by default and also provides the method getClickAction() to get it in onMessageReceived(), Should I really use click_action in data message ?
The bundle in onMessageReceived
Bundle[{
google.sent_time = 1521177008895,
google.ttl = 3600,
gcm.notification.e = 1,
lastName = Test,
profileUrl = ,
roleId = ,
userId = 140128,
gcm.notification.badge = 1,
gcm.notification.sound =
default,
gcm.notification.title = Someone
try to login with your credentials,
roleName = ,
userName = test,
flag = 0,
from = 612005318045,
type = 0,
gcm.notification.sound2 = simpleSound,
firstName = Test,
gcm.notification.notification_id = 1140,
google.message_id = 0: 1521177008900292 % c05b1316c05b1316,
notification = Someone
try to login with your credentials,
gcm.notification.body = Someone
try to login with your credentials,
gcm.notification.icon = myApp,
notificationId = 2047669,
gcm.notification.notification_type = 1,
gcm.notification.click_action = com.my.push.activities.OPEN_NOTIFICATION_LIST,
gcm.notification.notification_message = TEST MESSAGE,
notificationDate = Fri Mar 16 05: 10: 08 GMT 2018,
collapse_key = com.my.push,
gcm.notification.notification_title = APP
}]
The code snippet of the way it is handled in onMessageReceived
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
......
......
showNotification(remoteMessage);
}
public void showNotification(RemoteMessage remoteMessage) {
try {
Map<String, String> response = remoteMessage.getData();
Intent intent = prepareIntent(remoteMessage);
PendingIntent pIntent = PendingIntent.getActivity(this, 0,
intent, PendingIntent.FLAG_ONE_SHOT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "D4E_ANDROID")
.setContentTitle("New Notification")
.setContentText(response.get("notification"))
.setSmallIcon(R.drawable.d4e_logo)
.setContentIntent(pIntent)
.setAutoCancel(true)
.addAction(R.drawable.view_icon, "View", pIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(Integer.parseInt(response.get("notificationId")), builder.build());
} catch (Exception exception) {
Log.e("OnREC", exception.toString());
}
}
public Intent prepareIntent(RemoteMessage remoteMessage) {
Map<String, String> response = remoteMessage.getData();
Intent intent;
boolean isAppInBackground;
if (SessionContext.isLoggedIn()) {
isAppInBackground = SessionHelper.initializeSessionHelper().isAppInBackground(this);
Log.e("LOGGGGG", isAppInBackground + "");
if (isAppInBackground) {
intent = new Intent(this, SplashScreen.class);
} else {
intent = new Intent(remoteMessage.getNotification().getClickAction());
}
}
} else {
intent = new Intent(this, LoginActivity.class);
}
return intent;
}
Please anyone guide me to find the solution.
if you can receive FCM notification sent through console, then potentially something is wrong with build the notification. one suspect is that you are not using "icon" field.
If you can debug android device, set breakpoint here and see if you get error or missed some resource.
https://github.com/evollu/react-native-fcm/blob/master/android/src/main/java/com/evollu/react/fcm/SendNotificationTask.java#L46
I am using FCM in my android project and is working fine when app is running. But when the app is killed or closed onReceiveMessage is not called. I have tried by sending message using only data playload also still it is not working. Is there any any solution. Thanks in advance
Try this code it will solve your problem. MyFirebaseMessagingService.java
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
/**
* Called when message is received.
*
* #param remoteMessage Object representing the message received from Firebase Cloud Messaging.
*/
// [START receive_message]
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// If the application is in the foreground handle both data and notification messages here.
// Also if you intend on generating your own notifications as a result of a received FCM
// message, here is where that should be initiated. See sendNotification method below.
Log.d(TAG, "From: " + remoteMessage.getFrom());
Log.d(TAG, "Notification Message Title: " + remoteMessage.getNotification().getTitle());
Log.d(TAG, "Notification Message Body: " + remoteMessage.getNotification().getBody());
sendNotification("", "");
}
// [END receive_message]
/**
* Create and show a simple notification containing the received FCM message.
*
* #param messageBody FCM message body received.
*/
private void sendNotification(String xyz, String abc) {
Intent intent = new Intent(this, MainActivity.class);
Bundle b = new Bundle();
b.putString("key", xyz);
b.putString("key", abc);
intent.putExtras(b);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setContentTitle("title")
.setContentText("body")
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
boolean useSilhouette = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
if (useSilhouette) {
try {
notificationBuilder.setSmallIcon(R.mipmap.ic_sillate);
} catch (Exception e) {
notificationBuilder.setSmallIcon(R.mipmap.ic_sillate);
}
} else {
notificationBuilder.setSmallIcon(R.mipmap.ic_launcher);
}
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
//Random id number for notification
Random random = new Random();
int m = random.nextInt(9999 - 1000) + 1000;
notificationManager.notify(m/* ID of notification */, notificationBuilder.build());
}
}
Get values via getIntent() in MainActivity and do what you want to do ;)
GcmListenerService is not called when application is in background or when phone is locked or in sleep mode but notification is fired. How this will be called
When App is in foreground its working ideally.
Code for GcmListenerService is following
public class MyGcmListenerService extends GcmListenerService {
private static final String TAG = "MyGcmListenerService";
LocalDataBaseManager mDbManager;
String message;
Random randomNumber;
long ID;
/**
* Called when message is received.
*
* #param from SenderID of the sender.
* #param data Data bundle containing message data as key/value pairs.
* For Set of keys use data.keySet().
*/
// [START receive_message]
#Override
public void onMessageReceived(String from, Bundle data) {
String message ;
String title;
// ID = Utils.getIDForPush("pushId",this);
// if(ID == 0){
// ID = 1;
// }else {
// ID += 1;
// }
// Utils.saveIDForPush("pushId",ID,this);
Bundle bundle = data.getBundle("notification");
if(bundle!= null){
message = bundle.getString("body");
title = bundle.getString("title");
Log.d(TAG, "From: " + from);
Log.d(TAG, "Message: " + message);}
else {
message ="";
title = "NCMS";
}
mDbManager = LocalDataBaseManager.getInstance(this);
if (from.startsWith("/topics/")) {
Calendar c = Calendar.getInstance();
SimpleDateFormat s = new SimpleDateFormat("ddMMyyyyhhmmss");
String format = s.format(new Date());
ID = Long.parseLong(format);
String date = new SimpleDateFormat("dd-MM-yyyy HH:mm", Locale.ENGLISH).format(new Date());
Warnings warnings = new Warnings();
warnings.setWARNING_ID(ID);
warnings.setWARNING_EN(message);
warnings.setWARNING_AR(message);
warnings.setSTART_DATE_TIME(date);
warnings.setNotification_type(String.valueOf(Constant.NotificationType.PUSH));
warnings.setSEVERITY("");
warnings.setEND_DATE_TIME("");
warnings.setUPDATE_NO("");
mDbManager.insertNotificationInfo(warnings);
// message received from some topic.
} else {
// normal downstream message.
}
// [START_EXCLUDE]
/**
* Production applications would usually process the message here.
* Eg: - Syncing with server.
* - Store message in local database.
* - Update UI.
*/
/**
* In some cases it may be useful to show a notification indicating to the user
* that a message was received.
*/
// KeyguardManager km = (KeyguardManager) this.getSystemService(Context.KEYGUARD_SERVICE);
// boolean locked = km.inKeyguardRestrictedInputMode();
//
// String release = android.os.Build.VERSION.RELEASE;
//
//
// if (Integer.parseInt(String.valueOf(release.charAt(0))) < 5 && locked) {
//
// this.stopService(new Intent(this, NotificationService.class));
// Intent serviceIntent = new Intent(this, NotificationService.class);
// this.startService(serviceIntent);
//
// }
sendNotification(title,message);
// [END_EXCLUDE]
}
// [END receive_message]
/**
* Create and show a simple notification containing the received GCM message.
*
* #param message GCM message received.
*/
private void sendNotification(String title,String message) {
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("message",message);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ncms_launcher)
.setContentTitle(title)
.setContentText(message)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}
}
Manifest info for this service is following
<service
android:name=".gcm.MyGcmListenerService"
android:exported="false" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
What I am missing here.
It appears the heart of this issue is actually a server-side issue. If the server is sending notification messages, onMessageReceived won't be called if the app is in the background. The server should actually be sending data messages.
GCM Docs discuss the difference.
Basically, the payload of the message should have a data key such as
{
"to" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"data" : {
"Nick" : "Mario",
"body" : "great match!",
"Room" : "PortugalVSDenmark"
},
}
and NOT a notification key such as
{
"to" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"notification" : {
"body" : "great match!",
"title" : "Portugal vs. Denmark",
"icon" : "myicon"
}
}
More specifically, the GCM Docs state that messages sent including both data and notification payloads will be treated differently depending on if the app is in the foreground or background:
App behavior when receiving messages that include both notification and data payloads depends on whether the app is in the background, or the foreground —essentially, whether or not it is active at the time of receipt.
When in the background, apps receive the notification payload in the notification tray, and only handle the data payload when the user taps on the notification.
When in the foreground, your app receives a bundle with both payloads available.
This github thread also has a good explanation:
So there are two kinds of GCM messages:
Notification Messages - these are intended to generate a notification with no intermediate processing by the application. They only hit onMessageReceived if the app is running.
Data Messages - these are intended to silently pass data to the app's messaging service. They hit onMessageReceived even if the app is in the background. The service may then choose to generate a notification using the normal system notification APIs, or it may choose to handle the message silently.
The Issue I was facing was when Application is in background or force closed then notification is fired but not through GcmListenService but through GCMReceiver
So I extended GCMReceiver and made it something like this with this when application is in foreground or in background or force killed. it will be called
GCMListenerService after modification is as following
public class MyGcmListenerService extends GcmListenerService {
private static final String TAG = "MyGcmListenerService";
LocalDataBaseManager mDbManager;
String message;
Random randomNumber;
long ID;
/**
* Called when message is received.
*
* #param from SenderID of the sender.
* #param data Data bundle containing message data as key/value pairs.
* For Set of keys use data.keySet().
*/
// [START receive_message]
#Override
public void onMessageReceived(String from, Bundle data) {
String message ;
String title;
// ID = Utils.getIDForPush("pushId",this);
// if(ID == 0){
// ID = 1;
// }else {
// ID += 1;
// }
// Utils.saveIDForPush("pushId",ID,this);
Bundle bundle = data.getBundle("notification");
if(bundle!= null){
message = bundle.getString("body");
title = bundle.getString("title");
Log.d(TAG, "From: " + from);
Log.d(TAG, "Message: " + message);}
else {
message ="";
title = "NCMS";
}
mDbManager = LocalDataBaseManager.getInstance(this);
if (from.startsWith("/topics/")) {
Calendar c = Calendar.getInstance();
SimpleDateFormat s = new SimpleDateFormat("ddMMyyyyhhmmss");
String format = s.format(new Date());
ID = Long.parseLong(format);
String date = new SimpleDateFormat("dd-MM-yyyy HH:mm", Locale.ENGLISH).format(new Date());
Warnings warnings = new Warnings();
warnings.setWARNING_ID(ID);
warnings.setWARNING_EN(message);
warnings.setWARNING_AR(message);
warnings.setSTART_DATE_TIME(date);
warnings.setNotification_type(String.valueOf(Constant.NotificationType.PUSH));
warnings.setSEVERITY("");
warnings.setEND_DATE_TIME("");
warnings.setUPDATE_NO("");
mDbManager.insertNotificationInfo(warnings);
// message received from some topic.
} else {
// normal downstream message.
}
// [START_EXCLUDE]
/**
* Production applications would usually process the message here.
* Eg: - Syncing with server.
* - Store message in local database.
* - Update UI.
*/
/**
* In some cases it may be useful to show a notification indicating to the user
* that a message was received.
*/
// KeyguardManager km = (KeyguardManager) this.getSystemService(Context.KEYGUARD_SERVICE);
// boolean locked = km.inKeyguardRestrictedInputMode();
//
// String release = android.os.Build.VERSION.RELEASE;
//
//
// if (Integer.parseInt(String.valueOf(release.charAt(0))) < 5 && locked) {
//
// this.stopService(new Intent(this, NotificationService.class));
// Intent serviceIntent = new Intent(this, NotificationService.class);
// this.startService(serviceIntent);
//
// }
sendNotification(title,message);
// [END_EXCLUDE]
}
// [END receive_message]
/**
* Create and show a simple notification containing the received GCM message.
*
* #param message GCM message received.
*/
private void sendNotification(String title,String message) {
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("message",message);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ncms_launcher)
.setContentTitle(title)
.setContentText(message)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}
}
and GCM Receiver is as following
public class GcmBroadcastReceiver extends GcmReceiver {
LocalDataBaseManager mDbManager;
#Override
public void onReceive(Context context, Intent intent) {
mDbManager = LocalDataBaseManager.getInstance(context);
Bundle bundle = intent.getExtras();
bundle.keySet();
Set<String> keySet = bundle.keySet();
if(keySet != null && keySet.isEmpty() == false) {
Iterator<String> it = keySet.iterator();
int i = 0;
while(it.hasNext()){
String key = it.next();
String desc = bundle.getString(key);
Log.d("BroadCast Values",key +" "+desc);
}
}
Log.d("", "In Receive Method of Broadcast Receiver");
if (bundle != null && bundle.containsKey("gcm.notification.body")) {
String message = bundle.getString("gcm.notification.body","");
Long ID = new Date().getTime();
String date = new SimpleDateFormat("dd-MM-yyyy HH:mm", Locale.ENGLISH).format(new Date());
Warnings warnings = new Warnings();
warnings.setWARNING_ID(ID);
warnings.setWARNING_EN(message);
warnings.setWARNING_AR(message);
warnings.setSTART_DATE_TIME(date);
warnings.setNotification_type(String.valueOf(Constant.NotificationType.PUSH));
warnings.setSEVERITY("");
warnings.setEND_DATE_TIME("");
warnings.setUPDATE_NO("");
mDbManager.insertNotificationInfo(warnings);
// message received from some topic.
}
super.onReceive(context, intent);
// ComponentName cn = new ComponentName(context.getPackageName(), RegistrationIntentService.class.getName());
// startWakefulService(context, intent.setComponent(cn));
// setResultCode(Activity.RESULT_OK);
}
}
Manifest changes for GCMReceiver is following
<receiver
android:name=".gcm.GcmBroadcastReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.uae.ncms" />
</intent-filter>
</receiver>
<service
android:name=".gcm.MyGcmListenerService"
android:exported="false" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>