In my project, I'm using two libs to handle two different types of push notifications: Localytics and react-native-push-notification.
I have a custom FirebaseMessagingService that checks if it's a Localytics push then let the Localytics handle it via their provided methods. But if it's not a Localytics push, I need to pass this push data to react-native-push-notification's RNPushNotificationListenerService which is also a FirebaseMessagingService.
I'm attempting to start the RNPushNotificationListenerService but it doesn't seem to be starting because it never sends a push. I have tried setting breakpoints too but no luck.
AndroidManifest.xml
<!-- push notifications -->
<service android:name=".fcm.CustomFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationPublisher" />
<receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationBootEventReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationRegistrationService"/>
<service
android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<!-- push notifications end -->
CustomFirebaseMessagingService.java
public class CustomFirebaseMessagingService extends FirebaseMessagingService {
public CustomFirebaseMessagingService() {
super();
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Map<String, String> data = remoteMessage.getData();
try {
if (!Localytics.handleFirebaseMessage(data)) {
forwardPushNotification(remoteMessage);
}
} catch (Exception e) {
Timber.e(e, "Failed to extract Push Message", remoteMessage.getMessageId());
}
}
#Override
public void onDeletedMessages() {
super.onDeletedMessages();
}
#Override
public void onMessageSent(String msgId) {
super.onMessageSent(msgId);
}
#Override
public void onSendError(String msgId, Exception e) {
super.onSendError(msgId, e);
}
#Override
public void onNewToken(String token) {
super.onNewToken(token);
Localytics.setPushRegistrationId(token);
}
private void forwardPushNotification(RemoteMessage remoteMessage) {
Map<String, String> data = remoteMessage.getData();
data.put("from", remoteMessage.getFrom());
Intent intent = new Intent(this, RNPushNotificationListenerService.class);
Bundle extraData = new Bundle(data.size());
for (Map.Entry<String, String> entry : data.entrySet()) {
extraData.putString(entry.getKey(), entry.getValue());
}
intent.putExtras(extraData);
startService(intent);
}
}
I have a feeling I'm not starting the service correctly?
I am also aware that AndroidManifest will ignore the declaration of com.google.firebase.MESSAGING_EVENT for RNPushNotificationListenerService.
I have tried getting the individual libraries working without my custom FirebaseMessagingService and they both work correctly. I just need to figure out how to start RNPushNotificationListenerService when I have both setup with my custom FirebaseMessagingService.
Related
So now that the FirebaseInstanceIdService service is deprecated I'm unsure what to replace it with.
I previously had a service declared in the manifest like so:
<service
android:name=".fcm.FcmIdService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
And the service itself:
public class FcmIdService extends FirebaseInstanceIdService {
#Override
public void onTokenRefresh() {
// Create notification channel.
createFcmNotificationChannel();
}
}
If I remove the service I no longer receive notifications so I'm assuming I have to replace it with something else.
Thanks.
EDIT: This question differs from the proposed duplicate question by also covering the manifest declaration of the affected services which is still unclear to me.
Check this topic:
FirebaseInstanceIdService is deprecated
You have to replace it with:
public class MyFirebaseMessagingService extends FirebaseMessagingService {
#Override
public void onNewToken(String s) {
super.onNewToken(s);
Log.e("NEW_TOKEN",s);
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
}
}
And in manifest:
<service
android:name=".MyFirebaseMessagingService"
android:stopWithTask="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
And if you want to get token somewhere in your project:
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener( MyActivity.this, new OnSuccessListener<InstanceIdResult>() {
#Override
public void onSuccess(InstanceIdResult instanceIdResult) {
String newToken = instanceIdResult.getToken();
Log.e("newToken",newToken);
}
});
There is no need to use
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
Hope it helps you
All you need in the manifest is this (note that the service doesn't need android:stopWithTask="false" since it defaults to false:
<service android:name=".MyFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
And here's the rest of it in beautifully simple Kotlin...
To get the new token whenever it's refreshed:
class MyFirebaseMessagingService: FirebaseMessagingService() {
override fun onNewToken(token: String?) {
Log.d("FMS_TOKEN", token)
}
...
}
To get the token from anywhere at runtime:
FirebaseInstanceId.getInstance().instanceId.addOnSuccessListener {
Log.d("FMS_TOKEN", it.token)
}
This is what I have inside my AndroidManifest:
<service android:name=".MyFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<service android:name="io.smooch.core.service.SmoochService" />
<service android:name=".MyFirebaseInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
I am using version: implementation 'com.google.firebase:firebase-messaging:17.0.0'
This is how my FirebaseMessagingService looks like:
public class MyFirebaseMessagingService extends FirebaseMessagingService {
public void onMessageReceived(final RemoteMessage message) {
Log.i("", "MyFirebaseMessagingService onMessageReceived");
final Map data = message.getData();
FcmService.triggerSmoochNotification(data, this);
final Map bundle = data;
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
Log.i("", "GLOBAL intances before GCM:" + Realm.getGlobalInstanceCount(PSApplicationClass.Config));
try {
String title = getString(R.string.alert_title_warning) + " " + getString(R.string.trips_remaining_free, user.getTrips_left());
String message = getString(R.string.alert_freemium_upgrade);
Notification.generateNotificationStandard(MyFirebaseMessagingService.this, title, message, null, null, false, false);
} catch (Exception e) {
Utils.appendLog("GCMIntentService onMessageReceived error: " + e.getMessage(), "E", Constants.PUSH_NOTIFICATIONS);
}
}
});
}
}
And basically I put a breakpoint at the onMessageReceived of this function.
If the server sends a notification to my app, it will be received by this Service, and I can handle it as needed.
BUT. If I use the FirebaseConsole -> GROW -> Could Messaging -> I create a new Message and I send it. My app will get the notifications. but it will be created "automatically" without entering my onMessageReceived method.
How can I force it to do so?
This is the data that I send via the console:
https://s3.amazonaws.com/uploads.hipchat.com/39260/829560/7Pp0KJIErZ8XVZZ/upload.png
What am I doing wrong?
EDIT:
Like I said, I get notifications, but the notifications are being created automatically instead of going through my FirebaseMessaging Service.
I did manage to change the icon like this:
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="#drawable/notification_icon" />
But I still need to run other code when I get it, not just show it. and that I do not know how
I'm trying to migrate Android client app from Google Cloud Messaging to Firebase Cloud Messaging. I strictly followed an official tutorial, but didn't succeed - onMessageReceived() method is not called when app in foreground.
So here are code snippets that I touched.
build.gradle (project level)
dependencies {
//other stuff
classpath 'com.google.gms:google-services:3.0.0'
}
build.gradle (app level)
apply plugin: 'com.google.gms.google-services' //this line in the bottom
and
dependencies {
//other stuff here
compile 'com.google.firebase:firebase-messaging:9.0.0'
}
AndroidManifest.xml
<service android:name=".service.FirebaseService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
and
<service
android:name=".service.MyInstanceIDListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
and
<service
android:name=".service.RegistrationIntentService"
android:exported="false" />
as childs of <application> tag.
MyInstanceIDListenerService.java
public class MyInstanceIDListenerService extends FirebaseInstanceIdService {
final String TAG = "Firebase instance id";
#Override
public void onTokenRefresh() {
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.d(TAG, "Refreshed token: " + refreshedToken);
sendRegistrationToServer(refreshedToken);
}
private void sendRegistrationToServer(String token) {
Intent intent = new Intent(RegistrationIntentServiceEvent.TOKEN);
intent.putExtra(RegistrationIntentServiceEvent.TOKEN, token);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
FirebaseService.java
public class FirebaseService extends FirebaseMessagingService {
//OtherStuff
#Override
public void onMessageReceived(RemoteMessage message){
String from = message.getFrom();
Map data = message.getData();
Log.d(TAG, "Message: " + from); //Never appears in logcat
//other stuff
}
}
RegistrationIntentService
public class RegistrationIntentService extends IntentService {
private static final String TAG = "RegIntentService";
public RegistrationIntentService() {
super(TAG);
}
#Override
protected void onHandleIntent(Intent intent) {
try {
synchronized (TAG) {
String token = FirebaseInstanceId.getInstance().getToken();
Log.i(TAG, "GCM Registration Token: " + token);//This works fine
//and shows this line - 12-19 17:59:33.295 3146-5386/ru.bpc.mobilebank.bpc I/RegIntentService: GCM Registration Token: *some_token*
sendRegistrationToServer(token);
}
} catch (Exception e) {
Log.d(TAG, "Failed to complete token refresh", e);
}
}
private void sendRegistrationToServer(String token) {
Intent intent = new Intent(RegistrationIntentServiceEvent.TOKEN);
intent.putExtra(RegistrationIntentServiceEvent.TOKEN, token);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
Please, tell if i did something wrong and why registrations seems to be done properly, but the onMessageReceived() method is never called even if the app is in foreground. Thanks in advance.
P.S. By the way, is adding SHA-1 keys in Firebase console necessary? maybe this could cause the problem? But Firebase says this action is optional.
if you are using FCM then you should replace this
<service android:name=".service.GcmService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
to
<service android:name=".service.FirebaseService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
your service not registered properly..
I developing an Ionic 2 app and testing on Android emulator.
When the app is in background and the notification has no title, no message and content-available=1 the notification should be sent directly to app notification handler. But its not happening.
I can receive notifications with the app in foreground.
If I have a title and a message I receive the notification in the notification area. But I need to send the notification directly to the app in silent mode, without pass by the notification area.
Here is my code to send push notifications:
{
"delay_while_idle": true,
"priority": "high",
"sound": "default",
"color": "FFFF00",
//payload
"data": {
"content-available": "1",
"some_var": "some_value",
"ohter_var": "other_value",
}
}
How could I sent silent notifications to my Android app?
Android GCM and FCM both also work when app background.
For that you need to add below service classes at manifest with intent Filter.
<!-- [START gcm_listener] -->
<service
android:name=".gcm.GcmListener"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
<service
android:name=".gcm.TokenRefreshService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID" />
</intent-filter>
</service>
<service
android:name=".gcm.RegistrationIntentService"
android:exported="false" />
<!-- [END gcm_listener] -->
public class GcmListener extends GcmListenerService {
}
public class TokenRefreshService extends InstanceIDListenerService {
#Override
public void onTokenRefresh() {
super.onTokenRefresh();
Intent intent = new Intent(this, RegistrationIntentService.class);
startService(intent);
}
}
To get token:
public class RegistrationIntentService extends IntentService {
// TODO: Rename actions, choose action names that describe tasks that this
private String TAG = "RegistrationIntentService";
public RegistrationIntentService() {
super("RegistrationIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
InstanceID instanceID = InstanceID.getInstance(this);
String token = instanceID.getToken("PRODUCT_ID",
GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
}
}
Data sent through Data API from mobile app is not received in ondatachange of listenerservice in wearable emulator.I can send a notification though, which indicates both are connected.Below my code,
DataAPI call (mobile)
PutDataMapRequest putDataMapRequest = PutDataMapRequest.create(SharedConstants.START_FREE_RUN);
putDataMapRequest.getDataMap().putString(SharedConstants.PROGRAM_TYPE,totalCountUpTimer);
PutDataRequest request = putDataMapRequest.asPutDataRequest();
Wearable.DataApi.putDataItem(mGoogleApiClient, request)
.setResultCallback(new ResultCallback<DataApi.DataItemResult>() {
#Override
public void onResult(DataApi.DataItemResult dataItemResult) {
if (!dataItemResult.getStatus().isSuccess()) {
Log.e(TAG, "buildWatchOnlyNotification(): Failed to set the data, "
+ "status: " + dataItemResult.getStatus().getStatusCode());
} else {
Log.d(TAG,"SuccessFully sent notification");
}
}
});
After which I am getting "successfully sent" log message.
Below is ListenerService in wear,
public class ListenerService extends WearableListenerService {
private static final String TAG = ListenerService.class.getSimpleName();
#Override
public void onDataChanged(DataEventBuffer dataEvents) {
super.onDataChanged(dataEvents);
Log.d(TAG, "dchanged" + dataEvents);
}
#Override
public void onMessageReceived(MessageEvent messageEvent) {
Log.v(TAG, "onMessageReceivedWear: " + messageEvent);
if (SharedConstants.START_FREE_RUN.equals(messageEvent.getPath())) {
// Request for this device open the attraction detail screen
// to a specific tourist attraction
String Distance = new String(messageEvent.getData());
Log.d("ListenerService",Distance);
}
}
}
and my service declaration in Android manifest,
<service android:name=".services.ListenerService">
<intent-filter>
<action android:name="com.google.android.gms.wearable.DATA_CHANGED" />
<action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED" />
<data android:scheme="wear" android:host="*" android:pathPrefix="*" />
</intent-filter>
</service>
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
Did not add any permissions in wearable module.Do suggest.
Use android:pathPattern=".*" instead of android:pathPrefix="*"