I've been trying to implement a BackgroundTask for Raw Push Notifications on my Windows and Windows Phone 8.1 apps but it doesn't seem to be working. I've successfully managed to get toast based push notifications working but as far as I'm aware a Raw notification silently pushes data to the app and it's up to the app to display a toast notification or update the app's tile.
I've looked at the BackgroundTask Sample and followed it exactly yet nothing works (https://code.msdn.microsoft.com/windowsapps/Background-Task-Sample-9209ade9).
Here's the steps I've taken
Created a Windows Runtime Component Project in the same solution as my other projects (Called NotificationServer)
Renamed the class to RawTask.cs and implemented IBackgroundTask and its Run method
Created a method to create a toast notification
private void SendNotification(string text)
{
XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText01);
XmlNodeList elements = toastXml.GetElementsByTagName("text");
foreach (IXmlNode node in elements)
{
node.InnerText = text;
}
ToastNotification notification = new ToastNotification(toastXml);
ToastNotificationManager.CreateToastNotifier().Show(notification);
}
Added code to the Run method
BackgroundTaskDeferral _deferral = taskInstance.GetDeferral();
RawNotification notification = (RawNotification)taskInstance.TriggerDetails;
string content = notification.Content;
// ...
SendNotification("test");
// ...
_deferral.Complete();
Updated my App's manifest to Toast Capable = YES and Lock Screen Notifications = Badge
Added a Declaration for a Background Task with Supported Task Type = Push Notification and Entry Point = NotificationServer.RawTask
Added code to register the Background Task
public static BackgroundTaskRegistration RegisterBackgroundTask(string taskEntryPoint,
string taskName,
IBackgroundTrigger trigger,
IBackgroundCondition condition)
{
//
// Check for existing registrations of this background task.
//
foreach (var cur in BackgroundTaskRegistration.AllTasks)
{
if (cur.Value.Name == taskName)
{
//
// The task is already registered.
//
return (BackgroundTaskRegistration)(cur.Value);
}
}
//
// Register the background task.
//
var builder = new BackgroundTaskBuilder();
builder.Name = taskName;
builder.TaskEntryPoint = taskEntryPoint;
builder.SetTrigger(trigger);
if (condition != null)
{
builder.AddCondition(condition);
}
BackgroundTaskRegistration task = builder.Register();
return task;
}
And executing it with
var reg = RegisterBackgroundTask("NotificationServer.RawTask", "RawNotifications", new PushNotificationTrigger(), null);
Is there something I'm missing here, my app doesn't seem to be responding to the Push Notification event. I have made sure my app is associated with the app in the store and the pushes are being sent with the correct client secret and app ID.
There are four types of push notifications:
Tile update
Badge update
Toast notification
Raw notification
All Windows Runtime apps can use the first three push notifications when in the foreground. Only lock screen apps can receive raw push notifications from WNS.
so, you must make your app a lock screen app.
You can follow this topic to do that.
Related
i am trying to understand how an android app on a device could send a notification to another android app on another device when a user adds a record to sql server database or deletes one. i started my research and figured out that i must use FCM. i applied this tutorial https://learn.microsoft.com/en-us/xamarin/android/data-cloud/google-messaging/remote-notifications-with-fcm?tabs=windows and it worked but it didn't help me understand how the android app well send the notification. i tried to apply codes from java like this one https://blog.heyday.xyz/send-device-to-device-push-notifications-without-server-side-code-238611c143, i tried to convert it to c# but it didn't work for me. i actually didn't know how to completely write it as c#. i also tried this one: Xamarin android FCM Notification Client to client(phone to phone) but in vain. i searched a lot but i don't know why it feels complicated. if anyone could help me find a tutorial to do so. thanks in advance.
To send notifications from one device to another in Xamarin.android there are several ways:
using firebase cloud messaging when add new row to database
Example:
//process that add new row
//post on FCM
note: receive device must be register device token in firebase cloud messaging
for more details:
https://learn.microsoft.com/en-us/xamarin/android/data-cloud/google-messaging/firebase-cloud-messaging
using task work in background in reciver device and check the number of row in database
example:
Task.Run(()=>{
//code that check number of row
});
if changed call this method :
public void SendNotification(int periority_notification, return_user_info User_info, Context context)
{
/*here intent to open layout when click on notification*/
Intent inten = new Intent(context, typeof(MainActivity));
const int pendingIntentId = 0;
PendingIntent pendingIntent =
PendingIntent.GetActivity(context, pendingIntentId, inten, PendingIntentFlags.OneShot);
var title = User_info.User_Email;
var message = User_info.User_Name.Trim() + " Reserved Request";
using (var notificationManager = NotificationManager.FromContext(context))
{
Notification notification;
if (Android.OS.Build.VERSION.SdkInt < Android.OS.BuildVersionCodes.O)
{
notification = new Notification.Builder(context)
.SetContentIntent(pendingIntent)
.SetContentTitle(title)
.SetContentText(message)
.SetAutoCancel(true)
.SetPriority(1)
.SetSmallIcon(Resource.Drawable.carparts)
.SetDefaults(NotificationDefaults.All)
.Build();
}
else
{
var myUrgentChannel = context.PackageName;
const string channelName = "SushiHangover Urgent";
NotificationChannel channel;
channel = notificationManager.GetNotificationChannel(myUrgentChannel);
if (channel == null)
{
channel = new NotificationChannel(myUrgentChannel, channelName, NotificationImportance.High);
channel.EnableVibration(true);
channel.EnableLights(true);
channel.LockscreenVisibility = NotificationVisibility.Public;
notificationManager.CreateNotificationChannel(channel);
}
channel?.Dispose();
notification = new Notification.Builder(context)
.SetContentIntent(pendingIntent)
.SetChannelId(myUrgentChannel)
.SetContentTitle(title)
.SetContentText(message)
.SetAutoCancel(true)
.SetSmallIcon(Resource.Drawable.carparts)
.Build();
}
notificationManager.Notify(periority_notification, notification);
notification.Dispose();
}
}
I tried implemented it UNCalendarNotificationTrigger and then tried to schedule next day's notification in WillPresentNotification. It worked until the application was in foreground but as soon as it went background it stopped scheduling for next day.
I tried using UNTimeIntervalNotificationTrigger but the problem is that it will display same notification daily however my requirement is to display different notification daily for unlimited period until user stops it from within the application or via iOS itself.
Is there some way that I can modify the title and body of the next notification to be displayed using UNTimeIntervalNotificationTrigger?
Thanks.
Here is the sample to repeat an alarm everyday at 09:30 by using local notification in Xamarin iOS, you could have a look:
// 1
var dateComponents = new NSDateComponents();
dateComponents.Hour = 9;
dateComponents.Minute = 30;
var trigger = UNCalendarNotificationTrigger.CreateTrigger(dateComponents, true);
// 2
var content = new UNMutableNotificationContent();
content.Title = "Daily reminder";
content.Body = "Enjoy your day!";
var requestID = "request_" + id;
var request = UNNotificationRequest.FromIdentifier(requestID, content, trigger);
// 3
UNUserNotificationCenter.Current.AddNotificationRequest(request, (err) => {
if (err != null)
{
}
});
I have been working on a location-oriented project that I need to be able to track a user's location while the app is terminated.
I have a background service in my Android project and the Geolocator Plugin.
Just for reference, here are my Geolocator settings:
App.xaml.cs
public static async void StartListening()
{
if (CrossGeolocator.Current.IsListening)
return;
CrossGeolocator.Current.DesiredAccuracy = 10;
await CrossGeolocator.Current.StartListeningAsync(TimeSpan.FromSeconds(LOCATION_PING_SECONDS), 1, true, new Plugin.Geolocator.Abstractions.ListenerSettings
{
AllowBackgroundUpdates = true,
PauseLocationUpdatesAutomatically = false
});
CrossGeolocator.Current.PositionChanged += PositionChanged;
CrossGeolocator.Current.PositionError += PositionError;
}
This + my location service for Android work like a charm while the app is running and backgrounded, but obviously everything stops when the app is terminated.
Android/MainActivity.cs
public void StartLocationService()
{
powerManager = (PowerManager) GetSystemService(PowerService);
wakeLock = powerManager.NewWakeLock(WakeLockFlags.Full, "LocationHelper");
// create a new service connection so we can get a binder to the service
locationServiceConnection = new LocationServiceConnection(null);
// this event will fire when the Service connectin in the OnServiceConnected call
locationServiceConnection.ServiceConnected += (object sender, ServiceConnectedEventArgs e) => {
Console.WriteLine("Service Connected");
};
// Starting a service like this is blocking, so we want to do it on a background thread
new Task(() => {
// Start our main service
Console.WriteLine("App", "Calling StartService");
Android.App.Application.Context.StartService(new Intent(Android.App.Application.Context, typeof(LocationService)));
// bind our service (Android goes and finds the running service by type, and puts a reference
// on the binder to that service)
// The Intent tells the OS where to find our Service (the Context) and the Type of Service
// we're looking for (LocationService)
Intent locationServiceIntent = new Intent(Android.App.Application.Context, typeof(LocationService));
Console.WriteLine("App", "Calling service binding");
// Finally, we can bind to the Service using our Intent and the ServiceConnection we
// created in a previous step.
Android.App.Application.Context.BindService(locationServiceIntent, locationServiceConnection, Bind.AutoCreate);
}).Start();
Console.WriteLine("Aquiring Wake Lock");
wakeLock.Acquire();
}
Does anyone know of any tutorials for getting location updates even when the app is terminated? Is this even possible?
Thanks!
Also, I found this Xamarin forum post... The last post says he is able to get updates while the app is terminated from a service, but I have not been able to get the same outcome.
I'm trying to create a background task that will be run when the system detects an eddystone advertisement broadcasted by an estimote beacon.
I already configured the beacon to send eddystone packets and I used UniversalBeaconLibrary to get these packets while the application is in the foreground (no problems here).
Now I want to get a notification while the application is not launched (using a background task reacting to bluetooth broadcasted packets). To my understanding, to avoid putting to much strain on the battery/cpu, I do need to filter these advertisements.
One of the simplest form of filtering (the one I tried to use) is by using the company id given by the Bluetooth SIG.
Here is what I tried :
public static async void Register()
{
if (BackgroundTaskRegistration.AllTasks.Count == 0)
{
var trigger = MakeTrigger();
// this is needed for Phone, not so for Windows in this case.
var allowed = await BackgroundExecutionManager.RequestAccessAsync();
if ((allowed != BackgroundAccessStatus.Denied) &&
(allowed != BackgroundAccessStatus.Unspecified))
{
BackgroundTaskBuilder builder = new BackgroundTaskBuilder
{
Name = "BLEWatcher",
TaskEntryPoint = typeof(BLEBackgroundConsumer.Consumer).FullName
};
builder.SetTrigger(trigger);
builder.Register();
}
}
}
private static BluetoothLEAdvertisementWatcherTrigger MakeTrigger()
{
var trigger = new BluetoothLEAdvertisementWatcherTrigger();
//Can add some filters here
//trigger.AdvertisementFilter.Advertisement.ManufacturerData.Add(new BluetoothLEManufacturerData()
//{
// CompanyId = 349 //Estimote
//});
//trigger.AdvertisementFilter.Advertisement.ManufacturerData.Add(new BluetoothLEManufacturerData()
//{
// CompanyId = 76 // Apple
//});
//trigger.AdvertisementFilter.Advertisement.ManufacturerData.Add(new BluetoothLEManufacturerData()
//{
// CompanyId = 224 // Google
//});
return (trigger);
}
As it is I get an exception, saying that there is not enough or too much filtering.
When uncommenting one of the trigger blocks, I got no exception but the task does not seem to launch.
**EDIT : ** I asked estimote what was the Company Id they were boradcasting when using eddystone packets. And according to them there is none.
In regard of this answer, what would be a suitable filter ?
A Bluetooth SIG company id is only used with a manufacturer Bluetooth LE advertisement, like iBeacon and AltBeacon. Eddystone uses service Bluetooth LE advertisements, which don't contain a company id. Instead, they contain a 16-bit Service UUID of 0xFEAA.
See here for more details: https://github.com/google/eddystone/blob/master/protocol-specification.md
I was developing application with Geofencing, when stuck at issue:
ArgumentException (Value does not fall within the expected range)
when I am trying to register background task for geofencing.
Sample from MSDN has the same problem. I will show code from sample for clarity (link to sample: http://code.msdn.microsoft.com/windowsapps/Geolocation-2483de66#content
use scenario 5,
http://msdn.microsoft.com/en-us/library/windows/apps/dn440583.aspx - instruction how to test).
All what I have done:
Build my app in Visual Studio.
Deploy the app locally first and add the app to the lock screen in Settings.
Close your app that is running locally.
Launch your app in the Visual Studio simulator.
Call RegisterBackgroundTask(..) (simply pressed button register in scenario 5)
There is code from MSDN sample that I have commented for successful app deploying in Simulator - tagged with ////// [my changes] ////////
async private void RegisterBackgroundTask(object sender, RoutedEventArgs e)
{
try
{
// Get permission for a background task from the user. If the user has already answered once,
// this does nothing and the user must manually update their preference via PC Settings.
//BackgroundAccessStatus backgroundAccessStatus = await BackgroundExecutionManager.RequestAccessAsync(); ////// [my changes] ////////
// Regardless of the answer, register the background task. If the user later adds this application
// to the lock screen, the background task will be ready to run.
// Create a new background task builder
BackgroundTaskBuilder geofenceTaskBuilder = new BackgroundTaskBuilder();
geofenceTaskBuilder.Name = SampleBackgroundTaskName;
geofenceTaskBuilder.TaskEntryPoint = SampleBackgroundTaskEntryPoint;
// Create a new location trigger
var trigger = new LocationTrigger(LocationTriggerType.Geofence);
// Associate the locationi trigger with the background task builder
geofenceTaskBuilder.SetTrigger(trigger);
// If it is important that there is user presence and/or
// internet connection when OnCompleted is called
// the following could be called before calling Register()
// SystemCondition condition = new SystemCondition(SystemConditionType.UserPresent | SystemConditionType.InternetAvailable);
// geofenceTaskBuilder.AddCondition(condition);
// Register the background task
geofenceTask = geofenceTaskBuilder.Register();
// Associate an event handler with the new background task
geofenceTask.Completed += new BackgroundTaskCompletedEventHandler(OnCompleted);
UpdateButtonStates(/*registered:*/ true);
////// [my changes] ////////
//switch (backgroundAccessStatus)
//{
// case BackgroundAccessStatus.Unspecified:
// case BackgroundAccessStatus.Denied:
// rootPage.NotifyUser("This application must be added to the lock screen before the background task will run.", NotifyType.ErrorMessage);
// break;
// default:
// // Ensure we have presented the location consent prompt (by asynchronously getting the current
// // position). This must be done here because the background task cannot display UI.
// GetGeopositionAsync();
// break;
//}
////// [my changes] ////////
}
catch (Exception ex)
{
// HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED) == 0x80070032
const int RequestNotSupportedHResult = unchecked((int)0x80070032);
if (ex.HResult == RequestNotSupportedHResult)
{
rootPage.NotifyUser("Location Simulator not supported. Could not get permission to add application to the lock screen, this application must be added to the lock screen before the background task will run.", NotifyType.StatusMessage);
}
else
{
rootPage.NotifyUser(ex.ToString(), NotifyType.ErrorMessage);
}
UpdateButtonStates(/*registered:*/ false);
}
}
Exception falls on string:
geofenceTask = geofenceTaskBuilder.Register();
Can anybody help me?
P.S. Same question thread on msdn - http://social.msdn.microsoft.com/Forums/en-US/3d69f2f9-93e0-401b-8a13-598dc671fa4f/backgroundtask-register?forum=winappswithcsharp
This is a known "bug" see Windows Store 8.1 Location background tasks do not work in simulator. I have yet to get an answer other than
Your issue has been routed to the appropriate VS development team for investigation
Please upvote it!