Local Push notification not working in Xamarin iOS - xamarin

I am using Xamarin.forms and implemented Local push notification for iOS. It is working successfully when I am debugging the app through visual studio even when the app is minimized, the app can able to receive the notification. But while running the app directly without debugging through visual studio, the app is not able to display the notification. Kindly guide me on this.
Then I also tried by releasing the app to the app store but experienced the same, the app is not able to receive the notification it not even in foreground mode.
I already have selected the "Background fetch" property under Background Modes in Info.plist.
I have also added below the line in my FinishedLaunching method
UIApplication.SharedApplication.SetMinimumBackgroundFetchInterval(UIApplication.BackgroundFetchIntervalMinimum);
Entire Implementation of code is as below
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
try
{
UIApplication.SharedApplication.SetMinimumBackgroundFetchInterval(UIApplication.BackgroundFetchIntervalMinimum);
try
{
if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
{
UNUserNotificationCenter.Current.RequestAuthorization(UNAuthorizationOptions.Alert |
UNAuthorizationOptions.Sound |
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
{
UIRemoteNotificationType notificationTypes = UIRemoteNotificationType.Alert | UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound;
UIApplication.SharedApplication.RegisterForRemoteNotificationTypes(notificationTypes);
}
bool IsRegistered = UIApplication.SharedApplication.IsRegisteredForRemoteNotifications;
}
catch (Exception ex)
{
UIAlertView avAlert = new UIAlertView("FinishedLaunching Push Notification Exception", ex.Message, null, "OK", null);
avAlert.Show();
}
UNUserNotificationCenter.Current.Delegate = new UserNotificationCenterDelegate();
LoadApplication(new MessengerClient.App());
}
catch (Exception ex)
{
NativeHelper.SendUnhandledException(ex, NativeHelper.iOS + ": FinishedLaunching");
}
return base.FinishedLaunching(app, options);
}
public override void ReceivedLocalNotification(UIApplication application, UILocalNotification notification)
{
/// reset our badge
UIApplication.SharedApplication.ApplicationIconBadgeNumber = 0;
/// Cancel/clear all Local notifications fronm the tray.
UIApplication.SharedApplication.CancelLocalNotification(notification);
/// Cancel/clear all notifications fronm the tray.
UIApplication.SharedApplication.CancelAllLocalNotifications();
}
code for displaying the notification is as below.
UILocalNotification notification = new UILocalNotification();
notification.FireDate = NSDate.FromTimeIntervalSinceNow(1);
notification.AlertAction = title;
notification.AlertBody = content;
notification.AlertTitle = title;
notification.SoundName = UILocalNotification.DefaultSoundName;
notification.ApplicationIconBadgeNumber = 1;
UIApplication.SharedApplication.ScheduleLocalNotification(notification);
I know this is the repeat question but, I tried all the workaround but didn't work for me.

You can have a check with this Notifications in Xamarin.iOS .
iOS applications handle remote and local notifications in almost exactly the same fashion. When an application is running, the ReceivedLocalNotification method or the ReceivedRemoteNotification method on the AppDelegate class will be called, and the notification information will be passed as a parameter.
An application can handle a notification in different ways. For instance, the application might just display an alert to remind users about some event. Or the notification might be used to display an alert to the user that a process has finished, such as synching files to a server.
The following code shows how to handle a local notification and display an alert and reset the badge number to zero:
public override void ReceivedLocalNotification(UIApplication application, UILocalNotification notification)
{
// show an alert
UIAlertController okayAlertController = UIAlertController.Create(notification.AlertAction, notification.AlertBody, UIAlertControllerStyle.Alert);
okayAlertController.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Default, null));
Window.RootViewController.PresentViewController(okayAlertController, true, null);
// reset our badge
UIApplication.SharedApplication.ApplicationIconBadgeNumber = 0;
}
In addition , there is a sample you can download to check . It works no matter in Debug or Release Model in my local site (iOS 13.3).
The effect :

Just add this code in your AppDelegate DidFinishLaunching and notification will start working in the background. BackgroundTask- showNotification may get canceled sometime, for me whenever my dashboard is loaded, I guess as it has multiple API Calls. so add it in your DidEnterBackground Delegate as well with different taskID, to start a new background task. It works fine for me.
nint taskID = yourTaskID;
taskID = application.BeginBackgroundTask("showNotification", expirationHandler: ()=> {
UIApplication.SharedApplication.EndBackgroundTask(taskID);
});

Related

Xamarin Forms iOS Remote Notifications Not Displaying

Remote Notifications are not displaying on the device.
We are using iOS 11.2 and Twilio.
We have generated the APN in Apple Developer Portal and exported the
certificate and key into Twilio.
Twilio says the message is "sent," but it never displays on the
device.
The goal is to send a message with a simple header and body text, and have that display as a remote push notification on the device.
The Xamarin documentation seems incomplete, and I cannot find clear instructions on how to handle displaying the notification. I have looked at the Xamarin samples, but they mostly cover local notifications.
Questions are below in the comments. What is missing?
using Foundation;
using UserNotifications;
using UIKit;
namespace MyNotifications.iOS
{
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
protected UIWindow window;
protected string deviceToken = string.Empty;
public string DeviceToken { get { return deviceToken; } }
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());
// check for a notification while running
if (options != null)
{
if (options.ContainsKey(UIApplication.LaunchOptionsRemoteNotificationKey))
{
NSDictionary remoteNotification = options[UIApplication.LaunchOptionsRemoteNotificationKey] as NSDictionary;
if (remoteNotification != null)
{
//1) is this necessary to handle??? if so, how to display? what are the properties from the remoteNotification object that contain the text?
}
}
}
//this prompts for permissions, which are set
if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
{
var notificationSettings = UIUserNotificationSettings.GetSettingsForTypes(
UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound, null
);
app.RegisterUserNotificationSettings(notificationSettings);
app.RegisterForRemoteNotifications();
}
else
{
UIRemoteNotificationType notificationTypes = UIRemoteNotificationType.Alert | UIRemoteNotificationType.Badge;
UIApplication.SharedApplication.RegisterForRemoteNotificationTypes(notificationTypes);
}
UNUserNotificationCenter.Current.GetNotificationSettings((settings) =>
{
var alertsAllowed = (settings.AlertSetting == UNNotificationSetting.Enabled);
});
// Request notification permissions from the user
UNUserNotificationCenter.Current.RequestAuthorization(UNAuthorizationOptions.Alert, (approved, err) =>
{
// 2) how do we handle this??? what comes next?
});
return base.FinishedLaunching(app, options);
}
// 3) does this override need to do anything???
public override void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo)
{
// 4) should all of these trigger a notification? does that have to happen manually?
if (application.ApplicationState == UIApplicationState.Active)
{
ProcessPushNotification(userInfo, true);
}
else if (application.ApplicationState == UIApplicationState.Background)
{
ProcessPushNotification(userInfo, true);
}
else if (application.ApplicationState == UIApplicationState.Inactive)
{
ProcessPushNotification(userInfo, true);
}
}
protected void ProcessPushNotification(NSDictionary userInfo, bool isAppAlreadyRunning)
{
if (userInfo == null) return;
if (isAppAlreadyRunning)
{
// 5) do we need to generate our own view???
}
else
{
// 6) how to handle in the background???
}
}
// APNS background
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
deviceToken = deviceToken.ToString();
}
// Handle errors and offline
public override void FailedToRegisterForRemoteNotifications(UIApplication application, NSError error)
{
// 7) what to do here???
}
}
}
Microsoft Docs has a few guides on how to deal with push notifications on both platforms, iOS and Android. Most of them are sending notifications from an Azure Notifications Hub but in this case, it shouldn't make any difference, because your question is about displaying push notifications, and not sending them.
The guide on how to send and receive notifications in a Xamarin.Forms app gives you an idea of the complete end-to-end setup. There are also two slightly different guides with a focus on Azure here and here
And for rendering messages on iOS, if the app is backgrounded, the notification is rendered by iOS without any custom code so if the app is properly configured and signed, you should be able to see a push notifications without any additional client-side code, just make sure you test on a device (sims doesn't support pushes) and valid profile with pushes enabled.

How can I make my application prompt a "Would like to send you notifications" message when first opened?

I just downloaded an application (not mine) for my studies and noticed that the first time it's opened that a message saying it would like to send me notifications appears. Can anyone explain how to code this to happen with a Forms application? Below is a screen print to show what I mean.
#Timo's answer isn't wrong but few subtle thing are there which should be noticed.
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
//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;
//Messaging.SharedInstance.Delegate = this; //FCM
}
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();
//App.Configure(); If using firebase
return true;
}
On iOS, you need to use the UNUserNotificationCenter to request the authorization by modifying the AppDelegate class:
public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions)
{
// Ask for the permission to send notifications
UNUserNotificationCenter.Current.RequestAuthorization (UNAuthorizationOptions.Alert, (approved, err) => {
// User approved
});
return true;
}
On Android, you don't have to ask for push notification permission separately and no changes are required in your code as long as you have the INTERNET permission set up.

On Urban airship push notifican arise than app crash in xamarin.forms

I am creating Push notification with deep links and I test deep link but it works fine for me and redirect me to a particular page and when I try to handle notification at that time app is terminated and app is in crash mode and at that time I try to find best solution but I can't find any If there is anyone who can help than I thankful to His/Her.
My Code for handle notification is listed below:
public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo,
Action<UIBackgroundFetchResult> completionHandler)
{
try
{
UIApplication.SharedApplication.ApplicationIconBadgeNumber = 0;
NSDictionary aps = userInfo.ObjectForKey(new NSString("aps")) as NSDictionary;
var notificationTitle = (aps[new NSString("title")] as NSString).ToString();
var notificationMessage = (aps[new NSString("job_id")] as NSString).ToString();
var NotificationId = (aps[new NSString("notification_id")] as NSString).ToString();
if (UIApplication.SharedApplication.ApplicationState.Equals(UIApplicationState.Active))
{
//App is in foreground. Act on it.
}
else
{
App.Current.MainPage = new AppliedJobDetails(null, notificationMessage, NotificationId);
}
}
catch (Exception ex)
{
//LogInfo.ReportErrorInfo(ex.Message, ex.StackTrace, "AppDelegate-DidReceiveRemoteNotification");
}
}
If there is anyone who get a best solution please help me and my try to approach in iOS device.

How to resume the application and open a specific page with a push notification in Xamarin.forms

I'm currently working on a Xamarin application working both on iOS and Android, but the problem I'm going to explain only concerns the Android application (this is not yet implemented in the iOS app).
Actually, when I receive a given push notification, I need to open a specific page in my application. It works very well if the application is open when the push notification is received, but the app crashes if my app is closed or run in background.
Well, when I receive the notification, I end up in the method called "OnShouldOpenCommand" :
private void OnShouldOpenCommand(string commandId)
{
NotifyNewCommand(AppResources.AppName, AppResources.CommandNotificationText, commandId);
Device.BeginInvokeOnMainThread(() =>
{
try
{
App.MasterDetailPage.Detail = new NavigationPage(new CommandAcceptancePage(commandId))
{
BarBackgroundColor = Color.FromHex("1e1d1d")
};
App.MasterDetailPage.NavigationStack.Push(((NavigationPage)(App.MasterDetailPage.Detail)).CurrentPage);
}
catch(Exception e)
{
Log.Debug("PushAsync", "Unable to push CommandAcceptancePage : "+ex.Message);
}
});
}
private void NotifyNewCommand(string Title,string Description, string commandId)
{
var intent = new Intent(this, typeof(MainActivity));
if (!String.IsNullOrEmpty(commandId))
{
intent.PutExtra("CommandId", commandId);
}
intent.AddFlags(ActivityFlags.ClearTop);
var pendingIntent = PendingIntent.GetActivity(this, 0, intent, 0);
var notificationBuilder = new Notification.Builder(this)
.SetSmallIcon(Resource.Drawable.icon)
.SetContentTitle("Kluox")
.SetContentText(Description)
.SetAutoCancel(true)
.SetContentIntent(pendingIntent);
Notification notification = notificationBuilder.Build();
var notificationManager = (NotificationManager)GetSystemService(Context.NotificationService);
notificationManager.Notify(0, notification);
}
And the code
App.MasterDetailPage.Detail = new NavigationPage(new CommandAcceptancePage(commandId))
{
BarBackgroundColor = Color.FromHex("1e1d1d")
};
is generating an exception of type :
Java.Lang.IllegalStateException: Can not perform this action after
onSaveInstanceState
So well, I suppose I can't access "App" and redirect to another page if my application is not running in foreground. Well, this is when I receive the push notification an not when I click on it. But well, I do not intend to reopen my app by doing this.
Because afther that, when I click on the push notification called Kluox (and this is supposed to reopen my app), the app crashes and I really don't know why, I don't know where to put breakpoints to be able to debug because Visual Studio just tells me "An unhandled exception occured.".
Could anyone help me ? If you need any piece of code, you can just ask me, I'll edit my message and give you any information you need !
EDIT 1 : Here is the code of my OnCreate method :
protected override void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
var info = Intent.Extras?.GetString("CommandId", "");
global::Xamarin.Forms.Forms.Init(this, bundle);
if (String.IsNullOrEmpty(info))
{
LoadApplication(new App());
}
else
{
LoadApplication(new App(info));
}
if (instance == null)
{
instance = this;
RegisterWithGCM();
}
else
{
instance = this;
}
}
After overriding all the methods of MainActivity, I finally found the cause of the crash : the method OnDestroy was called twice, and threw a IllegalStateException because the activity was already destroyed. I found this workaround :
protected override void OnDestroy()
{
try
{
base.OnDestroy();
}
catch (Java.Lang.IllegalStateException ex)
{
Log.Debug("MainActivity.OnDestroy", ex, "The activity was destroyed twice");
}
}
And the exception is simply logged, the application can open and be used without problems.
I'll edit this answer when the redirection works too.
EDIT : how to redirect to a page
First, we needed to register for the MessagingCenter, in the constructor
public static MyPackage.Model.Command CurrentCommand { get; set; }
public App()
{
InitializeComponent();
MainPage = new ContentPage();
MessagingCenter.Subscribe<object, DataLib.Model.Command>(this, "Command", (sender, arg) => {
try
{
CurrentCommand = arg;
}
catch(Exception ex)
{
CurrentCommand = null;
}
});
}
And send the message when we get the push notification :
private void OnMessage(string serializedCommand)
{
//stuff happens
MessagingCenter.Send<object, MyPackage.Model.Command>(this, "Command", command);
}
Finally, when we get the OnStart() of App.Xaml.cs
if (CurrentCommand != null)
{
App.MasterDetailPage.Detail = new NavigationPage(new CommandAcceptancePage(CurrentCommand, service))
{
BarBackgroundColor = Color.FromHex("1e1d1d")
};
}
For now, it seems to do the trick ! More debugging will follow, but the code seems to work. Thanks a VERY lot to #BraveHeart for their help !
well luckily for you I was there few days ago and lost a lot of hair till I got it working in Android (and still in the strugle for iOS).
When you kill your app and instantiate it again form the icon or from the notification in both cases you will go to the main activity .
If we want to take some information in the main activity from the notification that instantiated it we do it like this in OnCreate():
var info = Intent.Extras?.GetString("info", "");
Now in your case I would add extra information to the notification showing that which View/Page this notification is about, something like the name of it for example)
This extra piece of information you can pass it to the constructor of the App before you load it.
In the constructor of the app you can check if there are extra info or not , if not that means to start the app's mainPage is the default MainPage, otherwise it is a certain page.

Xamarin.Forms - Toasts(Banners) - Alerts - in iOS and Android in Background

I try to show toasts(banners) notification - while application in the background.
I checked background fetch and push notification. I also received push notification when app in foreground.
But when my app in background - I only see how change my badges count - but i don't see notification
This is my code:
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init ();
LoadApplication (new App ());
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);
}
return base.FinishedLaunching (app, options);
}
and
public override void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo)
{
NSDictionary dic = userInfo.ObjectForKey(new NSString("aps")) as NSDictionary;
var test = (dic[new NSString("test")] as NSString).ToString();
var alert = new UIAlertView ("Test title", "This is message", null, "Ok", "Button");
alert.Clicked += (object sender, UIButtonEventArgs e) => {Console.WriteLine(e.ButtonIndex);};
alert.Show ();
}
So how i say - in foreground all works great but in background I only see the new count of badges.
I also find this plugin:
https://components.xamarin.com/view/alert-center
But I want to understand how to write it without plugin.
Thank you.
Ok - I solved it !
For developers who will take same problem:
I just don't send ALERT object in aps json to ios.

Resources