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支援的類型:
‧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,如下圖:
出現在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);
}
執行結果畫面:
最後的Toast XML內容如下:
<toast launch="{"type":"toast","param1":"12345","param2":"67890"}">
<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";
}
}
執行結果:
如果您覺得直接操作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)
‧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) (重要)
‧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