I am sending Firebase Notification on devices with Xamarin plugin. This is my configuration : Visual Studio 2022. iOS 15. Xcode 13. All is working fine in Android devices. All is working fine in Apple devices except one thing : When the application is in background, the notification is received only when the user open the application.
Here is my code :
public class MVision : UIApplicationDelegate, IUNUserNotificationCenterDelegate, IMessagingDelegate
{
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions){
Firebase.Core.App.Configure();
// Messaging.SharedInstance.Self
// Messaging.messaging().delegate = self
Messaging.SharedInstance.Delegate = (IMessagingDelegate)Self;
if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
{
// Request Permissions
UNUserNotificationCenter.Current.RequestAuthorization(
UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound,
(granted, error) =>
{
// Do something if needed
});
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.Current.Delegate = new MyUNUserNotificationCenterDelegate();
// For iOS 10 data message (sent via FCM)
Messaging.SharedInstance.Delegate = this;
}
else
{
// iOS 9 or before
var allNotificationTypes = UIUserNotificationType.Alert
| UIUserNotificationType.Badge
| UIUserNotificationType.Sound;
var settings = UIUserNotificationSettings
.GetSettingsForTypes(allNotificationTypes, null);
UIApplication.SharedApplication.RegisterUserNotificationSettings(settings);
}
Messaging.SharedInstance.ShouldEstablishDirectChannel = true;
UNUserNotificationCenter.Current.Delegate = new MyUNUserNotificationCenterDelegate();
UIApplication.SharedApplication.RegisterForRemoteNotifications();
The methods are :
[Export("messaging:didReceiveRegistrationToken:")]
public void DidReceiveRegistrationToken(Messaging messaging, string fcmToken)
{
var i = 1;
// var token = Messaging.SharedInstance.FcmToken;
// TODO: If necessary send token to application server.
// Note: This callback is fired at each app startup and whenever a new token is generated.
}
[Export("messaging:didRegisterForRemoteNotificationsWithDeviceToken:")]
public void DidRegisterForRemoteNotificationsWithDeviceToken(UIKit.UIApplication application, Foundation.NSData deviceToken) {
Messaging.SharedInstance.ApnsToken = deviceToken;
}
public override void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo) { var userInfo1 = userInfo; }
[Export("application:didReceiveNotificationResponse:fetchCompletionHandler:")]
public void DidReceiveNotificationResponse(UNUserNotificationCenter center, UNNotificationResponse response, System.Action completionHandler)
{
completionHandler();
}
[Export("application:didReceiveRemoteNotification:fetchCompletionHandler:")]
public override void DidReceiveRemoteNotification(
UIApplication application,
NSDictionary userInfo,
System.Action<UIBackgroundFetchResult> completionHandler)
{
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// Except if "content-available" is set to true / 1
// Print full message.
// Console.WriteLine(userInfo);
completionHandler(UIBackgroundFetchResult.NewData);
}
[Export("messaging:didReceiveMessage:")]
public void DidReceiveMessage(Messaging messaging, RemoteMessage remoteMessage)
{
var notification = (NSDictionary)remoteMessage.AppData.ValueForKey(new NSString("notification"));
var title = notification.ValueForKey(new NSString("title"));
var text = notification.ValueForKey(new NSString("body"));
// remotenotification = true;
ScheduleNotification(title.ToString(), text.ToString());
}
//This code is for showing notification
void ScheduleNotification(string title, string body)
{
// Create content
var content = new UNMutableNotificationContent();
content.Title = title;
//content.Subtitle = "Subtitle";
content.Body = body;
content.Badge = 1;
content.CategoryIdentifier = "notification_fv";
content.Sound = UNNotificationSound.Default;
// Fire trigger in one seconds
var trigger = UNTimeIntervalNotificationTrigger.CreateTrigger(1, false);
var requestID = "customNotification";
var request = UNNotificationRequest.FromIdentifier(requestID, content, trigger);
// This is the line that does the trick
UNUserNotificationCenter.Current.AddNotificationRequest(request, (err) => {
if (err != null)
{
// Report error
System.Console.WriteLine("Error: {0}", err);
}
else
{
// Report Success
System.Console.WriteLine("Notification Scheduled: {0}", request);
}
});
}
/* [Export("messaging:didReceiveMessage:")]
public void DidReceiveMessage(Messaging messaging, RemoteMessage remoteMessage)
{
// Handle Data messages for iOS 10 and above.
HandleMessage(remoteMessage.AppData);
var fcmToken = Messaging.SharedInstance.FcmToken;
}*/
[Export("userNotificationCenter:willPresentNotification:withCompletionHandler:")]
public void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, System.Action<UNNotificationPresentationOptions> completionHandler)
{
SystemSound.Vibrate.PlayAlertSound();
SystemSound.Vibrate.PlaySystemSound();
completionHandler(UNNotificationPresentationOptions.Alert);
}
The notification center delegate class is :
using Foundation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UIKit;
using UserNotifications;
namespace MVision.iOS
{
public class MyUNUserNotificationCenterDelegate : UNUserNotificationCenterDelegate
{
bool toggle;
public override void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
{
if (toggle)
completionHandler(UNNotificationPresentationOptions.Alert);
else
{
// Console.WriteLine(notification);
// completionHandler(UNNotificationPresentationOptions.None);
completionHandler(UNNotificationPresentationOptions.Alert);
}
toggle = !toggle;
}
}
}
I check the info.plist
<key>UIBackgroundModes</key>
<array>
<string>remote-notification</string>
</array>
<key>FirebaseAppDelegateProxyEnabled</key>
<false/>
<key>FirebaseScreenReportingEnabled</key>
<true/>
I also refer to entitlement.developer.plist :
<dict>
<key>aps-environment</key>
<string>development</string>
</dict>
I also parameter my notification with content-available = 1 and mutable-content = 1.
I think that the problem is that "DidReceiveRemoteNotification" is never call neither in background, nor in foreground. Any Ideas ?
Please also notice : In Xamarin, when you stay in Visual Studio 2019 and you pass to iOS 15, you will not have simulators anymore, please download Visual Studio 2022. Entitlement.plist does not work on this configuration. You must create Entitlement.developer.plist and refer to is.