Windows Phone 8 notifications and background tasks - c#

I have searched the official forums and documentation and all other places, but haven't been able to find a concrete answer.
Q. In Windows Phone 8, is it possible for an application to respond to a Push Notification, and perform a task, while it is in the background?
As far as I can understand, for Toast and Tile Notifications, when the app is not in the foreground, there are no hooks at all for it to be able to respond to the incoming message.
I think "raw notifications" are the correct choice for this, since I am not required to update the app tile, or even show a Toast Notification. But, I haven't been able to find an example, or in the documentations, if I can do this.
I have found several links which talk about doing this for Windows store apps, but I want to find out if this can be done for Windows Phone 8.
I have checked this other thread,
Windows Phone 8 Background Task with notifications
Where one of the answer suggests that Whatsapp actually has a hack for this, to download the messages after a push notification is received. So, is the answer to my question, a NO?

Answer to your question is not exactly "NO",
and you are right whatsapp uses hack for this,
whatsapp someyow use AudioAgent, as they are allowed to run in background,
i dont know how exactly they do it, i am also searching for the same answer, let's see if i find something will post here

This has changed in Windows Phone 8.1. From Raw notification overview (Windows Runtime apps)
Receiving a raw notification
There are two avenues through which your app can be receive raw
notifications:
Through notification delivery events while your application is running.
Through background tasks triggered by the raw notification if your app is enabled to run background tasks.
An app can use both mechanisms to receive raw notifications. If an app
implements both the notification delivery event handler and background
tasks that are triggered by raw notifications, the notification
delivery event will take priority when the app is running.
If the app is running, the notification delivery event will take priority over the background task and the app will have the first opportunity to process the notification.
The notification delivery event handler can specify, by setting the event's PushNotificationReceivedEventArgs.Cancel property to true, that the raw notification should not be passed to its background task once the handler exits. If the Cancel property is set to false or is not set (the default value is false), the raw notification will trigger the background task after the notification delivery event handler has done its work.

Here is a complete guide on receiving push notifications in the background for Windows Phone 8.1:
Get a push notifications channel URI:
PushNotificationChannel _channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();
string ChannelUri = _channel.Uri;
Make sure you actually get the URI by logging it. Save the URI and run this on every app launch as the URI gets updated quite frequently.
Create a Windows Runtime Component project inside your solution:
Right click on solution -> Add -> New Project -> select "Windows Runtime Component (Windows Phone)". Call this project "Tasks" or whatever you prefer.
Create a new class extending an IBackgroundTask inside your newly created project. I called mine "NotificationReceiver":
using Windows.ApplicationModel.Background;
namespace Tasks {
public sealed class NotificationReceiver : IBackgroundTask {
public void Run(IBackgroundTaskInstance taskInstance) {
// TODO: implement your task here
}
}
}
Your task will be implemented here inside "Run" function.
Reference your Runtime Component in your main project:
Click on your Windows Phone project -> right click on "References" -> Add Reference -> Tick your Runtime Component and press OK.
Edit your app manifest:
Double-click on your package manifest -> Declarations -> add "Location" and "Push notification" to Supported task types, add your background task class name to Entry point: mine is called "Tasks.NotificationReceiver". Save your changes.
Unregister and register your background task every time the app is launched. I am giving the complete solution, just call "setupBackgroundTask()":
private void setupBackgroundTask() {
requestAccess();
UnregisterBackgroundTask();
RegisterBackgroundTask();
}
private void RegisterBackgroundTask() {
BackgroundTaskBuilder taskBuilder = new BackgroundTaskBuilder();
PushNotificationTrigger trigger = new PushNotificationTrigger();
taskBuilder.SetTrigger(trigger);
taskBuilder.TaskEntryPoint = "Tasks.NotificationReceiver";
taskBuilder.Name = "pushTask";
try {
BackgroundTaskRegistration task = taskBuilder.Register();
Logger.log("TASK REGISTERED");
} catch (Exception ex) {
Logger.log("FAILED TO REGISTER TASK");
UnregisterBackgroundTask();
}
}
private bool UnregisterBackgroundTask() {
foreach (var iter in BackgroundTaskRegistration.AllTasks) {
IBackgroundTaskRegistration task = iter.Value;
if (task.Name == "pushTask") {
task.Unregister(true);
Logger.log("TASK UNREGISTERED");
return true;
}
}
return false;
}
private async void requestAccess() {
BackgroundAccessStatus backgroundStatus = await BackgroundExecutionManager.RequestAccessAsync();
}
Get RawNotification object inside your task:
RawNotification notification = (RawNotification) taskInstance.TriggerDetails;

Related

Can I know if my app is allowed to pair with unpaired devices in UWP?

I am using BluetoothLEAdvertisementWatcher to watch for Bluetooth low energy beacons.
If user has disabled option "Communicate with unpaired devices" (ms-settings:privacy-customdevices), my app will never get any beacon.
Is it possible to check if this option is enabled, or ask user to enable this option?
I haven't found a way to check directly, but if the user disables this option, calling the Start method of the watcher, it will immediately be aborted with error code DisabledByUser. You can see this in action in the Bluetooth Advertisment sample in UWP samples repo.
You can subscribe to the Stopped event on the watcher and then check the BluetoothLEAdvertisementWatcherStoppedEventArgs.Error to see if the user disabled it:
private async void OnAdvertisementWatcherStopped(
BluetoothLEAdvertisementWatcher watcher,
BluetoothLEAdvertisementWatcherStoppedEventArgs eventArgs)
{
if (watcher.Status == BluetoothLEAdvertisementWatcherStatus.Aborted)
{
if (eventArgs.Error == BluetoothError.DisabledByUser)
{
// do something - show dialog to open settings, etc.
}
}
}
You can ask the user to enable the app access with a dialog message and redirect them to the Settings app by executing Launch.LaunchUriAsync("ms-settings:privacy-customdevices").

HandleNotificationOpened are not handled if app is closed before i open the notification

HandleNotificationOpened is working perfectly if App is on the background or running but it's not fired if i open the notification when app is closed.
I've tried to persist the data from event with SecureStorage, because i'm not sure if the event run but in the wrong time or it doesn't run at all.
public App()
{
OneSignal.Current.StartInit("onesignal-id").HandleNotificationOpened(HandleNotificationOpened).HandleNotificationReceived(HandleNotificationReceived).EndInit();
}
private async void HandleNotificationOpened(OSNotificationOpenedResult result)
{
var data = result.notification.payload.additionalData;
if (data != null)
{
data.TryGetValue("Title", out object Title);
data.TryGetValue("Conteudo", out object Conteudo);
data.TryGetValue("Link", out object RLink);
string lastvar = (Title.ToString().GetHashCode() + Conteudo.ToString().GetHashCode() + RLink.ToString().GetHashCode()).ToString();
if (!ChecarDB(lastvar))
{
InserirDB(Title.ToString(), Conteudo.ToString(), RLink.ToString());
}
await SecureStorage.SetAsync("UrlFromPush", RLink.ToString());
var page = new MainPage();
MessagingCenter.Send<MainPage>(page, "MudarURL");
}
}
Expected result is the application properly handle the event, No error messages at all.
This method will not be called when app is closed.
Although I did not use OneSignal to push notifications , according to the Android/iOS system notification processing mechanism, when the app is closed, when the remote notification is received, the click notification will restart the app, and the notification processing mechanism is processed by the system tray.
So the HandleNotificationOpened method will not be called.
I've solved this issue using URI Scheme to access early init background data, replacing the HandleNotificationOpened method for Intent?.Data?.EncodedQuery; with custom formatting method, that's how i got the expected result.

C# Windows Phone 8.1 runtime: how to make a task survive beyond app lifecycle?

I have this kind of Task
private async Task SaveToFile(StorageFile file)
{
// prepare data
await ...
Debug.Writeline("completed");
}
If the user press "back" button this task won't be completed. I need a way to make it go on until all it's done, even if the calling app is not running any more.
You have To use "background Task" for this. Its pretty simple,
create a new project for background tasks and add it to your solution, because your background task is a not a simple class its a separate WINRT project. To do this, right-click on your solution node in the Solution Explorer and select Add->New Project. Then select the Windows Run-time Component (Universal Windows) project type, name the project, and click OK. I named here "BackgroundStuff". You can create more than one background task for single application. there is no any limit.
Consider simple example to generate toast even App is not running:
private async void button_Click(object sender, RoutedEventArgs e)
{
string myTaskName = "MyBackgroundClass";
// check if task is already registered
foreach (var cur in BackgroundTaskRegistration.AllTasks)
if (cur.Value.Name == myTaskName)
{
await (new MessageDialog("Task already registered")).ShowAsync();
return;
}
// Windows Phone app must call this to use trigger types (see MSDN)
await BackgroundExecutionManager.RequestAccessAsync();
// register a new task
BackgroundTaskBuilder taskBuilder = new BackgroundTaskBuilder { Name = "MyBackgroundClass", TaskEntryPoint ="MybackgroundStuff.MyBackgroundClass" };
taskBuilder.SetTrigger(new TimeTrigger(15, true));
BackgroundTaskRegistration myFirstTask = taskBuilder.Register();
If you want to learn more , refer my blog:
http://windowsapplife.blogspot.in/
No, you can not force a Task to keep running, if the parent process is terminated.
That said, the issue you've described is not really an issue unless your file takes longer than 10 seconds to save (which is an eternity, in computer lingo).
Windows Phone apps continue to run in the background for up to 10 seconds, after the user 'backs' out of it, or manually quits. This should be enough time for any application to finish its 'cleanup' operations.
See: App Lifecycle Windows Runtime Apps
See also: App activation and deactivation for Windows Phone 8

How to suppress push toast notification only when App in foreground?

Note: I have only tested this using the emulator, and pushing toasts using the built in functionality. I am assuming this isn't an emulator issue.
I followed this guide in order to intercept push toast notifications while the app is running. However, I only want to suppress the toast notification when the app is in the foreground. It should still display when another app is in the foreground. So I wrote the following handler in App.xaml.cs (and subscribed to the PushNotificationReceived event):
private async void OnPushNotification(PushNotificationChannel sender, PushNotificationReceivedEventArgs e)
{
string msg = "";
if (e.NotificationType == PushNotificationType.Toast)
{
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
if (Window.Current.Visible)
{
msg += " Toast canceled.";
e.ToastNotification.SuppressPopup = true;
}
});
if (true) // actually determines if it's a certain type of toast
{
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
ConfirmationContentDialog confirmationDialog = new ConfirmationContentDialog();
confirmationDialog.SetMessage("Please confirm that you like turtles." + msg);
await confirmationDialog.ShowAsync();
});
}
}
}
So this works, in the sense that I only see the "toast canceled" message when the app was in the foreground when receiving the push notification. When I'm on the start screen or somewhere else I always get the toast. This is good. However, when the app is in the foreground, sometimes (usually after sending the second push) the toast shows up anyway (even though "Toast canceled" displays). But sometimes it doesn't. It's rather inconsistent.
This is leading me to believe that due to the await, sometimes the toast gets through before the code gets run on the UI thread to check whether the app is visible or not. However, I can't access Window.Current.Visible from here without using the dispatcher. I even tried CoreApplication.MainView.CoreWindow.Visible but that gives me "interface marshalled for different thread etc" exception. Speaking of which, I don't understand how CoreApplication.MainView.CoreWindow.Dispatcher can be called from anywhere but CoreApplication.MainView.CoreWindow.Visible not? How does that even work.
Anyway, how do I fix this? I would like to keep this within App.xaml.cs because I have a number of pages in this app, but this content dialog needs to be shown no matter which page the user is on, and without the user being redirected to a different page. However, I am of course open for new suggestions.
I fixed this as per Kai Brummund's suggestion by using a simple boolean toggle in the App class, and subscribing to the VisibilityChanged event like so:
private bool APP_VISIBLE = true;
protected override async void OnLaunched(LaunchActivatedEventArgs e)
{
// Stuff put here by Visual Studio
Window.Current.VisibilityChanged += OnVisibilityChanged;
Window.Current.Activate();
}
private void OnVisibilityChanged(object sender, VisibilityChangedEventArgs e)
{
if (e.Visible)
APP_VISIBLE = true;
else
APP_VISIBLE = false;
}
That way I can use APP_VISIBLE to suppress the popup without having to use the dispatcher and the toast is suppressed immediately.

Register Background Task in Silverlight 8.1 app

I'm working on an app that uses BLE to communicate with an item and I need to receive background notifications from it. I am aware of the existence of GattCharacteristicNotificationTrigger but I can't find any way to register a Background Task in a Silverlight 8.1 app.
Any tip?
Registering a BackgroundTask is quite well explained here at MSDN.
Here is simple example fired upon TimeTrigger and showing a Toast, the steps are (applies to both - RunTime and Silverlight apps):
1. BackgroungTask must be a Windows Runtime Componenet (no matter if your App is Runtime or Silverlight). To add a new one, right click on your Solution in Solution Explorer window in VS, select Add then New project and choose Windows Runtime Component.
2. Add a reference in your main project.
3. Specify Declarations in Package.appxmanifest file - you need to add a Backgorund Task, mark Timer and specify Entry Point for the Task. The Entry Point will be a Namespace.yourTaskClass (which implements IBackgroundTask) - the added Windows Runtime Component.
4. How can your BackgroundTask look like? - let's say we want to send a Toast from it (of course it can be many other things):
namespace myTask // the Namespace of my task
{
public sealed class FirstTask : IBackgroundTask // sealed - important
{
public void Run(IBackgroundTaskInstance taskInstance)
{
// simple example with a Toast, to enable this go to manifest file
// and mark App as TastCapable - it won't work without this
// The Task will start but there will be no Toast.
ToastTemplateType toastTemplate = ToastTemplateType.ToastText02;
XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(toastTemplate);
XmlNodeList textElements = toastXml.GetElementsByTagName("text");
textElements[0].AppendChild(toastXml.CreateTextNode("My first Task"));
textElements[1].AppendChild(toastXml.CreateTextNode("I'm message from your background task!"));
ToastNotificationManager.CreateToastNotifier().Show(new ToastNotification(toastXml));
}
}
}
5. Finally, let's register our BackgroundTask in main project:
private async void Button_Click(object sender, RoutedEventArgs e)
{
// Windows Phone app must call this to use trigger types (see MSDN)
await BackgroundExecutionManager.RequestAccessAsync();
BackgroundTaskBuilder taskBuilder = new BackgroundTaskBuilder { Name = "First Task", TaskEntryPoint = "myTask.FirstTask" };
taskBuilder.SetTrigger(new TimeTrigger(15, true));
BackgroundTaskRegistration myFirstTask = taskBuilder.Register();
}
Compile, run and it should work. As you can see the task should start after 15 minutes (this time can vary as OS schedules task in specific intervals, so it will fire between 15-30 minutes). But how to debug a task faster?
There is a simple way - go to Debug location toolbar and you will see a dropdown Lifecycle events, choose your task from it and it will fire (sometimes open/close dropdown to refresh it).
Here you can download my sample code - WP8.1 Silverlight App.

Categories

Resources