I need some help with android push notifications, please. For context, I’ve read dozens of stack overflow posts on how to implement push notifications for android. All of the posts I’ve seen only cover part of the problem. I’ve been able to successfully receive push notifications and display a heads up notification when the app is in the foreground or background, but then it doesn’t work when the app is swiped closed. In order for the notification to display on the status bar when the app is swiped closed, you need to use a "notification" object in the payload instead of a "data" object.
What I am trying to achieve is this – I need a status bar notification, a sound and a heads up notification when the app is in any of these states – foreground, background and swiped closed.
What is the secret recipe of code, payload json, and manifest config to make this happen? Any major app that I have on my phone – eBay, etsy, amazon and most apps that I download can do all of this, so it must be possible regardless of what some off the fcm guides say.
Here is our onMessageReceived method in our FireBaseMessagingService:
public override void OnMessageReceived(RemoteMessage message)
{
try
{
base.OnMessageReceived(message);
string messageBody = string.Empty;
string messageTitle = string.Empty;
if (message.GetNotification() != null)
{
messageTitle = message.GetNotification().Title;
messageBody = message.GetNotification().Body;
}
else
{
if (message.Data.Values.Count == 1)
{
messageTitle = "Alerts Occurred";
messageBody = message.Data.Values.First();
}
else if (message.Data.Values.Count == 2)
{
messageTitle = message.Data.Values.ToList()[0];
messageBody = message.Data.Values.ToList()[1];
}
}
SendLocalNotification(messageTitle, messageBody);
}
catch (Exception e)
{
NotificationHubHelper.LogInfo($"Error receiving message on device: {e.Message}");
}
}
private void SendLocalNotification(string title, string body)
{
try
{
_notificationBadgeCount++;
var intent = new Intent(this, typeof(MainActivity));
intent.AddFlags(ActivityFlags.ClearTop);
intent.PutExtra("message", body);
var pendingIntent = PendingIntent.GetActivity(this, 0, intent, PendingIntentFlags.OneShot);
int notificationIconId =
Resources.GetIdentifier(NotificationHubHelper.AndroidNotificationIconImage, "drawable",
AppInfo.PackageName);
NotificationHubHelper.LogInfo($"Found notification icon with id: {notificationIconId}");
var notificationBuilder = new NotificationCompat.Builder(this,
NotificationHubHelper.NotificationChannelName)
.SetContentTitle(title)
.SetSmallIcon(notificationIconId) //.SetSmallIcon(ApplicationInfo.Icon)
.SetContentText(body)
.SetAutoCancel(true)
.SetShowWhen(false)
.SetContentIntent(pendingIntent)
.SetPriority((int)NotificationPriority.Max);
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
notificationBuilder.SetChannelId(NotificationHubHelper.NotificationChannelName);
}
var notificationManager = NotificationManager.FromContext(this);
notificationManager.Notify(0, notificationBuilder.Build());
CrossBadge.Current.SetBadge(_notificationBadgeCount);
}
catch (Exception e)
{
NotificationHubHelper.LogInfo($"Error sending local notification on device: {e.Message}");
}
}
Here is our manifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1"
android:versionName="1.0.9" package="HIDDEN_FROM_POST" android:installLocation="auto">
<uses-sdk android:minSdkVersion="23" android:targetSdkVersion="29" />
<application android:allowBackup="false" android:label="HIDDEN_FROM_POST"
android:icon="@drawable/HIDDEN_FROM_POST">
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="HIDDEN_FROM_POST" />
<meta-data android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<uses-library android:name="org.apache.http.legacy" android:required="false" />
<provider android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.fileprovider" android:exported="false"
android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"></meta-data>
</provider>
<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>
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/HIDDEN_FROM_POST" />
</application>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-permission android:name="com.anddoes.launcher.permission.UPDATE_COUNT"/>
<uses-permission android:name="com.android.launcher.permission.READ_SETTINGS"/>
<uses-permission android:name="com.android.launcher.permission.WRITE_SETTINGS"/>
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" />
<uses-permission android:name="com.htc.launcher.permission.READ_SETTINGS" />
<uses-permission android:name="com.htc.launcher.permission.UPDATE_SHORTCUT" />
<uses-permission android:name="com.sec.android.provider.badge.permission.READ" />
<uses-permission android:name="com.sec.android.provider.badge.permission.WRITE" />
<uses-permission android:name="com.sonyericsson.home.permission.BROADCAST_BADGE" />
<uses-permission android:name="com.sonymobile.home.permission.PROVIDER_INSERT_BADGE" />
</manifest>
And, finally, here is the latest payload we’ve tried:
{
"notification":{
"title":"Portugal vs. Denmark",
"body":"great match!"
},
"data":{
"message":"this is a message",
"title":"title"
}
}
With the above, we get a status bar notification when the app is swiped closed, a status bar notification when the app is in background and a status bar notification with heads up notification when the app is in the foreground.
How do we get the heads up notification in all scenarios?
Len
2
Answers
It is basically the same as ordinary notifications. In Android version 8.0 and after that, you can suspend notifications only by setting the importance level to
IMPORTANCE_HIGH
on the importance of notification channel.like:It also allows users to set notifications’ importance level directly on their phone. Emergency suspension can be realized.
For Android versions prior to 8.0, add a
SetFullScreenIntent
to thenotificationBuilder
Or activate sound and vibration prompts.
This could be a long shot but after a lot of digging I found that when in background and especically when swiped away you don’t have access to the XamarinForms object as it’s only instantiated once you actually go through the start activity.
E.g. if this is actually using a DependencyService or another Forms library you will get an error.
also make sure from your notification server you are setting the priority to
high
it is normal by default which will not cause the WAKEUP of the app if swiped away.