
Obsługa lokalnych notyfikacji w Universal Apps
- Kategoria: Aplikacje mobile, autor: Jerzy Piechowiak
- Tagi: C#, .Net, Biblioteki, Universal Apps, Windows Phone
- Odsłony: 3707
Notyfikacje są obecnie czymś powszechnym w każdym liczącym się mobilnym systemie. Dzięki nim, jesteśmy na bieżąco z mailami, powiadomieniami z Facebooka, czy choćby z wynikiem wyczekiwanego meczu. Windows Phone nie odstaje niczym w tym obszarze od swojej konkurencji, a nawet oferuje kilka dodatkowych, ciekawych opcji.
W dzisiejszym tekście przedstawię przykładowe użycie lokalnych notyfikacji typu toast - zarówno w wersji harmonogramowanej (scheduled) jak i normalnej. Notyfikacje innego typu wysyła się w zbliżony sposób - zmieniamy rodzaj używanych klas oraz XMLa.
Kilka słów teorii
Notyfikacje typu toast, możemy wysyłać od razu bądź też w zaplanowanym czasie. Jeśli skorzystamy z tej drugiej opcji, to notyfikacja zostanie dostarczona również w sytuacji gdy aplikacja będzie wyłączona.
Notyfikacje w systemie Windows Phone budowane są w oparciu o zestaw predefiniowanych szablonów XML, które możemy edytować na potrzeby konkretnego powiadomienia. Dostępne rodzaje szablonów zapisano w enumeracji ToastTemplateType.
W każdej notyfikacji, oprócz standardowych pól typu tytuł, tekst itp., możemy również dodać atrybut launch, który pozwala na określenie argumentów, które zostaną przekazane do aplikacji po kliknięciu w powiadomienie. String tego typu nie powinien być zbyt długi, by nie spowodować wyjątku. Z reguły jest to id jakiegoś elementu w bazie danych, na temat którego szczegóły aplikacja pobiera sobie sama.
Przykład praktyczny
Zwieńczeniem tekstu będzie przykład praktyczny. Wykorzystałem w tym celu zrąb standardowego projektu, do którego wprowadziłem kilka poprawek. Zacznijmy od pliku App.xaml.cs oraz fragmentu metody OnLaunched:
if (rootFrame.Content == null) { // ... if (!rootFrame.Navigate(typeof(MainPage), e.Arguments)) { throw new Exception("Failed to create initial page"); } } else { if(rootFrame.Content is MainPage) { ((MainPage)rootFrame.Content).ReceivedValue = e.Arguments; } }
W pierwszym fragmencie kodu, widzimy próbę nawigacji do strony MainPage, w sytuacji gdy aplikacja nie była wcześniej uruchomiona. To na co warto zwrócić uwagę w tym miejscu to fakt, że do strony przekazywane są argumenty aplikacji. Druga część kodu zostaje wywołana w sytuacji gdy program jest aktywny, a my kliknęliśmy na notyfikację. W takiej sytuacji sprawdzamy czy obecnie znajdujemy się na stronie MainPage i jeśli tak, to przekazujemy do jednej z właściwości tej strony, wartość pola Arguments. To oczywiście spore uproszczenie, w praktyce większość aplikacji posiada sporą liczbę różnych stron i powinniśmy te sytuację obsłużyć w jakiś bardziej zmyślny sposób, który będzie pasował do naszego kontekstu.
Pozostały kod aplikacji koncentruje się wokół strony MainPage. Zacznijmy od frontendu:
<Page x:Class="LocalNotifications.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:LocalNotifications" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Grid x:Name="LayoutRoot"> <Grid.Resources> <Style TargetType="Button"> <Setter Property="HorizontalAlignment" Value="Stretch" /> </Style> </Grid.Resources> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <StackPanel Margin="19,0,0,0"> <TextBlock Text="NOTIFICATIONS APP" Style="{ThemeResource TitleTextBlockStyle}" Margin="0,12,0,0"/> <TextBlock Text="test page" Margin="0,-6.5,0,26.5" Style="{ThemeResource HeaderTextBlockStyle}" CharacterSpacing="{ThemeResource PivotHeaderItemCharacterSpacing}"/> </StackPanel> <StackPanel Grid.Row="1" x:Name="ContentRoot" Margin="19,9.5,19,0"> <Button x:Name="ButtonToast" Click="ButtonToast_Click" Content="instant toast" /> <Button x:Name="ButtonScheduledToast" Click="ButtonScheduledToast_Click" Content="scheduled toast (10s)" /> <TextBlock Style="{StaticResource BaseTextBlockStyle}"> <Run Text="received value:" /> <Run Text="{Binding ReceivedValue}" /> </TextBlock> </StackPanel> </Grid> </Page>
W tym przypadku nic nadzwyczajnego. Dwa proste przyciski, a każdy z nich wysyła inną notyfikację. Ostatnim elementem formatki jest TextBlock, który wyświetla argumenty przekazane do aplikacji - jeśli oczywiście takowe występują.
Najważniejsze elementy znajdują się w części Code-Behind. Poniżej skrócony kod:
// usingi namespace LocalNotifications { [ImplementPropertyChanged] public sealed partial class MainPage : Page { private NavigationHelper navigationHelper; public MainPage() { // ... this.DataContext = this; } public string ReceivedValue { get; set; } // ... #region NavigationHelper registration protected override void OnNavigatedTo(NavigationEventArgs e) { this.navigationHelper.OnNavigatedTo(e); if(e.Parameter != null) { this.ReceivedValue = e.Parameter.ToString(); } } // ... #endregion private void ButtonToast_Click(object sender, RoutedEventArgs e) { ToastTemplateType toastTemplate = ToastTemplateType.ToastText02; XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(toastTemplate); var toastElement = ((XmlElement)toastXml.SelectSingleNode("/toast")); var toastTextElements = toastXml.GetElementsByTagName("text"); toastElement.SetAttribute("launch", "regulararg"); toastTextElements[0].AppendChild(toastXml.CreateTextNode("Regular Toast!")); try { ToastNotification toast = new ToastNotification(toastXml); var toastNotifier = ToastNotificationManager.CreateToastNotifier(); toastNotifier.Show(toast); } catch (Exception ex) { // Handle exception } } private void ButtonScheduledToast_Click(object sender, RoutedEventArgs e) { ToastTemplateType toastTemplate = ToastTemplateType.ToastText02; XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(toastTemplate); var toastElement = ((XmlElement)toastXml.SelectSingleNode("/toast")); var toastTextElements = toastXml.GetElementsByTagName("text"); toastElement.SetAttribute("launch", "scheduledarg"); toastTextElements[0].AppendChild(toastXml.CreateTextNode("Scheduled Toast!")); try { ScheduledToastNotification scheduledToast = new ScheduledToastNotification(toastXml, DateTimeOffset.Now.AddSeconds(10)); var toastNotifier = ToastNotificationManager.CreateToastNotifier(); toastNotifier.AddToSchedule(scheduledToast); } catch (Exception ex) { // Handle exception } } } }
Aby nie bawić się w implementację interfejsu INotifyPropertyChanged, postanowiłem wykorzystać sprawdzoną bibliotekę Fody (4). W kolejnym kroku ustawiamy kontekst danych (12) oraz definiujemy właściwość ReceivedValue (15-19), do której odnosiliśmy się już wcześniej zarówno z poziomu frontendu jak i pliku App.xaml.cs. W przypadku czystego
uruchomienia aplikacji, powinniśmy sprawdzić, czy argumenty zostały przekazane do strony (24-31) i w razie czego podstawić je do wspomnianej wyżej właściwości.
Całą brudną robotę
odwalają dwie metody na końcu listingu, które wysyłają notyfikacje. Jest to na tyle prosty i czytelny kod, że odpuszczę sobie jego szerszy opis.
Aby przykład zadziałał (a będzie działać poprawnie nawet na emulatorze), musimy pamiętać o ustawieniu flagi Toast capable w manifeście aplikacji.
Jak widać na załączonym przykładzie, cały mechanizm wysyłania lokalnych notyfikacji nie należy do skomplikowanych. Proces wysyłania pushy jest równie przyjazny, co postaram się udowodnić w jednym z kolejnych wpisów;-)
Cały kod projektu użytego w przykładzie, znajdziecie w dziale download.
Rekomendowane

Cena: 39,90 zł
Komentarze