Receive Firebase push notification - android

In my Android app I need to handle receiving of Firebase push notification messages, so that I can manipulate their ids (so that all notifications display rather than replacing each other) and so that I can display an app icon (setting it with a meta-data element in Android manifest doesn't work.)
I've creating a messaging service to handle receiving messages:
[Service (Name = "com.rpr.mobile.droid.LocalyticsFirebaseMessagingService")]
[IntentFilter (new[] { "com.google.firebase.MESSAGING_EVENT" })]
public class LocalyticsFirebaseMessagingService : FirebaseMessagingService {
private static int notificationId = 0;
public override void OnMessageReceived (RemoteMessage message) {
if (!message.Data.ContainsKey ("ll")) {
base.OnMessageReceived (message);
} else {
var body = message.GetNotification ().Body;
if (!String.IsNullOrEmpty (body)) {
var mainIntent = new Intent (this, typeof (IntentActivity));
var deepLinkUrl = "";
if (message.Data.TryGetValue ("ll_deep_link_url", out deepLinkUrl))
mainIntent.SetData (Android.Net.Uri.Parse (deepLinkUrl));
var launchIntent = PendingIntent.GetActivity (this, 1, mainIntent, PendingIntentFlags.UpdateCurrent);
var builder = new NotificationCompat.Builder (this)
.SetSmallIcon (Resource.Drawable.logo_blue_small)
.SetContentTitle (GetString (Resource.String.application_name))
.SetContentText (body)
.SetStyle (new NotificationCompat.BigTextStyle ().BigText (body))
.SetContentIntent (launchIntent)
.SetDefaults (-1)
.SetAutoCancel (true);
var notificationManager = NotificationManagerCompat.From (this);
notificationManager.Notify (notificationId++, builder.Build ());
}
}
}
}
And I've defined it in the application section of my Android manifest:
<service android:name="com.rpr.mobile.droid.LocalyticsFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
However, when I receive a push notification this code is never called, even when the app is in the foreground. I had similar code that worked fine for GCM push notifications, but I'm having no luck for Firebase. What am I missing?

You have to add the below code to your android manifest file inside application section:
<receiver android:name="com.google.firebase.iid.FirebaseInstanceIdInternalReceiver" android:exported="false" />
<receiver android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="${applicationId}" />
</intent-filter>
</receiver>
and in your class you have to add like this
[Service]
[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
public class MessagingService : FirebaseMessagingService
and this is the code to get the token
[Service]
[IntentFilter(new[] { "com.google.firebase.INSTANCE_ID_EVENT" })]
public class IDService : FirebaseInstanceIdService
also you have to add the google-services.json file to your project with the build action GoogleServicesJson

Related

Localytics Firebase Push Notifications are not working on Xamarin Forms for Android

I've managed to get this working in the past, but its suddenly stopped working and I don't know what to check in order to get it working again. I am trying to get push notifications working using Firebase Cloud Messaging through Localytics. I am testing using the Localytics Rapid Push Notification Test module. The device pairs ok but when I send the notification nothing happens on the device.
1) I've regenerated my google-services.json file and pasted into the root of my folder.
2) I'm pretty sure my Android Manifest is fine:
<meta-data android:name="LOCALYTICS_APP_KEY" android:value="{HIDDEN FROM STACK OVERFLOW}" />
<activity android:name="com.localytics.android.PushTrackingActivity" android:exported="true" />
<receiver android:name="com.localytics.android.ReferralReceiver" android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>
</receiver>
<receiver android:name="com.google.firebase.iid.FirebaseInstanceIdInternalReceiver" android:exported="false" />
<receiver android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="{HIDDEN FROM STACK OVERFLOW}" />
</intent-filter>
</receiver>
3) My implementation of FirebaseInstanceIdService gets called ok as I can debug it:
[Service]
[IntentFilter(new[] { "com.google.firebase.INSTANCE_ID_EVENT" })]
public class MyFirebaseIIDService : FirebaseInstanceIdService
{
const string TAG = "MyFirebaseIIDService";
public override void OnTokenRefresh()
{
var refreshedToken = FirebaseInstanceId.Instance.Token;
Log.Debug(TAG, "Refreshed token: " + refreshedToken);
Localytics.PushRegistrationId = refreshedToken;
SendRegistrationToServer(refreshedToken);
}
void SendRegistrationToServer(string token)
{
// Add custom implementation, as needed.
}
}
4) My implementation of FirebaseMessagingService never ever gets called!
[Service]
[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
public class MyFirebaseMessagingService : FirebaseMessagingService
{
const string _tag = "MyFirebase";
public override void OnMessageReceived(RemoteMessage message)
{
Log.Debug(_tag, "Remote Message Received");
}
}
5) In my MainActivity I am calling Localytics.RegisterPush(); within the OnCreate() override.
Can someone please help? Thanks in advance!

Android Firebase background notification not firing

I'm developing an Android App that receives push notifications from Firebase.
I can get the token and send push notifications from Postman without any problem.
If the App is in foreground everything works as expected and I receive the payload in the onMessageReceived (I tested with various payloads).
But if I close the App it don't receive nothing. I tried with a lot of payloads, and I read all the documentation (diference between data and notification in payload).
Here's my classes that my project uses:
1 - The class that extends FirebaseMessagingService
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "Android Push App";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
sendNotification("Received notification");
}
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);
Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.push_icon)
.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());
}
2 - The class that is responsible for get the token
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
private static String TAG = "Android Push App";
#Override
public void onTokenRefresh() {
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
sendRegistrationToServer(refreshedToken);
}
private void sendRegistrationToServer(String token) {
Log.d(TAG, "Did obtained token");
Log.d(TAG, token);
}
3 - My Manifest:
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="FIREBASE_ACTIVITY" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<service android:name=".push.core.MyFirebaseInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<service
android:name=".push.core.MyFirebaseMessagingService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="#drawable/push_icon" />
<meta-data android:name="com.google.firebase.messaging.default_notification_color"
android:resource="#color/colorAccent" />
</application>
4 - The MainActivity
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (getIntent().getExtras() != null) {
for (String key : getIntent().getExtras().keySet()) {
Object value = getIntent().getExtras().get(key);
Log.d("MainActivity", "Key: " + key + " Value: " + value);
}
}
}
5 - Finally I tried this payload in the Postman
POST https://fcm.googleapis.com/fcm/send
Content-Type application/json
Authorization key=AIzaSy(...)kY
JSON Body (the examples I tried):
{
"to": "dxe0RDKbP...m9Uc","notification" : {
"body" : "great match!",
"title" : "Portugal vs. Denmark",
"icon" : "push_icon",
"sound" : "default"
}}
And:
{
"to": "dxe0RDKbP...m9Uc","notification" : {
"body" : "great match!",
"title" : "Portugal vs. Denmark",
"icon" : "push_icon",
"sound" : "default"
}}
And:
{
"to": "d3j-9OJ6R...C6w",
"notification" : {
"title": "title",
"body": "body"
},
"data": {
"tipo": "normal"
}}
Also added the "priority" key and it doesn't work.
What I'm I doing wrong?
Thanks for all the help you can gave to me :)
UPDATE
Now it's working.
There was a conflict between the FireBaseMessagingService and a Geofence Push that is running (fired by the App).
After removed this Geofence service everything works as expected.
Also use the notification and data keys in the payload of the push.
Thanks
Try this
you must not put JSON key 'notification' in your request to firebase API but instead use 'data'.
Example
use this
{
"to": "dxe0RDKbP...m9Uc",
"data": {
"body" : "great match!",
"title" : "Portugal vs. Denmark",
"icon" : "push_icon",
"sound" : "default"
}
}
EDIT
you can try with only body and title
{
"to": "dxe0RDKbP...m9Uc",
"data": {
"body" : "great match!",
"title" : "Portugal vs. Denmark"
}
}
Edit New
Add this in your manifest file android:stopWithTask="false" service property.
<service
android:name="com.yourapp.YourPushService"
android:stopWithTask="false"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
you need to remove notification payload from the json and add a data payload to it. This is because Android has an inbuilt functionality of taking care of notification when it sees notification payload, i.e., it, whenever notification payload is sent android directly sends it to system dray and onMessageReceived function, is not called.
As per the firebase documentation, Firebase notifications behave differently depending on the foreground/background state of the receiving app.
onMessageReceived is provided for most message types, with the following exceptions:
Notification messages delivered when your app is in the background. In this case, the notification is delivered to the device’s system tray. A user tap on a notification opens the app launcher by default.
Messages with both notification and data payload, both background and foreground. In this case, the notification is delivered to the device’s system tray, and the data payload is delivered in the extras of the intent of your launcher Activity.
So you need to remove notification payload from your json and only need to keep data payload to trigger onMessageReceived when app is in background.
Link:https://firebase.google.com/docs/cloud-messaging/android/receive

Android Firebase notification when application starts

I’m new to android.I programmed an app that uses Firebase to get push notifications. If I send a notification from the Firebase interface, the device receives the notification only when the app is running. Is there a way to get the notifications when the app is not running or at least to get all the unseen notifications when the app starts up?
Thank you in advance!
I add my code...
This is the class extending the FirebaseMessagingService:
public class MyFirebaseMessagingService extends FirebaseMessagingService {
public MyFirebaseMessagingService() {
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
sendNotification(remoteMessage.getNotification().getBody());
}
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, intent, PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this);
notificationBuilder.setSmallIcon(R.mipmap.ic_launcher_round);
notificationBuilder.setContentTitle("My app");
notificationBuilder.setContentText(messageBody);
notificationBuilder.setAutoCancel(true);
notificationBuilder.setSound(defaultSoundUri);
//notificationBuilder.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0,notificationBuilder.build());
}
}
and this is the class extending the FirebaseInstanceIdService:
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService{
#Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
// 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(refreshedToken);
}
private void sendRegistrationToServer(String token)
{
}
}
Finally, this is the manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="user.pushnotificationexample">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".MyFirebaseInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<service
android:name=".MyFirebaseMessagingService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
</application>
</manifest>
This is Xamarin Android solution, but it should get you close to native.
Try test sending a "data" push notification from an online tester like "pushwatch". Make sure to click the json checkbox and add a json payload that includes the key, "data":
{"data": {"title":"This is a title!","body":"This is the body text!"}}
The OnMessageReceived(RemoteMessage message) method, message parameter, has a dictionary property "Data": i.e. message.Data. You'll find the json payload key value pairs (title & body) in that dictionary.
Note, if the app is STOPPED, the user will OPEN the notification and Android will open the app, targeting the Activity used in the pending intent created and used to build the local notification (see below). You will need to handle the notification intent from the OnCreate method of your target Activity ( otherwise if the app is running, you'll handle the intent from an override of OnNewIntent).
public class MainActivity....
{
protected override void OnCreate(Bundle bundle)
{
...
var pushExtra = Intent.GetStringExtra("your.pushextra.key");
if(pushExtra != null)
{
MyType myType = JsonConvert.Deserialize<MyType>(pushExtra);
//if you have a framework like MVVM or startup process
//and your type
//is used for app navigation, you may need to store
//the string value in shared preferences and deserialize
//and use it later
//after the app has completely finished starting
}
}
}
Save yourself some effort, if you need a type or dictionary here, make sure to serialize the object when putting the extra (when you create the local notification) and then deserialize the pushExtra to your concrete type to use an instance of it above. You may find most examples put a string, or int or dictionary of key value pairs.
void ConfigureLocalNotification(MyType typeInstance)
{
...
var intent = new Intent(context, typeof(MainActivity));
var jsonData = JsonConvert.SerializeObject(typeInstance);
Log.Info(TAG, $"Adding IntentExtra: {jsonData}");
intent.PutExtra("your.pushextra.key", jsonData);
intent.AddFlags(ActivityFlags.ClearTop | ActivityFlags.SingleTop |
ActivityFlags.IncludeStoppedPackages); //| ActivityFlags.NewTask);
var pendingIntent = PendingIntent.GetActivity(context, 0, intent,
PendingIntentFlags.OneShot);
....
NotificationCompat.Builder builder = null;
builder = new NotificationCompat.Builder(context ...);
builder.SetContentIntent(pendingIntent) ....
}
Hope this helps

Not receiving GCM notifications with app in background and content-available=1

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);
}
}

GCM message stops foregrounded service

I am using an indefinitely running service (with its own process) and an extension of GcmListenerService to receive push messages. The push messages will initiate an operation within the service.
The problem is, that if the app is closed/removed from the recently used app, the service is still running, but will stop immediately if a new message is received. The process list shows that first the background process is terminated and then a usual application process starts without any processing of the push message.
AndroidManifest.xml
<application android:allowBackup="false" android:label="#string/app_name"
android:icon="#drawable/icon" android:theme="#style/AppTheme"
android:process="domain.android.Application"
android:name=".Application">
<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="domain.android" />
</intent-filter>
</receiver>
<service
android:name=".service.MyGcmListenerService"
android:exported="false" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
<service
android:name=".service.BackgroundService"
android:icon="#drawable/icon"
android:label="#string/service_name"
android:process="domain.android.service.BackgroundService"
android:exported="false"
android:enabled="true"/>
</application>
The GCM listener
public class MyGcmListenerService extends GcmListenerService {
#Override
public void onMessageReceived(String from, Bundle data) {
String code = data.getString("code");
if ("j".equals(code)) {
final String id = data.getString("id", null);
String status = data.getString("status", null);
Intent serviceIntent = new Intent(getBaseContext(), domain.android.service.BackgroundService.class);
serviceIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
serviceIntent.putExtra("method", "push");
serviceIntent.putExtra("id", id);
serviceIntent.putExtra("status", status);
serviceIntent.putExtra("notificationId", (new Date()).getTime());
startService(serviceIntent);
}
}
}
The service:
public class BackgroundService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, final int startId) {
if (intent.hasExtra("method")) {
// Start processing
}
}
#Override
public void onCreate() {
Intent notificationIntent = new Intent(this, Main.class);
PendingIntent intent = PendingIntent.getActivity(getBaseContext(), 0, notificationIntent, 0);
android.app.Notification.Builder builder = new android.app.Notification.Builder(this)
.setContentIntent(intent)
.setContentTitle(getText(R.string.app_name))
.setContentText("Connected")
.setSmallIcon(R.drawable.marker_walker_white);
android.app.Notification notification = builder.build();
startForeground(1, notification);
}
}

Categories

Resources