Windows Phone推送通知类型
indows Phone推送通知类型
Tile通知

Toast通知
重要说明: |
您必须要求用户授权方可接收Toast通知,且在应用程序中必须具有允许用户禁用的Toast通知的功能。 |
Raw通知
推送通知类型选择
请考虑发送通知的频率以及您希望引起用户注意的事件类型。
推式通知类型 | 应用示例 |
Tile通知 | 如天气应用温度变化的信息性通知。 |
Toast通知 | 立即查看,如突发新闻的重要通知。 |
Raw通知 | 以自定义的格式将信息直接发送到您的应用程序。 |
推送通知的工作流

- Window Phone客户端应用程序请求与微软推送通知服务(Microsoft Push Notification Services)建立通道连接,微软推送通知服务(Microsoft Push Notification Services)使用通道URI响应。
- Window Phone客户端应用程序向监视服务(Web Service或者Cloud Application)发送包含推送通知服务通道URI以及负载的消息。
- 当监视服务检测到信息更改时(如航班取消、航班延期或天气警报),它会向微软推送通知服务(Microsoft Push Notification Services)发送消息。
- 微软推送通知服务(Microsoft Push Notification Services)将消息中继到Windows Phone设备,由Window Phone客户端应用程序处理收到的消息。
深度剖析推送通知实现架构
推送通知消息类
- RawPushNotificationMessage – 当Windows Phone应用程序运行时,可以接收到来自Web Service的Raw通知消息。
- TilePushNotificationMessage –当Windows Phone应用程序被固定显示在启动页面,Windows Phone将呈现Tile通知消息的内容。
- ToastPushNotificationMessage –发送Toast"警告"消息至Windows Phone。

图 Push Messages Class Diagram
推送通知消息的示例
发送Tile通知
var tile = new TilePushNotificationMessage
{
BackgroundImageUri = tileImageUri, // Remote or phone-local tile image uri.
Count = tileCount, // Counter between 1 to 99 should be displayed on the tile.
Title = “Tile Title” // Title to be displayed on the tile.
};
// Send the message synchronously.
try
{
var sendResult = tile.Send(phoneChannelUri);
// Check the send result.
}
catch (Exception ex)
{
// Log the error.
}
// Send the message asynchronously.
tile.SendAsync(
phoneChannelUri,
result => {/* Check the send result */},
exception => {/* Log the error */});
发送Raw通知
byte[] rawData = {};
var raw = new RawPushNotificationMessage
{
RawData = rawData, // Raw data to be sent with the message.
};
// Send the message synchronously.
try
{
var sendResult = raw.Send(phoneChannelUri);
// Check the send result.
}
catch (Exception ex)
{
// Log the error.
}
// Send the message asynchronously.
raw.SendAsync(
phoneChannelUri,
result => { /* Check the send result */ },
exception => { /* Log the error */ });
Windows Phone客户端设定启动推送通知
注册推送通知服务
推送通知设置页面
每个Windows Phone应用,如果使用推送通知都必须允许用户设置推送通知功能的开启和关闭。 即程序开启推送通知PN通道时需要得到用户的许可,且用户也可以选择关闭推送通知PN通道。下面的画面(Project : WindowsPhone.Recipes.Push.Client File : Views/PushSettingControl.XAML)显示了示例应用程序的推送通知设定页面。

图 push setting
Project : WindowsPhone.Recipes.Push.Client File : Views/PushSettingControl.XAML
<UserControl x:Class="WindowsPhone.Recipes.Push.Client.Controls.PushSettingsControl"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tk="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
xmlns:converters="clr-namespace:WindowsPhone.Recipes.Push.Client.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
d:DesignHeight="640" d:DesignWidth="480">
<UserControl.Resources>
<converters:BoolBrushConverter x:Key="BoolBrushConverter" />
<Style x:Key="DescTextStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="14" />
<Setter Property="Foreground" Value="Silver" />
<Setter Property="TextWrapping" Value="Wrap" />
<Setter Property="Margin" Value="16,-38,16,24" />
</Style>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}">
<StackPanel>
<StackPanel>
<tk:ToggleSwitch Header="Push Notifications"
IsChecked="{Binding IsPushEnabled, Mode=TwoWay}" />
<TextBlock Style="{StaticResource DescTextStyle}"
Text="Turn on/off push notifications." />
</StackPanel>
<Grid>
<StackPanel Margin="16,0,0,0">
<tk:ToggleSwitch Header="Tile Notifications"
IsChecked="{Binding IsTileEnabled, Mode=TwoWay}" />
<TextBlock Style="{StaticResource DescTextStyle}"
Text="Tile push notifications update the application's tile displayed in the Start Screen. The application must be pinned by the user first." />
<tk:ToggleSwitch Header="Toast Notifications"
IsChecked="{Binding IsToastEnabled, Mode=TwoWay}" />
<TextBlock Style="{StaticResource DescTextStyle}"
Text="Toast push notifications are system-wide notifications that do not disrupt the user workflow or require intervention to resolve and are displayed in the top of the screen for ten seconds." />
<tk:ToggleSwitch Header="Raw Notifications"
IsChecked="{Binding IsRawEnabled, Mode=TwoWay}" />
<TextBlock Style="{StaticResource DescTextStyle}"
Text="Raw push notifications are used to send application specific information. The application must be running first." />
</StackPanel>
<Border Background="{Binding IsPushEnabled, Converter={StaticResource BoolBrushConverter}}" />
</Grid>
</StackPanel>
</Grid>
</UserControl>
当用户登录时,注册PN推送通知的通道。
{
login.Visibility = Visibility.Collapsed;
progress.Visibility = Visibility.Visible;
var pushContext = PushContext.Current;
pushContext.Connect(c => RegisterClient(c.ChannelUri));
}
private void RegisterClient(Uri channelUri)
{
// Register the URI with 3rd party web service.
try
{
var pushService = new PushServiceClient();
pushService.RegisterCompleted += (s, e) =>
{
pushService.CloseAsync();
Completed(e.Error);
};
pushService.RegisterAsync(UserName, channelUri);
}
catch (Exception ex)
{
Completed(ex);
}
}
向Web Service提交订阅,创建PN通道
{
if (IsConnected)
{
prepared(NotificationChannel);
return;
}
try
{
// First, try to pick up an existing channel.
NotificationChannel = HttpNotificationChannel.Find(ChannelName);
if (NotificationChannel == null)
{
// Create new channel and subscribe events.
CreateChannel(prepared);
}
else
{
// Channel exists, no need to create a new one.
SubscribeToNotificationEvents();
PrepareChannel(prepared);
}
IsConnected = true;
}
catch (Exception ex)
{
OnError(ex);
}
}
public void Disconnect()
{
if (!IsConnected)
{
return;
}
try
{
if (NotificationChannel != null)
{
UnbindFromTileNotifications();
UnbindFromToastNotifications();
NotificationChannel.Close();
}
}
catch (Exception ex)
{
OnError(ex);
}
finally
{
NotificationChannel = null;
IsConnected = false;
}
}
创建PN通道的具体函数。
/// <summary>
/// </summary>
private void CreateChannel(Action<HttpNotificationChannel> prepared)
{
// Create a new channel.
NotificationChannel = new HttpNotificationChannel(ChannelName, ServiceName);
// Register to UriUpdated event. This occurs when channel successfully opens.
NotificationChannel.ChannelUriUpdated += (s, e) => Dispatcher.BeginInvoke(() => PrepareChannel(prepared));
SubscribeToNotificationEvents();
// Trying to Open the channel.
NotificationChannel.Open();
}
绑定和解除绑定Raw、Tile和Toast通知消息的函数。
Project: WindowsPhone.Recipes.Push.Client File: PushContext.cs
private void BindToTileNotifications()
try
{
if (NotificationChannel != null && !NotificationChannel.IsShellTileBound)
{
var listOfAllowedDomains = new Collection<Uri>(AllowedDomains);
NotificationChannel.BindToShellTile(listOfAllowedDomains);
}
}
catch (Exception ex)
{
OnError(ex);
}
}
private void BindToToastNotifications()
{
try
{
if (NotificationChannel != null && !NotificationChannel.IsShellToastBound)
{
NotificationChannel.BindToShellToast();
}
}
catch (Exception ex)
{
OnError(ex);
}
}
private void UnbindFromTileNotifications()
{
try
{
if (NotificationChannel.IsShellTileBound)
{
NotificationChannel.UnbindToShellTile();
}
}
catch (Exception ex)
{
OnError(ex);
}
}
private void UnbindFromToastNotifications()
{
try
{
if (NotificationChannel.IsShellToastBound)
{
NotificationChannel.UnbindToShellToast();
}
}
catch (Exception ex)
{
OnError(ex);
}
}
Web Service设计推送通知功能
One-Time--一次性推送三种类型的通知消息
说明
操作
- 运行 WindowsPhone.Recipes.Push.Server 和WindowsPhone.Recipes.Push.Client projects (设置 WindowsPhone.Recipes.Push.Server为默认启动程序)。
- 在Windows Phone模拟器中以任意用户名登录。


- 在服务器端,选择"One Time"选项卡。

- 设置Raw、Tile和Toast消息内容,然后选择"Send"发送。
注意:



代码
File: ViewModels/Patterns/OneTimePushPatternViewModel.cs
/// <summary>
/// </summary>
protected override void OnSend()
{
var messages = new List<PushNotificationMessage>();
if (IsTileEnabled)
{
// Prepare a tile push notification message.
messages.Add(new TilePushNotificationMessage(MessageSendPriority.High)
{
BackgroundImageUri = BackgroundImageUri,
Count = Count,
Title = Title
});
}
if (IsToastEnabled)
{
// Prepare a toast push notification message.
messages.Add(new ToastPushNotificationMessage(MessageSendPriority.High)
{
Title = ToastTitle,
SubTitle = ToastSubTitle
});
}
if (IsRawEnabled)
{
// Prepare a raw push notification message.
messages.Add(new RawPushNotificationMessage(MessageSendPriority.High)
{
RawData = Encoding.ASCII.GetBytes(RawMessage)
});
}
foreach (var subscriber in PushService.Subscribers)
{
messages.ForEach(m => m.SendAsync(subscriber.ChannelUri, Log, Log));
}
}
Counter—计数器重置
说明
代码
/// <summary>
/// is not running, send tile update and increase tile counter.
/// </summary>
protected override void OnSend()
{
// Notify phone for having waiting messages.
var rawMsg = new RawPushNotificationMessage(MessageSendPriority.High)
{
RawData = Encoding.ASCII.GetBytes(RawMessage)
};
foreach (var subscriber in PushService.Subscribers)
{
rawMsg.SendAsync(
subscriber.ChannelUri,
result =>
{
Log(result);
OnRawSent(subscriber.UserName, result);
},
Log);
}
}
一个Raw消息被发送后,运行回调函数OnRawSent。 获取MPNS的检查该设备是否连接的返回值。 如果手机没有连接,发送一个Raw消息是没有意义。 如果设备已连接,则发送一个Tile通知提示用户,Tile通知的内容就是计数器加1。
private void OnRawSent(string userName, MessageSendResult result)
// In case that the device is disconnected, no need to send a tile message.
if (result.DeviceConnectionStatus == DeviceConnectionStatus.TempDisconnected)
{
return;
}
// Checking these three flags we can know what's the state of both the device and apllication.
bool isApplicationRunning =
result.SubscriptionStatus == SubscriptionStatus.Active &&
result.NotificationStatus == NotificationStatus.Received &&
result.DeviceConnectionStatus == DeviceConnectionStatus.Connected;
// In case that the application is not running, send a tile update with counter increase.
if (!isApplicationRunning)
{
var tileMsg = new TilePushNotificationMessage(MessageSendPriority.High)
{
Count = IncreaseCounter(userName),
BackgroundImageUri = BackgroundImageUri,
Title = Title
};
tileMsg.SendAsync(result.ChannelUri, Log, Log);
}
}
Windows Phone应用程序重新登陆后,WPF应用程序Push Notifications Server创建一个计数器清零的Tile通知Windows Phone应用程序的计数器复位。
Project: WindowsPhone.Recipes.Push.Server
/// <summary>
/// </summary>
protected override void OnSubscribed(SubscriptionEventArgs e)
{
// Create a tile message to reset tile count.
var tileMsg = new TilePushNotificationMessage(MessageSendPriority.High)
{
Count = 0,
BackgroundImageUri = BackgroundImageUri,
Title = Title
};
tileMsg.SendAsync(e.Subscription.ChannelUri, Log, Log);
ResetCounter(e.Subscription.UserName);
}
Ask to Pin--询问用户是否将应用程序固定显示在启动页面
说明


代码
/// <summary>
/// has subscription logic on startup), try to update the tile again.
/// In case that the application is not pinned, send raw notification message
/// to the client, asking to pin the application. This raw notification message
/// has to be well-known and handled by the client side phone application.
/// In our case the raw message is AskToPin.
/// </summary>
protected override void OnSubscribed(SubscriptionEventArgs args)
{
// Asynchronously try to send Tile message to the relevant subscriber
// with data already sent before so the tile won't change.
var tileMsg = GetOrCreateMessage(args.Subscription.UserName, false);
tileMsg.SendAsync(
args.Subscription.ChannelUri,
result =>
{
Log(result);
OnMessageSent(args.Subscription.UserName, result);
},
Log);
}
File: ViewModels/Patterns/ AskToPinPushPatternViewModel.cs
/// <summary>
/// In case that the application is not pinned, ask to pin.
/// </summary>
private void OnMessageSent(string userName, MessageSendResult result)
{
if (!CheckIfPinned(result))
{
AskUserToPin(result.ChannelUri);
}
}
/// <summary>
/// Just in case that the application is running, send a raw message, asking
/// the user to pin the application. This raw message has to be handled in client side.
/// </summary>
private void AskUserToPin(Uri uri)
{
new RawPushNotificationMessage(MessageSendPriority.High)
{
RawData = Encoding.ASCII.GetBytes(RawMessage)
}.SendAsync(uri, Log, Log);
}
通过MPNS返回值的三个标志DeviceConnectionStatus、SubscriptionStatus和NotificationStatus来确定应用程序是否被固定显示在启动页面。
private bool CheckIfPinned(MessageSendResult result)
// We known if the application is pinned by checking the following send result flags:
return result.DeviceConnectionStatus == DeviceConnectionStatus.Connected &&
result.SubscriptionStatus == SubscriptionStatus.Active &&
result.NotificationStatus == NotificationStatus.Received;
}
Custom Tile--定制Tile通知消息
说明
限制
- URI必须能够访问到手机
- 图像的大小必须小于80KB
- 下载的时间不能超过60秒
代码
Tile Scheduled--Tile更新计划表
说明
代码



private void ButtonTestNow_Click(object sender, RoutedEventArgs e)
try
{
var pushService = new PushServiceClient();
pushService.UpdateTileCompleted += (s1, e1) =>
{
try
{
pushService.CloseAsync();
}
catch (Exception ex)
{
ex.Show();
}
};
pushService.UpdateTileAsync(PushContext.Current.NotificationChannel.ChannelUri, SelectedServerImage);
}
catch (Exception ex)
{
ex.Show();
}
}

浙公网安备 33010602011771号