Xamarin Forms: Push notification is not receiving to ios device - xamarin.forms

I have done the following things:
Created a project in FCM console and added ios project into it.
Downloaded the GoogleService-Info.plist and added it to the xamarin forms ios project directory and set the build action as Bundlesource.
On Info.plist enabled remote notification background mode.
Added FirebaseAppDelegateProxyEnabled in the app’s Info.plist file and set it to No.
Created a provisioning profile and distribution certificate and installed it into the keychain access. Also, mapped these certificates in the project options.
Uploaded .p12 certificate in FCM console.
Added codes for handling push notification in AppDelegate.cs.
My Code:
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate, IUNUserNotificationCenterDelegate
{
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App("",""));
RequestPushPermissionsAsync();
_launchoptions = options;
// Register your app for remote notifications.
if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
{
// iOS 10 or later
var authOptions = UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound;
UNUserNotificationCenter.Current.RequestAuthorization(authOptions, (granted, error) => {
Console.WriteLine(granted);
});
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.Current.Delegate = this;
// For iOS 10 data message (sent via FCM)
//Messaging.SharedInstance.RemoteMessageDelegate = this;
}
else
{
// iOS 9 or before
var allNotificationTypes = UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound;
var settings = UIUserNotificationSettings.GetSettingsForTypes(allNotificationTypes, null);
UIApplication.SharedApplication.RegisterUserNotificationSettings(settings);
}
UIApplication.SharedApplication.RegisterForRemoteNotifications();
return base.FinishedLaunching(app, options);
}
NSDictionary _launchoptions;
public override void OnActivated(UIApplication uiApplication)
{
base.OnActivated(uiApplication);
if (_launchoptions != null && _launchoptions.ContainsKey(UIApplication.LaunchOptionsRemoteNotificationKey))
{
var notfication = _launchoptions[UIApplication.LaunchOptionsRemoteNotificationKey] as NSDictionary;
PresentNotification(notfication);
}
_launchoptions = null;
}
async Task RequestPushPermissionsAsync()
{
var requestResult = await UNUserNotificationCenter.Current.RequestAuthorizationAsync(
UNAuthorizationOptions.Alert
| UNAuthorizationOptions.Badge
| UNAuthorizationOptions.Sound);
bool approved = requestResult.Item1;
NSError error = requestResult.Item2;
if (error == null)
{
if (!approved)
{
Console.Write("Permission to receive notification was not granted");
return;
}
var currentSettings = await UNUserNotificationCenter.Current.GetNotificationSettingsAsync();
if (currentSettings.AuthorizationStatus != UNAuthorizationStatus.Authorized)
{
Console.WriteLine("Permissions were requested in the past but have been revoked (-Settings app)");
return;
}
UIApplication.SharedApplication.RegisterForRemoteNotifications();
}
else
{
Console.Write($"Error requesting permissions: {error}.");
}
}
public async override void RegisteredForRemoteNotifications(
UIApplication application, NSData deviceToken)
{
//if (deviceToken == null)
//{
// // Can happen in rare conditions e.g. after restoring a device.
// return;
//}
//Console.WriteLine($"Token received: {deviceToken}");
// Get current device token
var DeviceToken = deviceToken.Description;
if (!string.IsNullOrWhiteSpace(DeviceToken))
{
DeviceToken = DeviceToken.Trim('<').Trim('>');
}
Console.WriteLine($"deviceToken received: {deviceToken}");
Console.WriteLine($"DeviceToken received: {DeviceToken}");
// Get previous device token
var oldDeviceToken = NSUserDefaults.StandardUserDefaults.StringForKey("PushDeviceToken");
// Has the token changed?
if (string.IsNullOrEmpty(oldDeviceToken) || !oldDeviceToken.Equals(DeviceToken))
{
//TODO: Put your own logic here to notify your server that the device token has changed/been created!
}
// Save new device token
NSUserDefaults.StandardUserDefaults.SetString(DeviceToken, "PushDeviceToken");
await SendRegistrationToServerAsync(DeviceToken);
}
async Task SendRegistrationTokenToMainPRoject(NSData deviceToken)
{
MessagingCenter.Send<object, string>(this, "fcmtoken", deviceToken.ToString());
}
public override void FailedToRegisterForRemoteNotifications(UIApplication application, NSError error)
{
Console.WriteLine($"Failed to register for remote notifications: {error.Description}");
}
public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo,
Action<UIBackgroundFetchResult> completionHandler)
{
PresentNotification(userInfo);
completionHandler(UIBackgroundFetchResult.NoData);
try
{
UIApplication.SharedApplication.ApplicationIconBadgeNumber = 0;
NSDictionary aps = userInfo.ObjectForKey(new NSString("aps")) as NSDictionary;
var message = (aps[new NSString("webContentList")] as NSString).ToString();
LoadApplication(new App("", message));
}
catch (Exception ex)
{
//LogInfo.ReportErrorInfo(ex.Message, ex.StackTrace, "AppDelegate-DidReceiveRemoteNotification");
}
}
void PresentNotification(NSDictionary userInfo)
{
NSDictionary aps = userInfo.ObjectForKey(new NSString("aps")) as NSDictionary;
var msg = string.Empty;
if (aps.ContainsKey(new NSString("alert")))
{
msg = (aps[new NSString("alert")] as NSString).ToString();
}
if (string.IsNullOrEmpty(msg))
{
msg = "(unable to parse)";
}
MessagingCenter.Send<object, string>(this, App.NotificationReceivedKey, msg);
}
}
I am not using any NuGet packages in ios part. When running the project into a device, the FCM token generating part is working and I can see the fcm token on the VS console. I tried to send a test notification to a device from postman but getting InvalidRegistration error.
Postman Response
{
"multicast_id": 8754155136812875313,
"success": 0,
"failure": 1,
"canonical_ids": 0,
"results": [
{
"error": "InvalidRegistration"
}
]
}
Postman Body
{
"to" : "d20ad003 7473bfba 85dffc33 1534decf b4b886f1 c738878f fd7f2c60 d9dabc36",
"collapse_key" : "type_a",
"data" : {
"body" : "Body of Your Notification in Data",
"title": "Title of Your Notification in Title",
"key_1" : "Value for key_1",
"key_2" : "Value for key_2"
},
"notification" : {
"body" : "Body of Your Notification",
"title": "Title of Your Notification",
"sound": "default",
"content_available" : true
}
}
I have completed the android part implementation and notifications are receiving when push from the postman. But getting InvalidRegistration error on ios part and not receiving any notification in my ios device.
I follow this youtube video for this implementation and the complete source code is here.
Anyone suggest a solution for this issue.
Thanks in advance.
Update
I have created a sample project and a postman collection and added it to my google folder.
Postman collection contains 2 REST APIs, one for Android device and the other one for ios device
If you import the postman collection and run the Android REST API, I will receive the notification, because I have added my device FCM token on it. But when running the ios REST API in postman will return InvalidRegistration error in postman.
Please go through the sample project and please give me a solution?

I have reviewed and can resolve this issue.
Install the plugin Xamarin.Firebase.iOS.CloudMessaging in iOS project.
AppDelegate class needs to inherit from IUNUserNotificationCenterDelegate and IMessagingDelegate interfaces.
Include the Firebase.Core.App.Configure (); in FinishedLaunching method before registering remote notification.
Then you can add the registering remote notification code (You can get the code from given link).
You need to set user notification delegate and messaging shared instant delegate (UNUserNotificationCenter.Current.Delegate = this; // For iOS 10 display notification (sent via APNS) and Messaging.SharedInstance.Delegate = this;).
Include DidReceiveRegistrationToken and DidReceiveMessage methods with corresponding attributes
Please refer this AppDelegate class for more clarity https://github.com/xamarin/GoogleApisForiOSComponents/blob/master/Firebase.CloudMessaging/samples/CloudMessagingSample/CloudMessagingSample/AppDelegate.cs
Related Xamarin Forums thread
https://forums.xamarin.com/discussion/159477/xamarin-forms-push-notification-is-not-receiving-to-ios-device#latest

Related

Xamarin.Forms push-notifications are transmitted very unreliably (late or not at all)

I am writing an Xamarin.forms based app which is currently running on android platform. It is the first time I need to use push-notifications. I followed a guide from microsoft (https://learn.microsoft.com/de-de/xamarin/android/data-cloud/google-messaging/remote-notifications-with-fcm?tabs=vswin)") to implement the notifications.
The target android version is 8.1 API 27. The app runs on a Samsung tab active 2, which has android 8.1.
I configured the app as seen in the tutorial. I push the messages through a defined channel and this channel is subscribed in the app. The messages are pushed by a server which triggers the rest call for the FCM api. The first day I did some tests the transmission worked very good and I would say it was (nearly) reliable.
The next day I implemented some other features and wanted to test the push notifications again. Then: I was very confused, the most messages were not delivered or VERY VERY late. I am not sure if all messages were transmitted, there went may be some lost.
For me the FCM service is a big blackbox where I can delegate some work and then I need to hope that the messages will be transmitted. I am very confused now.
I paste here some code, but it is nearly what you can find in the tutorial:
My Questions:
What can I do? Is there something to get some more information from the FCM what my messages are currently doing? Or are there some problems with the code?
This is run in the mainActivity:
if (this.IsPlayServicesAvailable())
{
// Creates a notification channel
this.CreateNotificationChannel();
//Console.WriteLine("InstanceID token: " + FirebaseInstanceId.Instance.Token);
// Subscribe to notification token
FirebaseMessaging.Instance.SubscribeToTopic("channel");
Log.Debug(TAG, "Subscribed to remote notifications");
}
This checks if the channel can be created and creates it: (is called in the mainActivity)
private void CreateNotificationChannel()
{
// The app is not running on Android 8.0 or higher
if (Build.VERSION.SdkInt < BuildVersionCodes.O)
{
// Notification channels are new in API 26 (and not a part of the
// support library). There is no need to create a notification
// channel on older versions of Android.
return;
}
// Create a notification channel for publishing notifications
var channel = new NotificationChannel(CHANNEL_ID, "FCM Notifications", NotificationImportance.Default)
{
Description = "Firebase Cloud Messages appear in this channel"
};
var notificationManager = (NotificationManager)GetSystemService(Android.Content.Context.NotificationService);
notificationManager.CreateNotificationChannel(channel);
}
This checks if playServices are available: (also called in mainActivity)
public bool IsPlayServicesAvailable()
{
int resultCode = GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.Success)
{
if (GoogleApiAvailability.Instance.IsUserResolvableError(resultCode))
{
Log.Debug(TAG, GoogleApiAvailability.Instance.GetErrorString(resultCode));
}
else
{
Log.Debug(TAG, "This device has no compatible Google Play services APK - Download an APK from the Google Play Store or to enable it in the device's system settings!");
Finish();
}
return false;
}
else
{
Log.Debug(TAG, "Google Play Services are available.");
return true;
}
}
The last snipped is the service to handle a notification and inform the user:
[Service]
[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
public class CustomFirebaseMessagingService : FirebaseMessagingService
{
// Logging Tag
private static readonly string TAG = "CustomFirebaseMessagingService";
/* Handles data messages and notifications messages if the app is in foreground.
*
* Apps only have 10 seconds in which to handle an incoming Firebase Cloud Message.
* Any work that takes longer than this should be scheduled for background execution using a library such as the 'Android Job Scheduler' or the 'Firebase Job Dispatcher'.
*
*/
public override void OnMessageReceived(RemoteMessage message)
{
Log.Debug(TAG, "Message from: " + message.From);
// If the message data payload is not empty, display a notification
if (message.Data.Count > 0)
{
Log.Debug(TAG, "Data Payload: " + message.Data.ToString());
this.SendNotification(message.Data);
}
}
// Converts the incoming FCM message into a local notification
private void SendNotification(IDictionary<string, string> data)
{
Console.WriteLine("Push Message received");
var intent = new Intent(this, typeof(MainActivity));
intent.AddFlags(ActivityFlags.ClearTop);
if (data.TryGetValue("message", out string message))
{
foreach (var key in data.Keys)
{
intent.PutExtra(key, data[key]);
}
var pendingIntent = PendingIntent.GetActivity(this, MainActivity.NOTIFICATION_ID, intent, PendingIntentFlags.OneShot);
var notificationBuilder = new NotificationCompat.Builder(this, MainActivity.CHANNEL_ID)
.SetSmallIcon(Resource.Drawable.NotificationIcon)
.SetContentTitle("TITEL")
.SetContentText(message)
.SetAutoCancel(true)
.SetContentIntent(pendingIntent);
var notificationManager = NotificationManagerCompat.From(this);
notificationManager.Notify(MainActivity.NOTIFICATION_ID, notificationBuilder.Build());
}
}
}

Why isn't my Xamarin.iOS app receiving push notifications from Google Firebase?

I'm trying to use Google Firebase to send push notifs to my Xamarin Forms App for iOS... I'm not receiving the notifications
To send the notifications I'm simply copying the Token out of my output window, putting my app in the background, and pasting the toking into the Firebase notif builder.
I receive the FCM Token so my App is definitely talking to Firebase.
So far I've tried:
Revoking my apple developer certificates and provisioning profile then making new ones.
I created A new Firebase project and Included the new GoogleService-Info.plist file (Build action -> BundleResource).. I didn't think that this would do anything
enabled remote notifications in the background mode of my info.plist
Any suggestions appreciated please!
public override bool FinishedLaunching(UIApplication app, NSDictionary
options)
{
global::Xamarin.Forms.Forms.Init();
UIApplication.SharedApplication.RegisterForRemoteNotifications();
Firebase.Core.App.Configure();
_connection = DependencyService.Get<ISQLiteDb>().GetConnection();
LoadApplication(application: new V5KitchenApp.App());
// Register your app for remote notifications.
if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
{
// iOS 10 or later
var authOptions = UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound;
UNUserNotificationCenter.Current.RequestAuthorization(authOptions, (granted, error) => {
Console.WriteLine(granted);
var token = Messaging.SharedInstance.FcmToken ?? "";
Console.WriteLine($"FCM token: {token}");
SendTokenToServer(token);
});
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.Current.Delegate = this;
// 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);
}
return base.FinishedLaunching(app, options);
}
Here's how I override DidReceiveRemoteNotification
public override void DidReceiveRemoteNotification(
UIApplication application,
NSDictionary userInfo,
Action<UIBackgroundFetchResult> completionHandler)
{
PresentNotification(userInfo);
completionHandler(UIBackgroundFetchResult.NewData);
}
And here's how I present the notification
void PresentNotification(NSDictionary dict)
{
NSDictionary aps = dict.ObjectForKey(new NSString("aps")) as NSDictionary;
var msg = string.Empty;
if (aps.ContainsKey(new NSString("alert")))
{
msg = (aps[new NSString("alert")] as NSString).ToString();
}
if (string.IsNullOrEmpty(msg))
{
msg = "(unable to parse)";
}
MessagingCenter.Send<object, string>(this, App.NotificationReceivedKey, msg);
}
I'm using Xamarin.Firebase.iOS.CloudMessaging v3.1.2 Xamarin.Firebase.iOS.Core v5.1.8 Xamarin.Firebase.iOS.InstanceID v2.0.0
The problem are Firebase versions
I used the next versions:
Xamarin.Firebase.iOS.InstanceID 2.0
Xamarin.Firebase.iOS.CloudMessaging 2.0
Xamarin.Firebase.iOS.Core 4.0.3
Xamarin.Firebase.iOS.Analtics 4.0.2

azure notification issue: apns works while template not response

Follow this tutorial "Add push notifications to your Xamarin.Forms app" for Xamarin.Forms development. After insert notification code in Azure backend and iOS, the notification template send out but no alert on device. However, the test sending of APNS shows the alert on the device. Appreciate any suggestion.
Here is my RegisteredForRemoteNotifications
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
const string templateBodyAPNS = "{\"aps\":{\"alert\":\"$(message)\"}}";
JObject templates = new JObject();
templates["genericMessage"] = new JObject
{
{"body", templateBodyAPNS}
};
/*
// Register for push with your mobile app
Push push = TodoItemManager.DefaultManager.CurrentClient.GetPush();
try
{
push.RegisterAsync(deviceToken, templates);
}
catch (System.Exception ex)
{
Debug.WriteLine(#"Register error: {0}", ex.Message);
}
*/
Hub = new SBNotificationHub(Constants.ConnectionString, Constants.NotificationHubName);
Hub.UnregisterAllAsync(deviceToken, (error) => {
if (error != null)
{
Console.WriteLine("Error calling Unregister: {0}", error.ToString());
return;
}
NSSet tags = new NSSet(); // create tags if you want
var expire = DateTime.Now.AddDays(90).ToString(); // set expire
try
{
//register native notification
Hub.RegisterNativeAsync(deviceToken, tags, (errorCallback) =>
{
if (errorCallback != null)
Console.WriteLine("RegisterNativeAsync error: " + errorCallback.ToString());
});
//register template notification
Hub.RegisterTemplateAsync(deviceToken, "add_newbook_notification", templateBodyAPNS, expire, tags, (errorCallback) => {
if (errorCallback != null)
Console.WriteLine("RegisterNativeAsync error: " + errorCallback.ToString());
});
}
catch (System.Exception ex)
{
Debug.WriteLine(#"Register error: {0}", ex.Message);
}
});
}
Because there could be multiple notification registration in one client app, theoretically both native and template notification registration should succeed here. However, I only receive the APNS but no template.
Azure Messaging - RegisterTemplateAsync isn't working? This link solves my problem.
Note:
The problem was that this ExpiryTemplate wasn't clear for me. I did find any docs on that one, but apparently, it's a DateTime formatted
as en-us.
The expiry datetime MUST be formatted as en-us. Otherwsie, the RegisterTemplateAsync can't work.

FCM on iOS An error occured on client IDB480752 while executing a reply for topic xvs/idb/4.8.0.752/stop-app

I added firecloud messaging to my iOS app as described here https://components.xamarin.com/gettingstarted/firebaseioscloudmessaging#subscribe-the-client-app-to-a-topic and it seems to work fine for both foreground and background notificaitons on initial run of the app. I am actually using the nuget Xamarin.Firebase.iOS.CloudMessaging not the component.
When I open the app a second time after having sent at least one push notification I get this error at launch in the debug output.
An error occured on client IDB480752 while executing a reply for topic xvs/idb/4.8.0.752/stop-app
Looking at the ide logs gives a little more detail.
NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)
2018-02-16 16:47:54.525 RecoveryConnect_Mobile_PCLiOS[1018:3202793] Encounter network error. Code, error: -1200, Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={NSURLErrorFailingURLPeerTrustErrorKey=, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, NSErrorPeerCertificateChainKey=(
"",
""
), NSUnderlyingError=0x10b0f5190 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, kCFStreamPropertySSLPeerTrust=, _kCFNetworkCFStreamSSLErrorOriginalValue=-9802, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, kCFStreamPropertySSLPeerCertificates=(
"",
""
)}}, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSErrorFailingURLKey=https://play.googleapis.com/log, NSErrorFailingURLStringKey=https://play.googleapis.com/log, NSErrorClientCertificateStateKey=0}
The app has been terminated.
Failed to Stop app: An error occured on client IDB480752 while executing a reply for topic xvs/idb/4.8.0.752/stop-app
The app has been terminated.
public partial class AppDelegate :
global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate,
IUNUserNotificationCenterDelegate, IMessagingDelegate
{
global::Xamarin.Forms.Forms.Init();
global::Xamarin.FormsMaps.Init();
App.BuildNumber = NSBundle.MainBundle.InfoDictionary[new
NSString("CFBundleVersion")].ToString();
LoadApplication(new App());
RegisterForPushNotifications();
return base.FinishedLaunching(app, options);
}
public override void DidEnterBackground(UIApplication uiApplication)
{
//Messaging.SharedInstance.ShouldEstablishDirectChannel = false;
Messaging.SharedInstance.Disconnect();
}
public override void OnActivated(UIApplication uiApplication)
{
ConnectFCM();
UIApplication.SharedApplication.ApplicationIconBadgeNumber = 0;
base.OnActivated(uiApplication);
}
private void RegisterForPushNotifications()
{
try
{
Firebase.Core.App.Configure();
if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
{
// iOS 10 or later
var authOptions = UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound;
UNUserNotificationCenter.Current.RequestAuthorization(authOptions, (granted, error) => {
Console.WriteLine(granted);
});
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.Current.Delegate = this;
// For iOS 10 data message (sent via FCM)
Messaging.SharedInstance.RemoteMessageDelegate = this;
}
else
{
// iOS 9 or before
var allNotificationTypes = UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound;
var settings = UIUserNotificationSettings.GetSettingsForTypes(allNotificationTypes, null);
UIApplication.SharedApplication.RegisterUserNotificationSettings(settings);
}
UIApplication.SharedApplication.RegisterForRemoteNotifications();
Firebase.InstanceID.InstanceId.Notifications.ObserveTokenRefresh((sender, e) =>
{
var newToken = Firebase.InstanceID.InstanceId.SharedInstance.Token;
var FCMTokenRegistration = new Models.Model_FCMToken(newToken);
FCMTokenRegistration.StoreToken();
// if you want to send notification per user, use this token
System.Diagnostics.Debug.WriteLine(newToken);
ConnectFCM();
});
}
catch(System.Exception ex)
{
Helpers.Helper_ErrorHandling.SendErrorToServer(ex);
}
}
private void ConnectFCM()
{
Messaging.SharedInstance.Connect(error => {
if (error != null)
{
// Handle if something went wrong while connecting
}
else
{
// Let the user know that connection was successful
}
});
}
public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, 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.
// Do your magic to handle the notification data
System.Console.WriteLine(userInfo);
}
// To receive notifications in foreground on iOS 10 devices.
[Export("userNotificationCenter:willPresentNotification:withCompletionHandler:")]
public void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
{
// Do your magic to handle the notification data
System.Console.WriteLine(notification.Request.Content.UserInfo);
}
// Receive data message on iOS 10 devices.
public void ApplicationReceivedRemoteMessage(RemoteMessage remoteMessage)
{
Console.WriteLine(remoteMessage.AppData);
}
[Export("userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:")]
public void DidReceiveNotificationResponse(UNUserNotificationCenter center, UNNotificationResponse response, Action completionHandler)
{
// Do your magic to handle the notification data
System.Console.WriteLine("");
}
public void DidRefreshRegistrationToken(Messaging messaging, string fcmToken)
{
var token = fcmToken;
//var newToken = Firebase.InstanceID.InstanceId.SharedInstance.Token;
//var FCMTokenRegistration = new Models.Model_FCMToken(newToken);
//FCMTokenRegistration.StoreToken();
//// if you want to send notification per user, use this token
//System.Diagnostics.Debug.WriteLine(newToken);
//ConnectFCM();
}
I did try adding NSAppTransportSecurity for arbitrary loads with no avail.

Firebase APN notification are not in the tray when app is in the background

For some reason notifications sent via Firebase don't get in the tray when the app is in the background. Here's the code that initialises Firebase (we're currently testing on iOS 10 using Xamarin in VS 2017). In AppDelegate.cs:
public void InitFirebase()
{
// Configure Firebase
App.Configure();
// Register your app for remote notifications.
if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
{
// iOS 10 or later
var authOptions = UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound;
UNUserNotificationCenter.Current.RequestAuthorization(authOptions, (granted, error) =>
{
Log.Info("BoaTan", "RequestAuthorization: {0}", granted);
});
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.Current.Delegate = this;
// For iOS 10 data message (sent via FCM)
Firebase.CloudMessaging.Messaging.SharedInstance.RemoteMessageDelegate = this;
// Monitor token generation
InstanceId.Notifications.ObserveTokenRefresh((sender, e) =>
{
Log.Info("BoaTan", "New firebase token received {0}", PlatformEntrance.Token);
LoginViewModel viewModel = LoginView.Me.ViewModel as LoginViewModel;
viewModel.UpdateFirebaseToken(PlatformEntrance.Token);
});
Firebase.CloudMessaging.Messaging.SharedInstance.Connect(error =>
{
if (error != null)
{
Log.Error("BoaTan", error.DebugDescription);
}
else
{
Log.Info("BoaTan", "Connection to Firebase messaging succeeded");
}
});
// Monitor token generation
InstanceId.Notifications.ObserveTokenRefresh((sender, e) =>
{
SendTokenToServer();
});
}
else
{
// iOS 9 or before
var allNotificationTypes = UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound;
var settings = UIUserNotificationSettings.GetSettingsForTypes(allNotificationTypes, null);
UIApplication.SharedApplication.RegisterUserNotificationSettings(settings);
}
UIApplication.SharedApplication.RegisterForRemoteNotifications();
}
In the AppDelegate.cs we also have the following code to receive the messages:
public override void WillEnterForeground(UIApplication application)
{
Firebase.CloudMessaging.Messaging.SharedInstance.Connect((NSError error) =>
{
Log.Info("BoaTan", "WillEnterForeground: Connected to Firebase messaging ({0})", error?.Description);
});
base.WillEnterForeground(application);
}
public override void DidEnterBackground(UIApplication application)
{
Firebase.CloudMessaging.Messaging.SharedInstance.Disconnect();
Log.Info("BoaTan", "DidEnterBackground: Disconnected from Firebase messaging");
base.DidEnterBackground(application);
}
// To receive notifications in foregroung on iOS 9 and below.
// To receive notifications in background in any iOS version
public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler)
{
Log.Info("BoaTan", "DidReceiveRemoteNotification: Disconnected from Firebase messaging");
SendDataMessage(userInfo);
}
// To receive notifications in foreground on iOS 10 devices.
[Export("userNotificationCenter:willPresentNotification:withCompletionHandler:")]
public void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
{
Log.Info("BoaTan", "WillPresentNotification: Disconnected from Firebase messaging");
SendDataMessage(notification.Request.Content.UserInfo);
}
public void ApplicationReceivedRemoteMessage(RemoteMessage message)
{
SendDataMessage(message.AppData);
}
/// <summary>
/// Use MvvmCross messaging to send a message to subcribers.
/// </summary>
/// <param name="dictionary"></param>
private void SendDataMessage(NSDictionary dictionary)
{
LogReceivedInfo(dictionary);
NSObject data;
NSString key = new NSString("data");
if (dictionary.TryGetValue(key, out data))
{
Log.Info("BoaTan", "Data: {0}", data);
Settings.Notification = JsonConvert.DeserializeObject<LoginNotificationParameter>((NSString)data);
ServicesHelper.SendMessage(this);
}
}
private void LogReceivedInfo(NSDictionary keyvalues)
{
Log.Info("BoaTan", "-----------------------------------------------------------");
foreach (var keyval in keyvalues)
{
Log.Info("BoaTan", "Key: {0} Value: {1}", keyval.Key, keyval.Value);
}
Log.Info("BoaTan", "-----------------------------------------------------------");
}
}
Message arrive perfectly when the App is in the foreground. All messages are queued until the App gets in the Foreground again.
This is in the info.plist:
<key>UIBackgroundModes</key>
<array>
<string>remote-notification</string>
<string>fetch</string>
</array>
When I go to the Firebase console and compose a message there in several variants the messages also don't arrive in the tray which leads me to the following conclusions:
The App is missing some configuration telling iOS I'm expecting messages.
Something missing is the configuration of APN at the Apple developer console.
Something missing in the Firebase/iOS configuration/initialization.
The permutations are endless. Who has the answer? And then there is still the challenge of iOS 9.
I have no experiences with Firebase on iOS but on Android I had the same problem.
Firebase has two types of messages: Notification message and Data message, see About FCM Messages
On Android the Notification message is only visible when the app is in foreground. Maybe this is also your problem
Don't know exactly why it started working but it works now. After deleting the App from my iPad and reinstalling it the tray started working too. My guess is that a redeploy keeps setting as they are and after a reinstall these were set correctly.

Resources