Windows Azure Mobile Services has great built-in support for
making Push Notifications; however there’s a better more scalable option using
the Notifications Hub which is part of the Service Bus group of services.
We can call the hub from external backend services using the
Windows Azure Service Bus SDK (NuGet PM> Install-Package
WindowsAzure.ServiceBus) and this is fairly well documented; however if you
want to do a direct replacement for the build-in Push Notifications using
Notifications Hub, it’s not so well documented. I did some digging in the
source to work out how to use it: https://github.com/WindowsAzure/azure-sdk-for-node
In our Mobile Services scripts we can make use of NPM
packages which we install ourselves and pre-installed packages like the Windows
Azure SDK for Node which we will use for calling the Hub.
Accessing the Notifications Hub
We need two things to allow us to connect to the hub and
those are the DefaultFullSharedAccessSignature which you can get from the
Notifications Hub Dashboard and the Hub name. We can declare these as variables
like this:
var
CONNECTION_STRING =
"Endpoint=sb://myapp.servicebus.windows.net/;SharedAccessKeyName=DefaultFullSharedAccessSignature;SharedAccessKey=XXXXXXXXXXXXXXXXXXXXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=";
var
HUB_NAME = "MyHubName";
Now to interact with the Notifications hub, we get a
reference to the Azure package like this:
var
azure = require("azure");
Then create a NotificationHubService like this:
var
notificationHubService = azure.createNotificationHubService(HUB_NAME,
CONNECTION_STRING);
All the native PNS send methods have prototypes similar to
this:
MpnsService.prototype.send
= function (tags, payload, targetName, notificationClass, optionsOrCallback,
callback)
The Notifications class is the batching interval (how quick
it’s sent).
Windows Phone MPNS Notofications
Following are examples of sending toast and tiles to Windows
Phone apps using the MPNS provider:
function
sendToastHubMpns(text1, text2, tagExpression)
{
var azure = require("azure");
var notificationHubService =
azure.createNotificationHubService(HUB_NAME, CONNECTION_STRING);
var toast = "<?xml
version=\"1.0\" encoding=\"utf-8\"?>" +
"<wp:Notification
xmlns:wp=\"WPNotification\">" +
"<wp:Toast>" +
"<wp:Text1>" +
text1 + "</wp:Text1>" +
"<wp:Text2>" +
text2 + "</wp:Text2>" +
"</wp:Toast> " +
"</wp:Notification>";
notificationHubService.mpns.send(tagExpression, toast,
"toast", 2, function(error) {
if (error) {
console.error(error);
}});
}
function
sendTileHubMpns(backTitle, backContent, tagExpression)
{
var azure = require("azure");
var notificationHubService =
azure.createNotificationHubService(HUB_NAME, CONNECTION_STRING);
var tile = "<?xml
version=\"1.0\" encoding=\"utf-8\"?>" +
"<wp:Notification
xmlns:wp=\"WPNotification\" Version=\"2.0\">" +
"<wp:Tile Template=\"FlipTile\">"
+
"<wp:BackTitle>"
+ backTitle + "</wp:BackTitle>" +
"<wp:BackContent>" + backContent +
"</wp:BackContent>" +
"<wp:WideBackContent>" + backContent +
"</wp:WideBackContent>" +
"</wp:Tile> " +
"</wp:Notification>";
notificationHubService.mpns.send(tagExpression, tile, "token",
1, function(error) {
if (error) {
console.error(error);
}});
}
Windows 8 WNS Notifications
Following are examples of sending toast, tile and badge
notifications to Windows 8 apps using the WNS provider:
function
sendToastHubWns(text1, text2, text3, tagExpression)
{
var azure = require("azure");
var notificationHubService =
azure.createNotificationHubService(HUB_NAME, CONNECTION_STRING);
var toast = "<toast>" +
"<visual>" +
"<binding
template=\"ToastText04\">" +
"<text
id=\"1\">" + text1 + "</text>" +
"<text
id=\"2\">" + text2 + "</text>" +
"<text
id=\"3\">" + text3 + "</text>" +
"</binding>" +
"</visual>" +
"</toast>";
notificationHubService.wns.send(tagExpression, toast,
"wns/toast", 2, function(error) {
if (error) {
console.error(error);
}});
}
function
sendTileHubWns(text1, text2, text3, tagExpression)
{
var azure = require("azure");
var notificationHubService =
azure.createNotificationHubService(HUB_NAME, CONNECTION_STRING);
var tile = "<tile>" +
"<visual>" +
"<binding
template=\"TileSquareText01\">" +
"<text
id=\"1\">" + text1 + "</text>" +
"<text
id=\"2\">" + text2 + "</text>" +
"<text
id=\"3\">" + text3 + "</text>" +
"</binding>" +
"</visual>" +
"</tile>";
notificationHubService.wns.send(tagExpression, tile,
"wns/tile", 2, function(error) {
if (error) {
console.error(error);
}});
}
function
sendBadgeHubWns(value, tagExpression)
{
var azure = require("azure");
var notificationHubService =
azure.createNotificationHubService(HUB_NAME, CONNECTION_STRING);
var badge = "<badge value=\""
+ value + "\" />";
notificationHubService.wns.send(tagExpression, badge,
"wns/badge", 2, function(error) {
if (error) {
console.error(error);
}});
}
These functions can be called like this:
function
sendAllHubNotifications(message)
{
sendToastHubMpns("My Application", message,
null);
sendTileHubMpns("My Application ", message,
null);
sendToastHubWns("My Application ",
"Here’s a notification", message, null);
sendTileHubWns("My Application ",
" Here’s a notification ", message, null;
sendBadgeHubWns("alert", null);
}
Notice there is a tagExpression variable which we have set
to null. We can use this to target notifications at user’s interests which are
registered in the app:
function
sendAllHubNotifications(message)
{
sendToastHubWns("My Application ",
"Here’s a notification", message, "NEWS");
sendTileHubWns("My Application ",
" Here’s a notification ", message, "NEWS");
sendBadgeHubWns("alert", "NEWS");
}
I managed to get Windows 8 to work with this but not Windows
Phone 8
Registering with the Hub from a Windows 8 App
This example shows how to register a Windows 8 Store App
with the DefaultListenSharedAccessSignature connection string this time (from
the Notifocations Hub Dashboard). This registers two tags, but you can use null
to receive everything:
using
System;
using
System.Collections.Generic;
using
System.Linq;
using System.Text;
using
System.Threading.Tasks;
using
Microsoft.WindowsAzure.MobileServices;
using
Newtonsoft.Json.Linq;
using
Microsoft.WindowsAzure.Messaging;
namespace
MyApp
{
internal class MyAppPush
{
private const string HUB_NAME = "myapp";
private const string CONNECTION_STRING
= "Endpoint=sb://myapp.servicebus.windows.net/;SharedAccessKeyName=DefaultListenSharedAccessSignature;SharedAccessKey=/XXXXXXXXXXXXXXXXXXXXXXXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=";
public async static void
UploadChannel()
{
var channel = await
Windows.Networking.PushNotifications.PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();
var token =
Windows.System.Profile.HardwareIdentification.GetPackageSpecificToken(null);
string installationId =
Windows.Security.Cryptography.CryptographicBuffer.EncodeToBase64String(token.Id);
try
{
// Register with hub
var hub = new
NotificationHub(HUB_NAME, CONNECTION_STRING);
var result = await
hub.RegisterNativeAsync(channel.Uri, new string[] { "NEWS", "SUPPORT"
});
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
}
}
}
Windows Phone 8 apps are registered in the same way, but
they have a slightly different mechanism as they have an event when the URI
changes which needs to be used for registration.
Hi! Thank you for article.
ReplyDeleteToasts notifications works correctly. If you use null instead 'toast' or 'token' your device will get notification as raw.
But the tile notofication doesn't work :/ In Azure Log there's no errors.
Maybe the sdk has changed, have a look at the functions here https://github.com/WindowsAzure/azure-sdk-for-node
DeleteI havent seen any changes. Have you some working client code for Windows Phone?
DeleteThis used to work, with tags null (couldn't get tags to work on mpns):
Delete// Register with hub
// var tags = TagHelper.Default.GetTags();
var hub = new NotificationHub(this.HUB_NAME, this.CONNECTION_STRING);
var result = await hub.RegisterNativeAsync(this._pushChannel.ChannelUri.AbsoluteUri, null);
Tagging seems to work OK with a .Net backend now so it should work with Node.js backend too as the hub is unrelated from the client-side, however there may be a difference between how the JS lib interacts with the hub
Deletetry "tile" instead of "token" they've probably updated that bit, I remember it taking ages to figure out it was token in the first place
DeleteI've tried multimple times and result is the same : The HTTP header 'X-WindowsPhone-Target'.
DeleteOnly with 'token' there is no errors. Toast works corectly, raw too. (Javascript backend)
Looks like the prototype has changed: NotificationHubService.prototype.send = function (tags, payload, optionsOrCallback, callback) {
ReplyDeleteTry this:
notificationHubService.mpns.send(tagExpression, tile, function(error) {
if (error) {
console.error(error);
}});
Where has changed? MpnsService.prototype.send = function (tags, payload, targetName, notificationClass, optionsOrCallback, callback) {
Deletein https://github.com/WindowsAzure/azure-sdk-for-node/blob/master/lib/services/serviceBus/mpnsservice.js
This comment has been removed by the author.
DeleteHave you tried a v2 template?
Deletehttp://blogs.msdn.com/b/thunbrynt/archive/2014/04/10/windows-phone-8-1-for-developers-live-tiles.aspx
Yes, it the same. Thanks for ur help. I'll let you know when it will work. :)
DeleteOops sorry I was looking at the wrong one. I'm reading the comments in the code and it looks like there are comments for future functions which aren't implemented like this:
ReplyDelete/**
* @name MpnsService#sendFlipTile
* @function
*
* @description
* Sends a FlipTile notification (Only Windows Phone version 7.8 or later). For more information see http://msdn.microsoft.com/en-us/library/windowsazure/jj206971.aspx.
*
* @param {string} tags A single tag or tag expression.
* @param {object} payload The message's payload.
* @param {string} payload.backgroundImage The URI of the background image for the tile.
* @param {string} payload.count The number that appears on the tile.
* @param {string} payload.title The title text of the tile.
* @param {string} payload.backBackgroundImage The URI of the image that is shown on the backside of the tile.
* @param {string} payload.backTitle Title for the backside side of the tile.
* @param {string} payload.backContent Text for the backside of the tile.
* @param {string} payload.id ID of a related, secondary tile.
* @param {string} payload.smallBackgroundImage The URI for the background image for the tile when it is reduced to its small size.
* @param {string} payload.wideBackgroundImage The URI for the background image for the tile when it is expanded to its wide size.
* @param {string} payload.wideBackContent Content for the back tile when the tile is expanded to its wide size.
* @param {string} payload.wideBackBackgroundImage The URI for the image to be on the backside of the tile when the tile is expanded to its wide size.
* @param {object} [options] The request options.
* @param {object} [options.headers] The mpns headers.
* @param {Function(error, response)} callback The callback function.
* @return {undefined}
*/
Could be worth asking someone on the Mobile Services team if they can shed any light on the issue. The mpns tile payload definitely used to work, but tags did not at the time