Unable to receive FCM push notification when iOS application is in background - ios

Currently I have been working on a xamarin ios application, and I am trying to implement push notification using firebase cloud messaging, I have updated the info.plist, Entitlement.plist
and also added the GoogleService-Info.plist i.e.
and here is what I have done in my AppDelegate.cs
using Foundation;
using UIKit;
using UserNotifications;
using Firebase.Core;
using Firebase.CloudMessaging;
using System;
using TrendSurveyApp.iOS;
using Newtonsoft.Json;
using System.Collections.Generic;
using AudioToolbox;
namespace CloudMessagingSample
{
// The UIApplicationDelegate for the application. This class is responsible for launching the
// User Interface of the application, as well as listening (and optionally responding) to application events from iOS.
[Register("AppDelegate")]
public class AppDelegate : UIApplicationDelegate, IUNUserNotificationCenterDelegate, IMessagingDelegate
{
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
// Override point for customization after application launch.
// If not required for your application you can safely delete this method
//(Window.RootViewController as UINavigationController).PushViewController(new DialogViewController1(this), true);
App.Configure();
Messaging.SharedInstance.Delegate = this;
UIRemoteNotificationType notificationTypes = UIRemoteNotificationType.Alert | UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound;
if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
{
UNUserNotificationCenter.Current.Delegate = this;
UNUserNotificationCenter.Current.RequestAuthorization(UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound,
(granted, error) =>
{
if (granted)
{
InvokeOnMainThread(UIApplication.SharedApplication.RegisterForRemoteNotifications);
}
});
}
else if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
{
var pushSettings = UIUserNotificationSettings.GetSettingsForTypes(
UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound,
new NSSet());
UIApplication.SharedApplication.RegisterUserNotificationSettings(pushSettings);
UIApplication.SharedApplication.RegisterForRemoteNotifications();
}
else
{
UIApplication.SharedApplication.RegisterForRemoteNotificationTypes(notificationTypes);
}
// To connect with FCM. FCM manages the connection, closing it
// when your app goes into the background and reopening it
// whenever the app is foregrounded.
Messaging.SharedInstance.ShouldEstablishDirectChannel = true;
return true;
}
public void DidReceiveRegistrationToken(Messaging messaging, string fcmToken)
{
// Monitor token generation: To be notified whenever the token is updated.
LogInformation(nameof(DidReceiveRegistrationToken), $"Firebase registration token: {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.
}
// You'll need this method if you set "FirebaseAppDelegateProxyEnabled": NO in GoogleService-Info.plist
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
Messaging.SharedInstance.ApnsToken = deviceToken;
}
public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler)
{
Messaging.SharedInstance.AppDidReceiveMessage(userInfo);
LogInformation(nameof(DidReceiveRemoteNotification), userInfo);
completionHandler(UIBackgroundFetchResult.NewData);
var myData = JsonConvert.DeserializeObject<List<string>>(userInfo[new NSString("webContentList")] as NSString);
}
[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;
LogInformation(nameof(DidReceiveMessage), remoteMessage.AppData);
}
[Export("userNotificationCenter:willPresentNotification:withCompletionHandler:")]
public void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
{
SystemSound.Vibrate.PlayAlertSound();
SystemSound.Vibrate.PlaySystemSound();
completionHandler(UNNotificationPresentationOptions.Alert);
}
void HandleMessage(NSDictionary message)
{
if (message == null)
return;
MessageType messageType;
if (message.ContainsKey(new NSString("aps")))
messageType = MessageType.Notification;
else
messageType = MessageType.Data;
var e = new UserInfoEventArgs(message, messageType);
}
void LogInformation(string methodName, object information) => Console.WriteLine($"\nMethod name: {methodName}\nInformation: {information}");
}
}
Now the problem is when the app is in background i am not receiving any notification neither any callback function such as didReceivedNotification is being hit while if i have the app opened in the foreground i can receive notification !! Need Help

Try this:
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
LoadApplication(new App());
Firebase.Core.App.Configure();
if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
{
// iOS => 10
var authOptions = UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound;
UNUserNotificationCenter.Current.RequestAuthorization(authOptions, (granted, error) =>
{
//request authorization method
Console.WriteLine(granted);
});
// For iOS 10+ display notification (sent via APNS)
UNUserNotificationCenter.Current.Delegate = this;
}
else
{
// iOS 9 <=
var allNotificationTypes = UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound;
var settings = UIUserNotificationSettings.GetSettingsForTypes(allNotificationTypes, null);
UIApplication.SharedApplication.RegisterUserNotificationSettings(settings);
}
UIApplication.SharedApplication.RegisterForRemoteNotifications();
return base.FinishedLaunching(application, launchOptions);
}

Related

iOS Background notification C# Xamarin via Firebase

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.

Xamarin Firebase iOS not receiving FCM messages

I tried to implement Firebase push notifications and messages in my Xamarin Forms application. In Android it works fine, while in iOS I am receiving push notifications but I'm not receiving FCM data-only messages.
I am using Xamarin.Firebase.iOS.CloudMessaging package, and I followed this guide and this other one too.
This is my AppDelegate.cs code:
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate, IUNUserNotificationCenterDelegate, IMessagingDelegate
{
//
// This method is invoked when the application has loaded and is ready to run. In this
// method you should instantiate the window, load the UI into it and then make the window
// visible.
//
// You have 17 seconds to return from this method, or iOS will terminate your application.
//
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
Forms.SetFlags("Brush_Experimental");
Rg.Plugins.Popup.Popup.Init();
//Ascetic.Plugins.PopupDecorations.iOS.PrettyPopup.Init();
global::Xamarin.Forms.Forms.Init();
SfListViewRenderer.Init();
new Syncfusion.SfAutoComplete.XForms.iOS.SfAutoCompleteRenderer();
Syncfusion.XForms.iOS.TabView.SfTabViewRenderer.Init();
iOSMaterialFrameRenderer.Init();
LoadApplication(new App());
// Register your app for remote notifications.
configureFirebase();
var result = base.FinishedLaunching(app, options);
app.KeyWindow.TintColor = UIColor.White;
foreach (var fs in UIFont.FamilyNames.OrderBy(c => c).ToList())
{
Console.WriteLine(" * " + fs);
foreach (var f in UIFont.FontNamesForFamilyName(fs).OrderBy(c => c).ToList())
{
Console.WriteLine(" *-- " + f);
}
}
return result;
}
private void configureFirebase()
{
Firebase.Core.App.Configure();
if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
{
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.Current.Delegate = this;
// iOS 10 or later
var authOptions = UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound;
UNUserNotificationCenter.Current.RequestAuthorization(authOptions, (granted, error) =>
{
});
// 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);
}
UIApplication.SharedApplication.RegisterForRemoteNotifications();
}
//Firebase
[Export("messaging:didReceiveRegistrationToken:")]
public void DidReceiveRegistrationToken(Messaging messaging, string fcmToken)
{
Preferences.Set("tokenNotifica", fcmToken);
Console.WriteLine("\nValue: " + (fcmToken));
}
//APP IN BACKGROUND
public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler)
{
handleNotification(userInfo);
completionHandler(UIBackgroundFetchResult.NewData);
}
[Export("userNotificationCenter:willPresentNotification:withCompletionHandler:")]
public void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification,
Action<UNNotificationPresentationOptions> completionHandler)
{
handleNotification(notification.Request.Content.UserInfo);
completionHandler(UNNotificationPresentationOptions.Sound | UNNotificationPresentationOptions.Alert);
}
[Export("userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:")]
public void DidReceiveNotificationResponse(UNUserNotificationCenter center, UNNotificationResponse response, Action
completionHandler)
{
completionHandler();
NSDictionary userInfo = response.Notification.Request.Content.UserInfo;
try
{
var Data = userInfo[new NSString("gcm.notification.data")] as NSString;
if (Data != null && Data != "")
{
string[] tokens = Data.ToString().Split(',');
string Username = tokens[0];
string Password = tokens[1];
var Title = string.IsNullOrEmpty(response.Notification.Request.Content.Title) ? "No Notification available" : response.Notification.Request.Content.Title;
var Body = string.IsNullOrEmpty(response.Notification.Request.Content.Body) ? "No Message available" : response.Notification.Request.Content.Body;
}
}
catch (Exception)
{
}
}
[Export("messaging:didReceiveMessage:")]
public void DidReceiveMessage(Messaging messaging, RemoteMessage message)
{
handleNotification(message.AppData);
}
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
Messaging.SharedInstance.ApnsToken = deviceToken;
}
public void ApplicationReceivedRemoteMessage(RemoteMessage remoteMessage)
{
;
}
}
The DidReceiveRegistrationToken method is called with the token. If I send a notification to that token the method DidReceiveRemoteNotification is called, and the notification is successfully shown by the device. But if I send a data-only message to that token, nothing is called.
I tried disabling swizzling, enabling it, reconfigure Firebase from scratch and delete and recreate certificates and provisioning profiles in the Apple Dev website, but nothing worked. Also, I think all is configured correctly since my app is receiving notifications.
I hope I gave enough information, I am struggling with this for weeks
EDIT
I use this function in php to send the data-only message to devices
function sendMessage($deviceKey, $data){
$curl = curl_init();
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
"Content-Type: application/json",
"project_id: ***",
"Authorization: key=***"
));
// Set some options - we are passing in a useragent too here
curl_setopt_array($curl, [
CURLOPT_URL => 'https://fcm.googleapis.com/fcm/send',
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_USERAGENT => 'Codular Sample cURL Request',
CURLOPT_POST => 1,
]);
$body = [
'to' => $deviceKey,
"data" => $data
];
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($body));
$res = json_decode(curl_exec($curl), true);
curl_close($curl);
return $res;
}
This function is equal to the function that send the notification, but the $body array doesn't contain a "notification" key.
What I would like to do is use the data payload of the message in the application without display the notification, and this works just fine in Android, but not in iOS.

FCM Xamarin.Forms, iOS background Notification doesnt show

Platform: iOS 10.2+
Xamarin Plugin: Firebase iOS cloud messaging https://components.xamarin.com/view/firebaseioscloudmessaging
Problem: When I send a notification from FireBase console or from my code calling FireBase. My iPhones don't receive the background notifications(as a bubble). But, if I had the application in foreground, I received the notification as a "DisplayAlert" from the function ApplicationReceivedRemoteMessage(RemoteMessage remoteMessage).
So, the device is registered on FCM, the device have the token, the device can receive the notifications, but the device didnt receive the notifications on background.
** In VisualStudio 2017 at .iOS project manifest I have the Background mode activated and the remote notifications activated too **
¿It's this a common issue? ¿Can I solve for working at my project?
Code of AppDelegate
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate, IUNUserNotificationCenterDelegate, IMessagingDelegate
{
protected SQLiteAsyncConnection conn;
//
// This method is invoked when the application has loaded and is ready to run. In this
// method you should instantiate the window, load the UI into it and then make the window
// visible.
//
// You have 17 seconds to return from this method, or iOS will terminate your application.
//
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
global::Xamarin.FormsMaps.Init();
CachedImageRenderer.Init();
LoadApplication(new App());
UITabBar.Appearance.SelectedImageTintColor = UIColor.FromRGB(139, 194, 77);
UINavigationBar.Appearance.TintColor = UIColor.FromRGB(139,194,77);
CrossVersionTracking.Current.Track();
// Firebase component initialize
Firebase.Analytics.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) => {
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) =>
{
newToken = Firebase.InstanceID.InstanceId.SharedInstance.Token;
//Conectamos con la base de datos.
database = new SQLiteClient();
conn = database.GetConnection();
usuario = null;
try
{
var task = Task.Run(async () =>
{
usuario = await conn.Table<Usuario>()
.FirstOrDefaultAsync();
});
task.Wait();
if (usuario != null)
{
usuario.token = newToken;
task = Task.Run(async () =>
{
await conn.InsertOrReplaceAsync(usuario);
});
task.Wait();
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("TOKEN ERROR\tNo se ha podido Guardar el Token" + ex.Message);
}
System.Diagnostics.Debug.WriteLine("TOKEN\t" + newToken);
connectFCM();
});
#endregion
return base.FinishedLaunching(app, options);
}
public override void DidEnterBackground(UIApplication uiApplication)
{
Messaging.SharedInstance.Disconnect();
Console.WriteLine("Disconnected from FCM");
}
public override void OnActivated(UIApplication uiApplication)
{
connectFCM();
base.OnActivated(uiApplication);
}
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
#if DEBUG
Firebase.InstanceID.InstanceId.SharedInstance.SetApnsToken(deviceToken, Firebase.InstanceID.ApnsTokenType.Sandbox);
#endif
#if RELEASE
Firebase.InstanceID.InstanceId.SharedInstance.SetApnsToken(deviceToken, Firebase.InstanceID.ApnsTokenType.Prod);
#endif
}
// iOS 9 <=, fire when recieve notification foreground
public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler)
{
Messaging.SharedInstance.AppDidReceiveMessage(userInfo);
// Generate custom event
NSString[] keys = { new NSString("Event_type") };
NSObject[] values = { new NSString("Recieve_Notification") };
var parameters = NSDictionary<NSString, NSObject>.FromObjectsAndKeys(keys, values, keys.Length);
// Send custom event
Firebase.Analytics.Analytics.LogEvent("CustomEvent", parameters);
if (application.ApplicationState == UIApplicationState.Active)
{
System.Diagnostics.Debug.WriteLine(userInfo);
var aps_d = userInfo["aps"] as NSDictionary;
var alert_d = aps_d["alert"] as NSDictionary;
var body = alert_d["body"] as NSString;
var title = alert_d["title"] as NSString;
debugAlert(title, body);
}
}
// iOS 10, fire when recieve notification foreground
[Export("userNotificationCenter:willPresentNotification:withCompletionHandler:")]
public void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
{
System.Console.WriteLine(notification.Request.Content.UserInfo);
var title = notification.Request.Content.Title;
var body = notification.Request.Content.Body;
debugAlert(title, body);
}
private void connectFCM()
{
Console.WriteLine("connectFCM\tEjecutandose la función.");
Messaging.SharedInstance.Connect((error) =>
{
if (error == null)
{
//TODO: Change Topic to what is required
Messaging.SharedInstance.Subscribe("/topics/all");
}
//System.Diagnostics.Debug.WriteLine("connectFCM\t" + (error != null ? "error occured" : "connect success"));
Console.WriteLine("connectFCM\t" + (error != null ? "error occured" + error.DebugDescription : "connect success"));
});
}
private void debugAlert(string title, string message)
{
var alert = new UIAlertView(title ?? "Title", message ?? "Message", null, "Cancel", "OK");
alert.Show();
}
public void ApplicationReceivedRemoteMessage(RemoteMessage remoteMessage)
{
Console.WriteLine("\n*******************************************");
Console.WriteLine("AplicationReceivedRemoteMessage\t" + remoteMessage.AppData);
Console.WriteLine("\n*******************************************");
var title = remoteMessage.AppData.ValueForKey(new NSString("title"));
var text = remoteMessage.AppData.ValueForKey(new NSString("text"));
debugAlert("" + title, "" + text);
}
[Export("userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:")]
public void DidReceiveNotificationResponse(UNUserNotificationCenter center, UNNotificationResponse response, Action completionHandler)
{
debugAlert("DidreceiveNotificationResponse", response + "" );
}
For more info, my info.plist contais the key:
<key>UIBackgroundModes</key>
<array>
<string>location</string>
<string>bluetooth-central</string>
<string>bluetooth-peripheral</string>
<string>fetch</string>
<string>remote-notification</string>
</array>
After a long investigation I solve it.
It is necesary to add that key to Entile.plist file.
<dict>
<key>aps-environment</key>
<string>development</string>
</dict>

Xamarin.Forms - Push Notification - iOS

I try to add to my project GCM for iOS
(https://components.xamarin.com/view/googleiosgcm)
This is my code:
[Register ("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate, IInstanceIdDelegate, IReceiverDelegate
{
public Google.Core.Configuration Configuration { get; set; }
NSData DeviceToken { get; set; }
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
NSError err;
Google.Core.Context.SharedInstance.Configure (out err);
if (err != null)
Console.WriteLine ("Failed to configure Google: {0}", err.LocalizedDescription);
Configuration = Google.Core.Context.SharedInstance.Configuration;
// Configure and Start GCM
var gcmConfig = Google.GoogleCloudMessaging.Config.DefaultConfig;
gcmConfig.ReceiverDelegate = this;
Service.SharedInstance.Start (gcmConfig);
// Register for remote notifications
var notTypes = UIUserNotificationType.Sound | UIUserNotificationType.Alert | UIUserNotificationType.Badge;
var settings = UIUserNotificationSettings.GetSettingsForTypes (notTypes, null);
UIApplication.SharedApplication.RegisterUserNotificationSettings (settings);
UIApplication.SharedApplication.RegisterForRemoteNotifications ();
global::Xamarin.Forms.Forms.Init ();
LoadApplication (new App ());
return base.FinishedLaunching (app, options);
}
public override void RegisteredForRemoteNotifications (UIApplication application, NSData deviceToken)
{
// Save our token in memory for future calls to GCM
DeviceToken = deviceToken;
// Configure and start Instance ID
var config = Google.InstanceID.Config.DefaultConfig;
InstanceId.SharedInstance.Start (config);
// Get a GCM token
GetToken ();
}
void GetToken ()
{
// Register APNS Token to GCM
var options = new NSDictionary ();
options.SetValueForKey (DeviceToken, Constants.RegisterAPNSOption);
options.SetValueForKey (new NSNumber(true), Constants.APNSServerTypeSandboxOption);
// Get our token
InstanceId.SharedInstance.Token (
"1055xxxx" ,//My sender id here,
Constants.ScopeGCM,
options,
(token, error) => Console.WriteLine ("GCM Registration ID: " + token));
}
public override void DidReceiveRemoteNotification (UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler)
{
// Your own notification handling logic here
// Notify GCM we received the message
Service.SharedInstance.AppDidReceiveMessage (userInfo);
}
public override void OnActivated (UIApplication application)
{
Service.SharedInstance.Connect (error => {
if (error != null)
Console.WriteLine ("Could not connect to GCM: {0}", error.LocalizedDescription);
else
Console.WriteLine ("Connected to GCM");
});
}
public override void DidEnterBackground (UIApplication application)
{
Service.SharedInstance.Disconnect ();
}
public void DeleteToken ()
{
InstanceId.SharedInstance.DeleteToken (
"1055xxxx" ,//My sender id here
Constants.ScopeGCM,
error => {
// Callback, non-null error if there was a problem
if (error != null)
Console.WriteLine ("Deleted Token");
else
Console.WriteLine ("Error deleting token");
});
}
int messageId = 1;
// We can send upstream messages back to GCM
public void SendUpstreamMessage ()
{
var msg = new NSDictionary ();
msg.SetValueForKey (new NSString ("1234"), new NSString ("userId"));
msg.SetValueForKey (new NSString ("hello world"), new NSString ("msg"));
var to = "1055xxxxxx" + "#gcm.googleapis.com";
Service.SharedInstance.SendMessage (msg, to, (messageId++).ToString ());
}
[Export ("didDeleteMessagesOnServer")]
public void DidDeleteMessagesOnServer ()
{
// ...
}
[Export ("didSendDataMessageWithID:")]
public void DidSendDataMessage (string messageID)
{
// ...
}
[Export ("willSendDataMessageWithID:error:")]
public void WillSendDataMessage (string messageID, NSError error)
{
// ...
}
and this is console:
You have enabled the CloudMessaging service in Developer Console, but it appears as though your Podfile is missing the line: 'pod "Google/CloudMessaging" or you may need to run pod update in your project directory.
2016-04-26 20:54:43.197 xxxx.iOS[2072:94709] Failed to configure Google: Missing expected subspaces.
GCM | GCM registration is not ready with auth credentials
2016-04-26 20:54:47.712 xxxxxxxx.iOS[2072:94709] Could not connect to GCM: The operation couldn’t be completed. (com.google.gcm error 501.)
I do it from Xamarin.Forms - maybe this is problem???
I did ALL step from getting start but got this problem
Any idea guys what is problem???
For sure - I added file from google to resource folder add did build action - BundleResource
and in info.plist checked remove-notification module
As per the gcm documentation, you should have cocoa pods to integrate their framework.
So make sure you added/update gcm with cocoa pod.
As per the log, pod is not updated.

Push Notification in Xamarin Forms

I'm trying to implement Push Notification in PCL app in Xamarin forms IOS. I have a suitable provisioning profile and p12 file that I used to send notification to native app and I'm using it on my Xamarin forms, do I need to do something more beside this changes? I changed the AppDelegate in the IOS project to look like this:
using System;
using System.Collections.Generic;
using System.Linq;
using Foundation;
using UIKit;
namespace Punteam.iOS
{
[Register ("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
String model = UIDevice.CurrentDevice.Model;
String sysName = UIDevice.CurrentDevice.SystemName;
String sysVer = UIDevice.CurrentDevice.SystemVersion;
NSUserDefaults.StandardUserDefaults.SetString (model, "Model");
NSUserDefaults.StandardUserDefaults.SetString (sysName, "sysName");
NSUserDefaults.StandardUserDefaults.SetString (sysName, "sysVer");
if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
{
var pushSettings = UIUserNotificationSettings.GetSettingsForTypes(
UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound,
new NSSet());
UIApplication.SharedApplication.RegisterUserNotificationSettings(pushSettings);
UIApplication.SharedApplication.RegisterForRemoteNotifications();
}
else
{
UIRemoteNotificationType notificationTypes = UIRemoteNotificationType.Alert | UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound;
UIApplication.SharedApplication.RegisterForRemoteNotificationTypes(notificationTypes);
}
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());
return base.FinishedLaunching(app, options);
}
//***********************************************************************************************
//** RegisteredForRemoteNotifications *
//***********************************************************************************************
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
// Get current device token
var DeviceToken = deviceToken.Description;
if (!string.IsNullOrWhiteSpace(DeviceToken)) {
DeviceToken = DeviceToken.Trim('<').Trim('>');
}
// 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");
}
//***********************************************************************************************
//** ReceivedRemoteNotification *
//***********************************************************************************************
public override void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo)
{
ProcessNotification(userInfo, false);
}
//***********************************************************************************************
//** ProcessNotification *
//***********************************************************************************************
void ProcessNotification(NSDictionary options, bool fromFinishedLaunching)
{
// Check to see if the dictionary has the aps key. This is the notification payload you would have sent
if (null != options && options.ContainsKey(new NSString("aps")))
{
//Get the aps dictionary
NSDictionary aps = options.ObjectForKey(new NSString("aps")) as NSDictionary;
string alertString = string.Empty;
string paramString = string.Empty;
if (aps.ContainsKey(new NSString("alert")))
alertString = (aps[new NSString("alert")] as NSString).ToString();
if (aps.ContainsKey(new NSString("param")))
paramString = (aps[new NSString("param")] as NSString).ToString();
if (!fromFinishedLaunching)
{
//Manually show an alert
if (!string.IsNullOrEmpty(alertString))
{
UIAlertView avAlert = new UIAlertView("Awesome Notification", alertString , null,
NSBundle.MainBundle.LocalizedString("Cancel", "Cancel"),
NSBundle.MainBundle.LocalizedString("OK", "OK"));
avAlert.Clicked += (sender, buttonArgs) =>
{
if (buttonArgs.ButtonIndex != avAlert.CancelButtonIndex)
{
if (!string.IsNullOrEmpty(paramString))
{
// App.Current.MainPage = new NavigationPage(new PushNotifMessageDisplay(paramString));
}
}
};
avAlert.Show();
}
}
}
}
//***********************************************************************************************
//** FailedToRegisterForRemoteNotifications *
//***********************************************************************************************
public override void FailedToRegisterForRemoteNotifications (UIApplication application , NSError error)
{
new UIAlertView("Error registering push notifications", error.LocalizedDescription, null, "OK", null).Show();
}
}
}
You can check my full example for push notification here
Regarding the iOS part, this is the relevant code that goes to your AppDelegate:
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
var deviceTokenString = deviceToken.ToString().Replace("<","").Replace(">", "").Replace(" ", "");
var notificationService = Resolver.Resolve<IPushNotificationService>();
var pushNotificationRegister = Resolver.Resolve<IPushNotificationRegister>();
if (pushNotificationRegister.ShouldSendToken(deviceTokenString))
{
var uid = UIDevice.CurrentDevice.IdentifierForVendor.AsString();
notificationService.AddPushToken(deviceTokenString, DeviceUtils.GetDeviceType(), uid);
}
}
*IPushNotificationRegister - checks if the token is already sent to the server (it is done to avoid unneeded requests to the server).
*IPushNotificationService - The service to send the token to the server.

Resources