Windows Phone 8.1 - 操作Toast Notification

Windows Phone 8.1 - 操作Toast Notification

千呼萬喚的Action Center終於在WP 8.1出現了,可以看到Toast訊息的清單,不再是一閃即逝的可怕體驗。

因此,該篇將會介紹相關新的Toast使用方式以及Action Center如何管理Toast。

 

[重要觀念]

1. WP 8.1開始採用「notification」的機制來操作Tile、Badge、Toast;

2. Toast支援App在前景或背景中使用;

3. Toast可利用local API呼叫或是結合Push Notification Service(from Cloud)的方式加以呈現;

 

 

A. Toast notification

    根據<Toast notification overview (Windows Runtime apps)>的介紹,Toast支援顯示文字、圖片與音效,

音效僅支援系統的音效,而WP圖片只有logo。在WP裡Toast僅顯示於畫面正上方與Win8是不一樣的。

Toast的activated、dismissed與ignored均是依照用戶來決定,用戶點擊了Toast即會觸發他們預期要進入的畫面與任務。

但需注意Toast必竟僅能呈現少數資訊,最好在顯示Toast的訊息時先進行整理顯示用戶主要觀切的部分即可。

 

Toast具有二種類型:Standard toast與Long-duration toast;但WP僅支援Standard toast

在WP8.1針對Toast支援了:

‧Schedule(可以自訂發出Toast的時間)它不需要依賴App的狀態或是網路的能力;

‧Schedule toast可顯示多次在指定的週期內;

 

Toast支援透過XML或是使用指定元件的方式來建立,根據<The toast template catalog>來看一下WP8.1支援的類型:

Example phone toast

ToastText02

<toast>
    <visual>
        <binding template="ToastText02">
            <text id="1">headlineText</text>
            <text id="2">bodyText</text>
        </binding>  
    </visual>
</toast>

    從上述XML範例可以了解它與過去ShellToast可操作的是一樣,包括:Title與Content。

    WP8.1無法在Toast上放入圖片,使會出現150x150的logo。需要注意WP的<text id="2" />是不會折行的

    詳細說明可參考<schema>或是<The toast template catalog (Windows Runtime apps)>。

 

‧Toast audio options

    主要藉由Toast notification XML中的<audio />來定義該Toast要使用的音效。它是選擇性使用的,目前僅能使用系統的音效

(Only the system sounds listed in this topic can be used in a toast notification; the selections are not extensible.) 使用方法如下:

<!-- loop 屬性值會根據選擇的音效為true或false -->
<audio src="ms-winsoundevent:Notification.Mail" loop="false"/>

 

1. 在指定音效時,「ms-winsoundevent」關鍵字固定需存在的。

 

2. loop屬性:false代表播放一次;true代表重覆播放。

    當設定loop="true"時,需要注意多設定duration,讓Toast知道要播的是長還是短音效,如下:

<toast duration? = "long" | "short">
  <!-- Child elements -->
  visual,
  audio?,
  commands?
</toast>

   但是WP8.1不支援loop="true"的音效,所以設定「duration="long"」是無效的

 

3. 可用的音效與類型如下表(The toast audio options catalog (Windows Runtime apps)):

類型 名稱 說明
non-looping sounds
(loop="false")
Notification.Default situations:
‧When it is explicitly specified
‧When no other audio option is specified
‧When the specified audio option is invalid
‧When no other audio option fits your scenario
  Notification.IM Scenario: A new instant messenger notification has arrived.
  Notification.Mail Scenario: A new e-mail has arrived.
  Notification.Reminder Scenario: An calendar item is due.
  Notification.SMS Scenario: A new text message has arrived.
Looping sounds
(loop="true")
Notification.Looping.Alarm Scenario: A countdown stopwatch has reached 0.
  Notification.Looping.Alarm2 Scenario: A countdown stopwatch has reached 0.
  Notification.Looping.Alarm3 Scenario: A countdown stopwatch has reached 0.
  Notification.Looping.Alarm4 Scenario: A countdown stopwatch has reached 0.
  Notification.Looping.Alarm5 Scenario: A countdown stopwatch has reached 0.
  Notification.Looping.Alarm6 Scenario: A countdown stopwatch has reached 0.
  Notification.Looping.Alarm7 Scenario: A countdown stopwatch has reached 0.
  Notification.Looping.Alarm8 Scenario: A countdown stopwatch has reached 0.
  Notification.Looping.Alarm9 Scenario: A countdown stopwatch has reached 0.
  Notification.Looping.Alarm10 Scenario: A countdown stopwatch has reached 0.
  Notification.Looping.Call Scenario: An incoming phone call.
如果設定loop="true"的音效有問題或無效的,則系統會預設使用該類型的音效。
  Notification.Looping.Call2 Scenario: An incoming phone call.
  Notification.Looping.Call3 Scenario: An incoming phone call.
  Notification.Looping.Call4 Scenario: An incoming phone call.
  Notification.Looping.Call5 Scenario: An incoming phone call.
  Notification.Looping.Call6 Scenario: An incoming phone call.
  Notification.Looping.Call7 Scenario: An incoming phone call.
  Notification.Looping.Call8 Scenario: An incoming phone call.
  Notification.Looping.Call9 Scenario: An incoming phone call.
  Notification.Looping.Call10 Scenario: An incoming phone call.

 

4. 如果需要Toast出現時是靜音,可以在<audio />加上「silent="true"」的屬性值,預設值為「silent="false"」。

 

 

大致上介紹完Toast的一些新屬性,接下來介紹如何操作Toast。

 

[必要步驟]

在manifest開啟Toast Capable,如下圖:

    000

出現在Package.appxmanifest中的內容為:

m3:VisualElements DisplayName="wp81Toast" 
        Square150x150Logo="Assets\Logo.png" 
        Square44x44Logo="Assets\SmallLogo.png" 
        Description="wp81Toast" 
        ForegroundText="light" BackgroundColor="transparent" 
        ToastCapable="true">
    <m3:DefaultTile Wide310x150Logo="Assets\WideLogo.png" 
                    Square71x71Logo="Assets\Square71x71Logo.png">
    </m3:DefaultTile>
    <m3:SplashScreen Image="Assets\SplashScreen.png" />
    <m3:ApplicationView MinWidth="width320" />
    <!--Used in XAML Designer. DO NOT REMOVE-->
  </m3:VisualElements>

詳細的解釋可參考<How to opt in for toast notifications (Windows Runtime apps)>。

 

〉利用ToastTemplateType取得Toast XML建立Toast

    ToastTemplateType提供了Toast可用的XML Template,但WP8.1目前僅支援 toastText02 一種類型。

<text id="1" />是粗體文字,<text id="2" />則為一般文字,二者均不會折行,建議二者不要有連續文字的串聯。

1. 操作方式如下:

private void SendToast()
{
   XmlDocument tXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);
   //加入text1 與 text2
   XmlNodeList tTextNodes = tXml.GetElementsByTagName("text");
   tTextNodes[0].AppendChild(tXml.CreateTextNode("Text1"));
   tTextNodes[1].AppendChild(tXml.CreateTextNode("Text2"));
  
   ToastNotification tToastNo = new ToastNotification(tXml);
 
   ToastNotifier tTastNotifier = ToastNotificationManager.CreateToastNotifier();
   tTastNotifier.Show(tToastNo);
}

    取得xml之後就要透過XML Path的方式去操作text1與text2二個node的文字。另外,由於WP8.1不支援Toast <image />的調整,非常可惜。

    如果您是做Win8.1的App則可以加上修改但有些規範<Tile and toast image sizes>;

     a. 必需低於200 KB;

     b. 必需小於1024x1024 pixles;

     c. src需要的url是ms-appx://(代表圖片需封裝在程序中)、local folder或是web;

 

2. 指定<audio />的元素

//指定<audio />
IXmlNode tToastNode = tXml.SelectSingleNode("/toast");
XmlElement tAudio = tXml.CreateElement("audio");
tAudio.SetAttribute("src", "ms-winsoundevent:Notification.IM");
tAudio.SetAttribute("loop", "false");
//設定靜音
//tAudio.SetAttribute("silent", "true");

    如果設定了<audio />的屬性,要記得把上述silent的設定註解掉,不然無法正確發出音效。記得把loop=false,預設即是false。

 

3. 控制點擊Toast後要執行的參數

    當用戶點擊Toast預期App會被執行,並且看到相關該Toast的畫面與資訊。因此,需要在Toast裡面增加指定 launch 的屬性

launch屬性跟過去一樣可以指定一些string的參數在Toast被點擊後,在程式執行時將這些參數給取出來應用。

如下範例:

//指定Launch的參數,param1與param2是自定的
((XmlElement)tToastNode).SetAttribute("launch", 
           "{\"type\":\"toast\",\"param1\":\"12345\",\"param2\":\"67890\"}");

 

 

4. 發送Toast訊息

     最後將上述提到建立Toast XML、加上<audio />與指定Launch的步驟總合起來,進行發送Toast如下:

private void SendToast()
{
    XmlDocument tXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);
    //加入text1 與 text2
    XmlNodeList tTextNodes = tXml.GetElementsByTagName("text");
    tTextNodes[0].AppendChild(tXml.CreateTextNode("Text1"));
    tTextNodes[1].AppendChild(tXml.CreateTextNode("Text2"));
 
    //指定<audio />
    IXmlNode tToastNode = tXml.SelectSingleNode("/toast");
    XmlElement tAudio = tXml.CreateElement("audio");
    tAudio.SetAttribute("src", "ms-winsoundevent:Notification.IM");
    tAudio.SetAttribute("loop", "false");
    //設定靜音
    //tAudio.SetAttribute("silent", "true");
    tToastNode.AppendChild(tAudio);
 
    //指定Launch的參數,type, param1與param2是自定的
    ((XmlElement)tToastNode).SetAttribute("launch", 
                "{\"type\":\"toast\",\"param1\":\"12345\",\"param2\":\"67890\"}");
   
    //將ToastXML轉換成一個ToastNotification物件
    ToastNotification tToastNo = new ToastNotification(tXml);
    //藉由ToastNotificationManager建立Notifier將ToastNotification進行發送
    ToastNotifier tTastNotifier = ToastNotificationManager.CreateToastNotifier();
    tTastNotifier.Show(tToastNo);
}

     執行結果畫面:

     image   002

 

     最後的Toast XML內容如下:

<toast launch="{&quot;type&quot;:&quot;toast&quot;,&quot;param1&quot;:&quot;12345&quot;,&quot;param2&quot;:&quot;67890&quot;}">
  <visual>
    <binding template="ToastText02">
      <text id="1">Text1Text1</text>
      <text id="2">Text1Text2</text>
    </binding>
  </visual>
  <audio src="ms-winsoundevent:Notification.IM" loop="false"/>
</toast>

     可以看到launch屬性帶入的值是比較接近JSON的格式。至於launch給予參數是否要這麼複雜,其實也不一定,可以改用舊有的寫法:

((XmlElement)tToastNode).SetAttribute("launch",
                        string.Format("key1={0}&key2={1}", "12345", 67890));

    模擬類似QueryString的寫法來傳參資料也是可以的。

 

5. 操作launch帶入的參數

     新的Toast使用與過去ShellToast使用的方式不同,它沒有NavigationUri可指定畫面與QueryString參數值,而是改由launch取代參數的部分。

那點擊Toast之後究竟要進入那一個畫面該怎麼控制呢?

     改由App.xaml.cs中的OnLaunched()事件來負責,藉由LaunchActivatedEventArgs物件中的Arguments屬性取得定義在launch的參數值。

開發人員即可以用參數值自訂義要轉到那一個畫面進行處理

 

舉個簡單範例,在Toast的launch給了2個參數:key1=12345,key2=6789,那我希望直接交由MainPage.xaml.cs來處理。

以下是修改OnLaunched()的程式邏輯:

protected override void OnLaunched(LaunchActivatedEventArgs e)
{
    //第一次進入App或是App以被關閉重新開啟
    if (rootFrame.Content == null)
    {
        // Removes the turnstile navigation for startup.
        if (rootFrame.ContentTransitions != null)
        {
            this.transitions = new TransitionCollection();
            foreach (var c in rootFrame.ContentTransitions)
            {
                this.transitions.Add(c);
            }
        }
 
        rootFrame.ContentTransitions = null;
        rootFrame.Navigated += this.RootFrame_FirstNavigated;
 
        // 預設進入就會將e.Arguments帶入
        if (!rootFrame.Navigate(typeof(MainPage), e.Arguments))
        {
            throw new Exception("Failed to create initial page");
        }
    }
    else
    {
        //代表不是第一次進入App畫面中已存在MainPage
        //如果您使用的畫面不是在MainPage,記得要重新Navigate
        if (rootFrame.Content.GetType().Equals(typeof(MainPage)))
        {
            ((MainPage)rootFrame.Content).FeedParams(e.Arguments);
        }
    }
}

     我利用識別目前是否為第一次進入App或是App被關閉重新啟動,識別是否需要將參數帶入MainPage;

另一個則是如果當rootFrame.Content正是目前執行的MainPage,則是直接在MainPage開一個方法進行參數傳遞,

不再重新呼叫Navigate避免Navigation Stack錯誤。<如何處理從快顯通知的啟用 (使用 C#/VB/C++ 和 XAML 的 Windows 執行階段應用程式)>。

 

那MainPage.xaml.cs需要做什麼處理呢?分別在OnNavigatedTo處理App第一次開始與開立新的方法FeedParams處理App非第一次開啟。

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    if (string.IsNullOrEmpty(e.Parameter.ToString()) == false)
    {
        //代表是由Toast傳入的參數
        Dictionary<string, string> tKeySet = e.Parameter.ToString().Split('&').Select(x => x.Split('='))
                                            .ToDictionary(x => x[0], x => x[1]);
        txtParma1.Text = tKeySet["key1"];
        txtParma2.Text = tKeySet["key2"];
        txtParma3.Text = "OnNavigatedTo";
    }
}
 
public void FeedParams(string pParams)
{
    if (string.IsNullOrEmpty(pParams) == false)
    {
        //代表是由Toast傳入的參數
        Dictionary<string, string> tKeySet = pParams.Split('&').Select(x => x.Split('='))
                                            .ToDictionary(x => x[0], x => x[1]);
        txtParma1.Text = tKeySet["key1"];
        txtParma2.Text = tKeySet["key2"];
        txtParma3.Text = "FeedParams";
    }
}

執行結果:

(app被關閉用Toast第一次開啟App)003

(直接點擊Toast的訊息進入App中)004

 

如果您覺得直接操作XML的方式很不方便的話,可參考<Quickstart: Using the NotificationsExtensions library in your code>的方式。

先將NotificationExtensions加入專案參考,即可以透過熟悉的物件化方式操作Toast與其他notification的物件(Tile、Badge)。

 

[範例程式]

====

以上是介紹如何操作Toast Notification的方式與組合結構,針對新的Windows Phone 8.1還存在著很多新的功能與機制。

更進階的說明請參考<Windows Phone 8.1 - Toast Notification事件與Action Center>。

希望對大家有所幫助,謝謝。

 

References

Sending toast notifications (Windows Runtime apps using C#/VB/C++ and XAML)

Delivering scheduled, periodic, and push notifications (Windows Runtime apps using C#/VB/C++ and XAML)

Working with tiles, badges, and toast notifications (Windows Runtime apps using JavaScript and HTML)

App tiles and badges sample (重要)

Managing toast notifications in action center (重要)

//Build/ 2014 Windows Phone 8.1 重點Session 整理

Windows Phone 8.1 for Developers–Live Tiles

Lock screen overview (Windows Runtime apps)

Managing toast notifications in action center(Windows Phone Store apps) (重要)

Quickstart: Managing toast notifications in action center (Windows Phone Store apps using C#/VB/C++ and XAML)

Windows Phone 8.1 for Developers–Overview

Quickstart: Sending a toast notification & Toast notifications sample

Quickstart: Sending a toast notification (Windows Runtime apps using JavaScript and HTML)

Quickstart: Using the NotificationsExtensions library in your code.

Toast - commands & Alarm toast notifications sample

 

Dotblogs 的標籤: