I am working with Firebase to send notifications to a user. I am able to send a basic notification perfectly fine. However, I am having trouble with turning that notification into a heads up notification. I have tried multiple solutions from StackOverflow, but none of them have worked with me.
Below is the respective class I have for receiving push notifications.
public class MyFirebaseMessagingService extends FirebaseMessagingService {
#Override
public void onMessageReceived(RemoteMessage message) {
super.onMessageReceived(message);
NotificationManager mNotificationManager = getSystemService(NotificationManager.class);
NotificationChannel channel = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
channel = new NotificationChannel("channel",
"Channel description",
NotificationManager.IMPORTANCE_HIGH);
mNotificationManager.createNotificationChannel(channel);
}
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(getApplicationContext(), "channel")
.setSmallIcon(R.drawable.googleg_standard_color_18)
.setContentTitle(message.getNotification().getTitle())
.setContentText(message.getNotification().getBody())
.setDefaults(Notification.DEFAULT_ALL)
.setPriority(Notification.PRIORITY_HIGH);
mNotificationManager.notify(0, mBuilder.build());
}
}
You should add your listener service, as you would in a standard GCM implementation.
public class MyGcmListenerService extends GcmListenerService {
private static final String TAG = "MyGcmListenerService";
/**
* 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 = data.getString("message");
Log.d(TAG, "From: " + from);
Log.d(TAG, "Message: " + message);
if (from.startsWith("/topics/")) {
// 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.
*/
sendNotification(message);
// [END_EXCLUDE]
}
// [END receive_message]
Run code snippetExpand snippet
Then, register your receiver in AndroidManifest.xml tag to listen on incoming notifications:
<!-- [START gcm_listener] -->
<service
android:name="gcm.play.android.samples.com.gcmquickstart.MyGcmListenerService"
android:exported="false" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
<!-- [END gcm_listener] -->
This way - you won't have to handle incoming messages separately for cases when app is in foreground vs background.
Related
I am trying to integrate Firebase Cloud Messaging into my Android Studio project. I began by going to tools, clicking Firebase, going to Cloud Messaging, and then clicking "Connect your app to Firebase" and "Add FCM to your App". Both processes went without a hitch, but the problem came up later. When I was following step 3, there were two blocks of code that we were supposed to integrate. The first block was supposed to be a service that extends FirebaseMessagingService. The second block was a dependency that was supposed to be placed in the manifest. These are the two blocks respectively:
The problem is that the service file is returning the error "Cannot resolve method 'scheduleJob()'", 'handleNow()', and 'sendRegistrationToServer(token)'
I suspected that new methods had to be created, but these methods were supposed to draw from the parent class (I think). I have not clicked the suggestion to create the new methods because I was uncertain whether there would be any functionality.
The first set of code below is the file I made by doing
File->New->Service->Service.
I named the file "MyFirebaseMessagingService". The second set of code is my manifest.
package com.example.piggybank_v3;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
import static androidx.constraintlayout.widget.Constraints.TAG;
public class MyFirebaseMessagingService extends FirebaseMessagingService {
public MyFirebaseMessagingService() {
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// ...
// TODO(developer): Handle FCM messages here.
// Not getting messages here? See why this may be:
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());
if (/* Check if data needs to be processed by long running job */ true) {
// For long-running tasks (10 seconds or more) use Firebase Job Dispatcher.
scheduleJob();
} else {
// Handle message within 10 seconds
handleNow();
}
}
// 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.
}
/**
* Called if InstanceID token is updated. This may occur if the security of
* the previous token had been compromised. Note that this is called when the InstanceID token
* is initially generated so this is where you would retrieve the token.
*/
#Override
public void onNewToken(String token) {
Log.d(TAG, "Refreshed token: " + token);
// If you want to send messages to this application instance or
// manage this apps subscriptions on the server side, send the
// Instance ID token to your app server.
sendRegistrationToServer(token);
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
<service
android:name=".MyFirebaseMessagingService"
android:enabled="true"
android:exported="true"></service>
<service android:name=".java.MyFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
The ideal result is that the project should sync when running, but it returns these errors: "Cannot resolve method 'scheduleJob()'", 'handleNow()', and 'sendRegistrationToServer(token)'
This is how service class work to receive notification message. So you've to edit your event in it then it'll works fine.
Firebase cloud message demo's are provided on github so can download it and can change firebase keys and package name to test it.
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import androidx.core.app.NotificationCompat;
import android.util.Log;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
import com.google.firebase.quickstart.fcm.R;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
// [START receive_message]
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
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());
if (/* Check if data needs to be processed by long running job */ true) {
// For long-running tasks (10 seconds or more) use WorkManager.
scheduleJob();
} else {
// Handle message within 10 seconds
handleNow();
}
}
// 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.
}
// [END receive_message]
// [START on_new_token]
/**
* Called if InstanceID token is updated. This may occur if the security of
* the previous token had been compromised. Note that this is called when the InstanceID token
* is initially generated so this is where you would retrieve the token.
*/
#Override
public void onNewToken(String token) {
Log.d(TAG, "Refreshed token: " + token);
// If you want to send messages to this application instance or
// manage this apps subscriptions on the server side, send the
// Instance ID token to your app server.
sendRegistrationToServer(token);
}
// [END on_new_token]
/**
* Schedule async work using WorkManager.
*/
private void scheduleJob() {
// [START dispatch_job]
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(MyWorker.class)
.build();
WorkManager.getInstance().beginWith(work).enqueue();
// [END dispatch_job]
}
/**
* Handle time allotted to BroadcastReceivers.
*/
private void handleNow() {
Log.d(TAG, "Short lived task is done.");
}
/**
* Persist token to third-party servers.
*
* Modify this method to associate the user's FCM InstanceID token with any server-side account
* maintained by your application.
*
* #param token The new token.
*/
private void sendRegistrationToServer(String token) {
// TODO: Implement this method to send token to your app server.
}
/**
* Create and show a simple notification containing the received FCM message.
*
* #param messageBody FCM message body received.
*/
private void sendNotification(String messageBody) {
Intent intent = new Intent(this, MainActivity.class);
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.ic_stat_ic_notification)
.setContentTitle(getString(R.string.fcm_message))
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
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());
}
}
Try this:
1.- Verify that the library is added in build.gradle:
implementation 'com.google.firebase: firebase-messaging: 19.0.1'
2.- As indicated, you must add the 'MyFirebaseMessagingService' service (previously created) to the AndroidManifest.xml and provide a default notification channel: (click here to learn more about the channels)
<service
android:name=".java.MyFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="#string/default_notification_channel_id" />
3.- Add the following in MainActivity.java to retrieve the current token when you need it:
FirebaseInstanceId.getInstance().getInstanceId()
.addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
#Override
public void onComplete(#NonNull Task<InstanceIdResult> task) {
if (!task.isSuccessful()) {
Log.w(TAG, "getInstanceId failed", task.getException());
return;
}
// Get new Instance ID token
String token = task.getResult().getToken();
// Log and toast
String msg = getString(R.string.msg_token_fmt, token);
Log.d(TAG, msg);
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
}
});
4.- Fill in the file '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.
*/
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// Check if message contains a data payload (beauty messages).
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
createAndSendNotificationB(remoteMessage);
}
// Check if message contains a notification payload (from console).
if (remoteMessage.getNotification() != null) {
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
createAndSendNotificationC(remoteMessage.getNotification().getBody());
}
}
private void createAndSendNotificationB(RemoteMessage remoteMessage){
//Code here
}
private void createAndSendNotificationC(String messageBody){
//Code here
}
}
With this it should work.
I have taken everything from the official documentation, I recommend you read it: https://firebase.google.com/docs/cloud-messaging/android/client
Update
onMessageReceived called in API 19 but not on 23 and 24.
Update
I am sending FCM notifications from a server, I can receive notifications but onMessageReceived is not called(foreground, background), even with data messages. This is the code I'm using.
import android.app.PendingIntent;
import android.content.Intent;
import android.util.Log;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
import uk.co.socktchat.socketchat.MainActivity;
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) {
// [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.
// Not getting messages here? See why this may be:
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());
if (/* Check if data needs to be processed by long running job */ true) {
// For long-running tasks (10 seconds or more) use Firebase Job Dispatcher.
scheduleJob();
} else {
// Handle message within 10 seconds
handleNow();
}
}
// 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.
}
// [END receive_message]
/**
* Schedule a job using FirebaseJobDispatcher.
*/
private void scheduleJob() {
// [START dispatch_job]
// [END dispatch_job]
}
/**
* Handle time allotted to BroadcastReceivers.
*/
private void handleNow() {
Log.d(TAG, "Short lived task is done.");
}
/**
* Create and show a simple notification containing the received FCM message.
*
* #param messageBody FCM message body received.
*/
private void sendNotification(String messageBody) {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
}
}
My Manifest file
<service
android:name=".fcm.MyFirebaseMessagingService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
<!-- [END firebase_service] -->
<!-- [START firebase_iid_service] -->
<service
android:name=".fcm.MyFirebaseInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
json im posting from server
{
"data": {
"title": "5x1",
"body": "15:10"
},
"to" : "d6IJZlXAUZ4:APA91bF8kB_jBn_N93otIdRFsu89ZDhrFsL--i0I4TmS-LO_h3QQ79lu6VlTQe0poNpuUni7N45_jw2XMli",
"priority" : "high",
"content_available" : true
}
I don't see anything wrong, I tried different versions of Android, thinking android version could be any reason, but didn't seem the find any problem. Any ideas? Thank you.
Check if message contains a notification payload.
if (remoteMessage.getNotification() != null) {
Log.e(TAG, "Notification Payload: " + remoteMessage.getNotification().getBody());
//handleNotification(remoteMessage.getNotification().getBody());
}
Check if message contains a data payload.
if (remoteMessage.getData().size() > 0){
Log.e(TAG, "Data Payload: " + remoteMessage.getData().toString());
handleNotification(remoteMessage.getData());
}
As per FCM document
Notification messages contain a predefined set of user-visible keys.
Data messages, by contrast, contain only your user-defined custom
key-value pairs. Notification messages can contain an optional data
payload. Maximum payload for both message types is 4KB, except when
sending messages from the Firebase console, which enforces a 1024
character limit.
check that your message size is within limit.
In fact onMessageReceived is being called the whole time, it is just that Logcat didn't show any messages, weird enough it happened only with devices of API 19 above, on a device with API 19 Logcat is showing the messages, I can't explain why this happened but my problem was solved.
I use FirebaseMessaging in an Android Application for an instant messaging.
For messages from server to device Android, there is no loss of message.
But from mobile to server some messages are lost...
The server receives the ACK messages, but in the other direction (mobile to server) the mobile does not receive the ACK.
The consequence is that 30% approximately of messages are lost. If I send multiple messages quickly, there will be more loss (40-60%). If I send multiple message slowly, there are 10% lost messages...
When I send messages mobile to server, I noticed that in my FirebaseMessagingService, the method "onMessageSent" is called by vague of 10 messages. Is it normal ?
Why "onMessageSent" is not called once as soon as message was sent...
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
/** constante pour renvoyer la position GPS */
public static final String BROADCAST_FIREBASE_FILTER= "android.intent.action.MY_APP_FIREBASE";
private DatabaseHelper helper;
#Override
public void onCreate() {
super.onCreate();
}
/**
* 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) {
Notification method below.
DebugLog.logw(TAG,"MESSAGE RECEIVED");
String clickAction = remoteMessage.getNotification().getClickAction();
[..]
}
// [END receive_message]
/**
* Create and show a simple notification containing the received FCM message.
*
* #param messageBody FCM message body received.
*/
private void sendNotification(String title, String messageBody,Intent intent2) {
intent2.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent2,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(title)
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}
#Override
public void onDeletedMessages() {
super.onDeletedMessages();
DebugLog.logi(TAG, "onDeletedMessages");
}
#Override
public void onMessageSent(String s) {
super.onMessageSent(s);
DebugLog.logi(TAG, "onMessageSent = " + s);
}
#Override
public void onSendError(String s, Exception e) {
super.onSendError(s, e);
DebugLog.logi(TAG, "onSendError = " + s);
}
}
My method in my FragmentMessaging for send an message :
public void sendMessage(Message msg){
DebugLog.logd("FragmentMessagerie","sendMessage msg = " + msg.getMsg());
if(textMessage.getText().length()>0) {
final Message message = msg;
AtomicInteger atomicInteger = new AtomicInteger();
FirebaseMessaging fm = FirebaseMessaging.getInstance();
RemoteMessage rm = new RemoteMessage.Builder(senderID)
.setMessageId("myApp_" + atomicInteger.incrementAndGet() + System.currentTimeMillis())
.addData("action", "chat")
.addData("destinataire", String.valueOf(contact.getId()))
.addData("emetteur",username)
.addData("texte",msg.getMsg())
.setTtl(0)
.build();
fm.send(rm); // appel à fireBase pour l'envoi du message
[..]
textMessage.setText("");
} else {
[..]
}
}
}
My questions are :
When sending a message (firebaseMessaging.send(remoteMessage)) Firebase is supposed to handle the sending of messages to server.
Is it Android that sends the messages incorrectly to Firebase ?
Or is it Firebase that sends the messages badly to my server ?
On the server, I receive the ACK messages sent to mobiles.
On my device Android, I don't receive the ACK message, only the method "onMessageSent" was called 10 times when 10 messages were sent... Is this normal ?
How can I receive ACK for messages device Android to server ? from my device ?
Thanks in advance for your help !
It clearly says in FCM documentation, that the response is batched.
To optimize network usage, FCM batches responses to onMessageSent and
onSendError, so the acknowledgement may not be immediate for each message.
I'm trying to send Firebase notification to a single device and for that I have retrieved the FCM registration token using the code below:
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
private static final String TAG = "MyFirebaseIIDService";
/**
* Called if InstanceID token is updated. This may occur if the security of
* the previous token had been compromised. Note that this is called when the InstanceID token
* is initially generated so this is where you would retrieve the token.
*/
// [START refresh_token]
#Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.d(TAG, "Refreshed token: " + refreshedToken);
// TODO: Implement this method to send any registration to your app's servers.
sendRegistrationToServer(refreshedToken);
}
// [END refresh_token]
/**
* Persist token to third-party servers.
*
* Modify this method to associate the user's FCM InstanceID token with any server-side account
* maintained by your application.
*
* #param token The new token.
*/
private void sendRegistrationToServer(String token) {
// Add custom implementation, as needed.
}
}
Here is MyFirebaseMessagingService.java file's code:
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) {
// TODO(developer): Handle FCM messages here.
// 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 Body: " + remoteMessage.getNotification().getBody());
sendNotification(remoteMessage.getNotification().getBody());
}
// [END receive_message]
/**
* Create and show a simple notification containing the received FCM message.
*
* #param messageBody FCM message body received.
*/
public void sendNotification(String messageBody) {
Intent intent = new Intent(this, SettingsActivity.class);
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.mipmap.ic_launcher)
.setContentTitle("FCM Message")
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}
}
The problem is that when I'm trying to send Firebase notification while the app is still on screen, it is crashing giving this error multiple times: java.lang.IllegalArgumentException: URI: content://com.android.contacts/phone_lookup/?encrypt=%20%3C%202, calling user: com.android.mms:10015, calling package:com.android.mms
I really don't know what's going wrong here!
Please let me know.
Try Debugging your onMessageReceived(), you must be getting remoteMessage.getNotification() = null if you are not sending a notification block in your push:
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d(TAG, "From: " + remoteMessage.getFrom());
// Check if remoteMessage.getNotification() == null ??
Log.d(TAG, "Notification Message Body: " + remoteMessage.getNotification().getBody());
sendNotification(remoteMessage.getNotification().getBody());
}
Also update your question with full error log.
Just make sure that the line "apply plugin: 'com.google.gms.google-services'" in your app's build.gradle lies at the very bottom of build.gradle file. Otherwise the app may crash when a message is being received.
I've tried using Google GCM but when the app is closed (Swipe or clear from the task manager), it wont receive any push notifications. And when i open the app again, the notification is already gone and lost.
GCM is working for:
- App is open
- App is minimized
Not working:
- App is closed (swipe from task manager)
- App is closed via clear all open apps in task manager
I want receive push notifications even though the app is closed just like Facebook or instagram. How can i achieve this?? Is this possible in GCM? if yes how? if no then what are the other way to achieve this??
here is my code:
AndroidManifest.xml
<!-- [START gcm_receiver] -->
<receiver
android:name="com.google.android.gms.gcm.GcmReceiver"
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.example.airwyntin.notificationtest" />
</intent-filter>
</receiver>
<!-- [END gcm_receiver] -->
<!-- [START gcm_listener] -->
<service
android:name=".MyGcmListenerService"
android:exported="false" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
<!-- [END gcm_listener] -->
<!-- [START instanceId_listener] -->
<service
android:name=".MyInstanceIDListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID"/>
</intent-filter>
</service>
<!-- [END instanceId_listener] -->
<service
android:name=".RegistrationIntentService"
android:exported="false">
</service>
MyGcmListenerService.java:
public class MyGcmListenerService extends GcmListenerService {
private static int notifId = 0;
private static final String TAG = "MyGcmListenerService";
/**
* 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 = data.getString("alert");
Log.i(TAG, "From: " + from);
if (message != null) {
Log.d(TAG, "From: " + from);
Log.d(TAG, "Message: " + message);
if (from.startsWith("/topics/")) {
// 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.
*/
sendNotification(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 message) {
Intent intent = new Intent(this, NotificationView.class);
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.mipmap.ic_launcher)
.setContentTitle("GCM Tesst Message")
.setContentText(message)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
//Vibration
notificationBuilder.setVibrate(new long[] { 0, 200, 200, 200, 200, 200 });
//LED
//notificationBuilder.setLights(Color.RED, 3000, 3000);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Notification notif = notificationBuilder.build();
notif.flags |= Notification.FLAG_AUTO_CANCEL;
/*notif.ledARGB = 0xFFff0000;
notif.flags = Notification.FLAG_SHOW_LIGHTS;
notif.ledOnMS = 100;
notif.ledOffMS = 100;*/
notificationManager.notify(notifId++ /* ID of notification */, notif);
}
}
MyInstanceIDListenerService.java:
public class MyInstanceIDListenerService extends InstanceIDListenerService {
private static final String TAG = "MyInstanceIDLS";
/**
* Called if InstanceID token is updated. This may occur if the security of
* the previous token had been compromised. This call is initiated by the
* InstanceID provider.
*/
// [START refresh_token]
#Override
public void onTokenRefresh() {
// Fetch updated Instance ID token and notify our app's server of any changes (if applicable).
Intent intent = new Intent(this, RegistrationIntentService.class);
startService(intent);
}
// [END refresh_token]
}
RegistrationIntentService.java:
public class RegistrationIntentService extends IntentService {
private static final String TAG = "RegIntentService";
private static final String[] TOPICS = {"global"};
public RegistrationIntentService() {
super(TAG);
}
#Override
protected void onHandleIntent(Intent intent) {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
try {
// [START register_for_gcm]
// Initially this call goes out to the network to retrieve the token, subsequent calls
// are local.
// R.string.gcm_defaultSenderId (the Sender ID) is typically derived from google-services.json.
// See https://developers.google.com/cloud-messaging/android/start for details on this file.
// [START get_token]
InstanceID instanceID = InstanceID.getInstance(this);
String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
// [END get_token]
Log.i(TAG, "GCM Registration Token: " + token);
// TODO: Implement this method to send any registration to your app's servers.
sendRegistrationToServer(token);
// Subscribe to topic channels
subscribeTopics(token);
// You should store a boolean that indicates whether the generated token has been
// sent to your server. If the boolean is false, send the token to your server,
// otherwise your server should have already received the token.
sharedPreferences.edit().putBoolean(QuickstartPreferences.SENT_TOKEN_TO_SERVER, true).apply();
// [END register_for_gcm]
} catch (Exception e) {
Log.d(TAG, "Failed to complete token refresh", e);
// If an exception happens while fetching the new token or updating our registration data
// on a third-party server, this ensures that we'll attempt the update at a later time.
sharedPreferences.edit().putBoolean(QuickstartPreferences.SENT_TOKEN_TO_SERVER, false).apply();
}
// Notify UI that registration has completed, so the progress indicator can be hidden.
Intent registrationComplete = new Intent(QuickstartPreferences.REGISTRATION_COMPLETE);
LocalBroadcastManager.getInstance(this).sendBroadcast(registrationComplete);
}
/**
* Persist registration to third-party servers.
*
* Modify this method to associate the user's GCM registration token with any server-side account
* maintained by your application.
*
* #param token The new token.
*/
private void sendRegistrationToServer(String token) {
// Add custom implementation, as needed.
}
/**
* Subscribe to any GCM topics of interest, as defined by the TOPICS constant.
*
* #param token GCM token
* #throws IOException if unable to reach the GCM PubSub service
*/
// [START subscribe_topics]
private void subscribeTopics(String token) throws IOException {
GcmPubSub pubSub = GcmPubSub.getInstance(this);
for (String topic : TOPICS) {
pubSub.subscribe(token, "/topics/" + topic, null);
}
}
// [END subscribe_topics]
}
As per the official statement of GCM it works with Google play services library so try to check if your mobile have the latest updates of Google play services installed also sometimes internet connectivity problem conject the network causes the problem with GCM push notification or else you can check for delivery receipt if receiver has really receive the message or not.
But what you say that GCM will not work when app is not in foreground is incorrect
When the app is closed forcefully by the user : notifications don't arrive
It's a feature of the Android platform. Force stopping an application by the user puts the application in a stopped state and none of its code is run, including any broadcast receivers declared in manifest. Only when the user explicitly launches the app it is put in a state where the receivers get fired.
For more documentation regarding Force Stop, please follow this links:
https://possiblemobile.com/2014/06/effects-android-application-termination/
https://developer.android.com/about/versions/android-3.1.html#launchcontrols
A simple solution for this problem is that, "set priority high while building your notification". Priority constant varies in the range from -2 to 2(lowest to highest) and 0 is default value for this field. Hope this will help. Thanks.