Azure notification hub UWP, UWP toast notifications don't launch app - azure

i'm using a notification hub for an UWP application following this tutorial : Getting started with Notification Hubs for Windows Universal Platform Apps.
If i test send with a Windows 8 notification like :
<?xml version="1.0" encoding="utf-8"?>
<toast>
<visual><binding template="ToastText01">
<text id="1">Test message</text>
</binding>
</visual>
</toast>
It works and if i click on the notification, it open the app through the OnLaunched() method. But if i send a UWP specific notification like :
<toast launch="app-defined-string">
<visual>
<binding template="ToastGeneric">
<text>Microsoft Company Store</text>
<text>New Halo game is back in stock!</text>
</binding>
</visual>
<actions>
<action activationType="foreground" content="See more details" arguments="details"/>
<action activationType="background" content="Remind me later" arguments="later"/>
</actions>
</toast>
The toast works but if I click on it, it open the app and OnLaunched() never called so the app stuck on spashscreen.
Thanks in advance for your help,
Regards

you need to implement OnActivated in your app.xaml.cs
protected override void OnActivated(IActivatedEventArgs args)
{
base.OnActivated(args);
}
see https://blogs.msdn.microsoft.com/tiles_and_toasts/2015/07/08/quickstart-sending-a-local-toast-notification-and-handling-activations-from-it-windows-10/

For those who have the same problem, with Dave Smits answer : juste add OnZctivated method in App.xaml.cs file and place same content as OnLaunched method :
protected override async void OnLaunched(LaunchActivatedEventArgs e)
{
await OnLaunchedOrActivated(e);
}
protected override async void OnActivated(IActivatedEventArgs e)
{
await OnLaunchedOrActivated(e);
}
private async Task OnLaunchedOrActivated(IActivatedEventArgs e)
{
// Initialize things like registering background task before the app is loaded
Frame rootFrame = Window.Current.Content as Frame;
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null)
{
// Create a Frame to act as the navigation context and navigate to the first page
rootFrame = new Frame();
rootFrame.NavigationFailed += OnNavigationFailed;
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
// TODO: Load state from previously suspended application
}
// Place the frame in the current Window
Window.Current.Content = rootFrame;
}
// Handle toast activation
if (e is ToastNotificationActivatedEventArgs)
{
var toastActivationArgs = e as ToastNotificationActivatedEventArgs;
// If empty args, no specific action (just launch the app)
if (toastActivationArgs.Argument.Length == 0)
{
if (rootFrame.Content == null)
rootFrame.Navigate(typeof(MainPage));
}
// Otherwise an action is provided
else
{
// Parse the query string
// See what action is being requested
// If we're loading the app for the first time, place the main page on the back stack
// so that user can go back after they've been navigated to the specific page
if (rootFrame.BackStack.Count == 0)
rootFrame.BackStack.Add(new PageStackEntry(typeof(MainPage), null, null));
}
}
// Handle launch activation
else if (e is LaunchActivatedEventArgs)
{
var launchActivationArgs = e as LaunchActivatedEventArgs;
// If launched with arguments (not a normal primary tile/applist launch)
if (launchActivationArgs.Arguments.Length > 0)
{
// TODO: Handle arguments for cases like launching from secondary Tile, so we navigate to the correct page
throw new NotImplementedException();
}
// Otherwise if launched normally
else
{
// If we're currently not on a page, navigate to the main page
if (rootFrame.Content == null)
rootFrame.Navigate(typeof(MainPage));
}
}
else
{
// TODO: Handle other types of activation
throw new NotImplementedException();
}
// Ensure the current window is active
Window.Current.Activate();
}

Related

Xamarin IOS - Show local notification when application is closed

I have a Xamarin IOS application that get's the users location each 10 sec, even when the app is killed. I make us of this library: "https://jamesmontemagno.github.io/GeolocatorPlugin/".
What I want is: When the app is closed or open and the user is at a specific location, I want to show a local notification. Is that even possible when the app is closed? I can't find information on this because it's always about remote notifications.
Notification permission should be requested as soon as the app launches by adding the following code to the FinishedLaunching method of the AppDelegate and setting the desired notification type (UNAuthorizationOptions):
...
using UserNotifications;
...
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
....
//after iOS 10
if(UIDevice.CurrentDevice.CheckSystemVersion(10,0))
{
UNUserNotificationCenter center = UNUserNotificationCenter.Current;
center.RequestAuthorization(UNAuthorizationOptions.Alert | UNAuthorizationOptions.Sound | UNAuthorizationOptions.UNAuthorizationOptions.Badge, (bool arg1, NSError arg2) =>
{
});
center.Delegate = new NotificationDelegate();
}
else if(UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
{
var settings = UIUserNotificationSettings.GetSettingsForTypes(UIUserNotificationType.Alert| UIUserNotificationType.Badge| UIUserNotificationType.Sound,new NSSet());
UIApplication.SharedApplication.RegisterUserNotificationSettings(settings);
}
return true;
}
New to iOS 10, an app can handle Notifications differently when it is in the foreground and a Notification is triggered. By providing a UNUserNotificationCenterDelegate and implementing the UserNotificationCentermethod, the app can take over responsibility for displaying the Notification. For example:
using System;
using ObjCRuntime;
using UserNotifications;
namespace workplat
{
public class NotificationDelegate:UNUserNotificationCenterDelegate
{
public NotificationDelegate()
{
}
public override void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
{
// Do something with the notification
Console.WriteLine("Active Notification: {0}", notification);
// Tell system to display the notification anyway or use
// `None` to say we have handled the display locally.
completionHandler(UNNotificationPresentationOptions.Alert|UNNotificationPresentationOptions.Sound);
}
public override void DidReceiveNotificationResponse(UNUserNotificationCenter center, UNNotificationResponse response, Action completionHandler)
{
// Take action based on Action ID
switch (response.ActionIdentifier)
{
case "reply":
// Do something
break;
default:
// Take action based on identifier
if (response.IsDefaultAction)
{
// Handle default action...
}
else if (response.IsDismissAction)
{
// Handle dismiss action
}
break;
}
// Inform caller it has been handled
completionHandler();
}
}
}
To create and register a Custom Action with the system, use the following code:
public void RegisterNotification(long time)
{
UNUserNotificationCenter center = UNUserNotificationCenter.Current;
//creat a UNMutableNotificationContent which contains your notification content
UNMutableNotificationContent notificationContent = new UNMutableNotificationContent();
notificationContent.Title = "xxx";
notificationContent.Body= "xxxx";
notificationContent.Sound = UNNotificationSound.Default;
UNTimeIntervalNotificationTrigger trigger = UNTimeIntervalNotificationTrigger.CreateTrigger(time, false);
UNNotificationRequest request = UNNotificationRequest.FromIdentifier("FiveSecond", notificationContent, trigger);
center.AddNotificationRequest(request,(NSError obj) =>
{
});
}
When you call this method ,for emample:
RegisterNotification(20);//set the time you want to push notification
The notification will been pushed after 20 seconds,enen if you close your app. You could put this line after uploading the location .
I have upload my demo to my github, you can download it for your reference: Demo Link .
And you can access the link for more information and details: MicroSoft Document

Local notification not presenting when app is in background in Xamarin iOS

I have implemented chat functionality in my Xamarin.IOS app, as remote notifications are not possible to send from the server-side, I am using local notification to alert the user of new incoming messages. Everything works fine in the simulator, I can see notifications are displayed in the foreground as well as in background mode.
But when I run the app on the device, notification is only working in foreground mode. When the app is in the background, notifications won't show.
After investigating this issue I found that they work fine when the app is running in debug mode(i.e. launched from VisualStudio and cable still attached). But as soon as I disconnect the cable, they won't show anymore.
I have found a few posts https://stackoverflow.com/a/35029847 which suggested that this line would fix the issue, but it won't work since handler cant be null anymore.
application.BeginBackgroundTask("showNotification", expirationHandler: null);
So I implemented the below code in my app delegate but it still not working
nint taskID = 111;
taskID = application.BeginBackgroundTask("showNotification", expirationHandler: ()=> {
UIApplication.SharedApplication.EndBackgroundTask(taskID);
});
I also tried Background fetch and added below the line in AppDelegate, but it didn't work. application.SetMinimumBackgroundFetchInterval(UIApplication.BackgroundFetchIntervalMinimum);
Schedule Local Notification code
var content = new UNMutableNotificationContent();
content.Body = body;
content.Sound = UNNotificationSound.Default;
content.UserInfo = dict;
content.Badge = IOSAppConstant.LocalNotificationCount + 1;
var request = UNNotificationRequest.FromIdentifier(chatID, content, null);
// schedule it
UNUserNotificationCenter.Current.AddNotificationRequest(request, (error) =>
{
if (error != null)
{
Console.WriteLine($"Error: {error.LocalizedDescription ?? ""}");
}
else
{
Console.WriteLine("Scheduled...");
}
});
//Register notification
UNUserNotificationCenter.Current.RequestAuthorization
(UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound,
(granted, error) =>
{
if (granted)
InvokeOnMainThread(UIApplication.SharedApplication.RegisterForRemoteNotifications);
});
//Assign Delegate
this._userNotificationCenterDelegate = new UserNotificationCenterDelegate();
UNUserNotificationCenter.Current.Delegate = this._userNotificationCenterDelegate;
//Notification Delegate
public class UserNotificationCenterDelegate : UNUserNotificationCenterDelegate
{
public override void WillPresentNotification(UNUserNotificationCenter center,
UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
{
completionHandler(UNNotificationPresentationOptions.Alert);
}
public override void DidReceiveNotificationResponse(UNUserNotificationCenter center,
UNNotificationResponse response, Action completionHandler)
{
completionHandler();
}
}
I have also tried calling schedule Notification function from BeginBackgroundTask on my chat controller but it is not working
The issue is similar to Local Push notification not working in Xamarin iOS but there is no solution available.
You mentioned that you couldn't use the answer in this question https://stackoverflow.com/a/3502984 because you can't provide null for expirationHandler for BeginBackgroundTask.
To get past this you can provide an arbitrary action. The result is that local notifications should work when the released app is in the background
public void NotifAction()
{
// This exists because expirationHandler can't be null
}
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());
UIApplication.SharedApplication.SetMinimumBackgroundFetchInterval(UIApplication.BackgroundFetchIntervalMinimum);
Action testActon = NotifAction;
UIApplication.SharedApplication.BeginBackgroundTask("showNotification", testActon);
return base.FinishedLaunching(app, options);
}

Launch a new page on Clicking a push notification?

I am trying to launch an explicit page whenever user clicks on an push notification to demonstrate a concept.
This code used to work earlier(last year) but i dont remember what i changed in the interim that it stopped working.
Here is the code for app.xaml .
private async void AcquirePushChannel()
{
try
{
CurrentChannel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();
}
catch (Exception)
{
new MessageDialog("Cannot Contact Azure Server", "Operation Timed Out");
}
IMobileServiceTable<Registrations> registrationsTable = App.MobileService.GetTable<Registrations>();
var registration = new Registrations { Handle = CurrentChannel.Uri };
await registrationsTable.InsertAsync(registration);
}
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
}
/// <summary>
/// Invoked when the application is launched normally by the end user. Other entry points
/// will be used when the application is launched to open a specific file, to display
/// search results, and so forth.
/// </summary>
/// <param name="args">Details about the launch request and process.</param>
protected async override void OnLaunched(LaunchActivatedEventArgs args)
{
Frame rootFrame = Window.Current.Content as Frame;
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null)
{
// Create a Frame to act as the navigation context and navigate to the first page
rootFrame = new Frame();
if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: Load state from previously suspended application
}
// Place the frame in the current Window
Window.Current.Content = rootFrame;
}
if (rootFrame.Content == null)
{
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
if (!rootFrame.Navigate(typeof(MainPage), args.Arguments))
{
throw new Exception("Failed to create initial page");
}
}
string launchstring = args.Arguments;
if (!string.IsNullOrEmpty(launchstring))
{
rootFrame.Navigate(typeof(InstructionSetBlue));
}
AcquirePushChannel();
// Ensure the current window is active
Window.Current.Activate();
}
This piece of code launches the specific page.
if (!string.IsNullOrEmpty(launchstring))
{
rootFrame.Navigate(typeof(InstructionSetBlue));
}

Issue with Game Center on Monotouch

I'm trying to implement Game Center into my game but i have problems with it.
Here is my Main.cs code :
namespace iosgame
{
public class Application
{
[Register ("AppDelegate")]
public partial class AppDelegate : IOSApplication {
MainViewController mainViewController;
public AppDelegate(): base(new Game(new StaticsDatabase(),new StoreDatabase(),new InappPurchase(),new Social(),new MissionsDatabase()), getConfig()) {
}
internal static IOSApplicationConfiguration getConfig() {
IOSApplicationConfiguration config = new IOSApplicationConfiguration();
config.orientationLandscape = true;
config.orientationPortrait = false;
config.useAccelerometer = false;
config.useMonotouchOpenTK = true;
config.useObjectAL = true;
return config;
}
//
// 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)
{
base.FinishedLaunching(app,options);
UIViewController controller = ((IOSApplication)Gdx.app).getUIViewController();
mainViewController = new MainViewController();
controller.View.Add(mainViewController.View);
return true;
}
private bool isGameCenterAPIAvailable()
{
return UIDevice.CurrentDevice.CheckSystemVersion (4, 1);
}
}
static void Main (string[] args)
{
UIApplication.Main (args, null, "AppDelegate");
}
}
}
And here is the superclass of that Main.cs : https://github.com/libgdx/libgdx/blob/master/backends/gdx-backend-iosmonotouch/src/com/badlogic/gdx/backends/ios/IOSApplication.java
I'm trying to use this https://github.com/xamarin/monotouch-samples/blob/master/GameCenterSample/GameCenterSample/MainViewController.cs example but i can't see any authenticate window in my game.I can see "Welcome back ,name" notification but after i log out from gamecenter app and reopen my game but i can't see any authentication window.
How can i fix it?
Thanks in advance
Just call this in FinishedLaunching:
if (!GKLocalPlayer.LocalPlayer.Authenticated) {
GKLocalPlayer.LocalPlayer.Authenticate (error => {
if (error != null)
Console.WriteLine("Error: " + error.LocalizedDescription);
});
}
This should display a Game Center "toast" saying "Welcome back, Player 1".
Here are some ideas if this doesn't work:
Make sure you have setup a new bundle id in the developer portal, and declare it in your Info.plist
Start filling out your app details in iTunes connect (Minimum is description, keywords, icon, 1 screenshot), and make sure to enable Game Center and add your new game to a group
Login with a test iTunes user in Game Center (create in ITC), or the login associated with your developer account
PS - I wouldn't worry about checking for iOS 4.1, just target iOS 5.0 and higher these days.

How can I display a dialog on Currently visible activity on BroadcastReceiver?

I have a main Activity (OceanintelligenceActivity). In this activity I register the device for push notifications and also I registered a receiver that shows a Dialog and starts the proper Activity depending on the info sent from my server. This is the code I'm using to register the device and the receiver :
protected void gcmRegistration(){
PMApplication thisApp = PMApplication.getInstance();
AppDelegate delegate = thisApp.getAppDelegate();
final Context context = this;
// Make sure the device has the proper dependencies.
GCMRegistrar.checkDevice(this);
// Make sure the manifest was properly set - comment out this line
// while developing the app, then uncomment it when it's ready.
GCMRegistrar.checkManifest(this);
// Let's declare our receiver
registerReceiver(mHandleMessageReceiver,new IntentFilter(DISPLAY_MESSAGE_ACTION));
final String regId = GCMRegistrar.getRegistrationId(this);
if (regId.equals("")) {
Log.d("", "Lets register for Push");
GCMRegistrar.register(this, SENDER_ID);
}else {
if(GCMRegistrar.isRegisteredOnServer(this)) {
// Skips registration.
String apnsToken = delegate.sso.getAPNSToken();
if(!apnsToken.equals(regId)){
Log.d("", "The Device RegId has changed on GCM Servers");
// We should let our servers know about this
ServerUtilities.update(regId, context);
}
} else {
Log.d("","Is not register on PM Server");
// Try to register again, but not in the UI thread.
// It's also necessary to cancel the thread onDestroy(),
// hence the use of AsyncTask instead of a raw thread.
mRegisterTask = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
boolean registered = ServerUtilities.register(context, regId);
// At this point all attempts to register with the app
// server failed, so we need to unregister the device
// from GCM - the app will try to register again when
// it is restarted. Note that GCM will send an
// unregistered callback upon completion, but
// GCMIntentService.onUnregistered() will ignore it.
if (!registered) {
GCMRegistrar.unregister(context);
}
return null;
}
#Override
protected void onPostExecute(Void result) {
mRegisterTask = null;
}
};
mRegisterTask.execute(null, null, null);
}
}
}
This is how I set the receiver:
private final BroadcastReceiver mHandleMessageReceiver =
new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String newMessage = intent.getExtras().getString(EXTRA_MESSAGE);
Log.d("","BroadcastReceiver onReceive");
notificationIntent = GCMIntentService.getNotificationIntent(context);
new AlertDialog.Builder(context)
.setMessage(newMessage+". Would you like to see it right now?")
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// Show update
startActivity(notificationIntent);
}
})
.setNegativeButton("No", null).show();
}
};
GCMIntentService.getNotificationIntent(context). This line returns the the Intent with the Activity I want to start.
Whenever there is a notification onReceive gets called but the Dialog only shows if I am on the main activity. So if the app is on a different activity, onReceive still gets called but the dialog doesn't show and therefore I can't start the proper activity.
How can I display a dialog on Currently visible activity on BroadcastReceiver?
Playing around with this one and searching on google I came across a solution. It is not the best one but it works. I still can't believe there is not an easy way to get the current context in Android. So this is what I did to manage to show the Dialog regardless of what the current activity is : I have a public static property of type Context on my singleton class(AppDelegate) and on each activity I override the onResume method and set the Context to the current activity like this AppDelegate.CURRENT_CONTEXT = this. Then on my dialog : AlertDialog.Builder(AppDelegate.CURRENT_CONTEXT).....

Resources