標籤:winform style blog http color 使用
最近想給應用添加推送訊息,主要是toast訊息,所以就打算去瞭解一下wp訊息推送機制以及實現方法,過程中,查了許多資料,也遇到過一些問題,做完後,自己就做個小筆記,總結一下,好記性不如爛筆頭嘛,以後可以回頭看看,也方便多了,廢話不多說!
wp訊息推送機制
用一幅圖說明,因為官方是英文的,自己在上面添加了一些中文的解析上去,方便大家去理解!
這幅圖的核心內容是,當你的應用請求手機Uri(注意:這裡uri相當於一個ip或者一個物理地址,是唯一性的一個標識),手機的用戶端服務會與微軟推送中心聯絡,然後返回一個uri給用戶端推送服務,然後用戶端服務再把這個uri給你的應用,你的應用再把這個uri發回來給你的伺服器,然後你的伺服器再把這個uri和需要發送的訊息發送給微軟推送中心,最後微軟推送中心再根據這個uri,把訊息推送到指定的手機!
toast訊息推送(wp端)
這個我不想多解釋,直接上推送代碼,下面的代碼主要是查看在應用程式的早期執行個體中是否已設定 Toast 通知通道。如果找到通知通道,則通知通道串連到通知事件。如果未找到通知通道,則建立通知通道,然後將其串連到通知事件
// 建構函式 public MainPage() { HttpNotificationChannel myChannel = null; // 推送通道的名字,隨便取一個就行了 string ChannelName = "ToastChannel"; InitializeComponent(); // Find靜態方法可以根據名字尋找通道 myChannel = HttpNotificationChannel.Find(ChannelName); // 因為系統有時候會刪除通道,所以要判斷是否存在,如果找不到,就要建立一個了 if (myChannel == null) { myChannel = new HttpNotificationChannel(ChannelName); // 註冊事件 myChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(myChannel_ChannelUriUpdated); myChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(myChannel_ErrorOccurred); myChannel.ShellToastNotificationReceived += new EventHandler<NotificationEventArgs>(myChannel_ShellToastNotificationReceived); // 開啟通道 myChannel.Open(); // 綁定Toast通知,這樣在程式不在前台時才會顯示 // 螢幕上方的通知提示條 myChannel.BindToShellToast(); } else { // 如果存在,還要註冊一次事件,因為在程式被扔到後台後可能會刪除事件綁定 myChannel.ChannelUriUpdated+=new EventHandler<NotificationChannelUriEventArgs>(myChannel_ChannelUriUpdated); myChannel.ErrorOccurred+=new EventHandler<NotificationChannelErrorEventArgs>(myChannel_ErrorOccurred); myChannel.ShellToastNotificationReceived+=new EventHandler<NotificationEventArgs>(myChannel_ShellToastNotificationReceived); // 在“輸出”窗輸出URL,因為我們只是測試,這樣一來方便一點 System.Diagnostics.Debug.WriteLine("通道URI為:{0}", myChannel.ChannelUri.ToString()); } } void myChannel_ShellToastNotificationReceived(object sender, NotificationEventArgs e) { //這裡主要是當使用者正在使用你的應用,而你剛好推送訊息過來,執行此方法 string msg = ""; foreach (string key in e.Collection.Keys) { msg += key + " : " + e.Collection[key] + "\r\n"; } Dispatcher.BeginInvoke(() => { this.txtInfo.Text = msg; }); } void myChannel_ErrorOccurred(object sender, NotificationChannelErrorEventArgs e) { Dispatcher.BeginInvoke(() => MessageBox.Show(e.Message)); //錯誤產生的時候,執行這裡面內容,實際情況,可以根據 自己需要處理 } void myChannel_ChannelUriUpdated(object sender, NotificationChannelUriEventArgs e) { // 當URL發生改變後,還要輸出一次 // 保證我們得到的是最新版本的URI Dispatcher.BeginInvoke(() => { System.Diagnostics.Debug.WriteLine("通道URI:{0}", e.ChannelUri.ToString()); }); } toast訊息推送(server端)
這裡我建立一個 ASP.NET 網頁,該網頁使用在裝置上建立推送通道時返回的 URI 來發送 Toast 通知,當然你可以使用任何能發送網路訊息的應用來推送,如winform jsp php等等
具體推送訊息代碼如下:
private void SendMsg() { //txtUrl.Tex該參數是手機的uri,要推送訊息,首先要確定你要推送使用者手機的uri HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(txtUrl.Text); myRequest.ContentType = "text/xml"; myRequest.Headers.Add("X-WindowsPhone-Target", "toast"); /* * X-NotificationClass 處理間隔 * 2 - 立即發送 * 12 - 450秒內發送 * 22 - 900秒內發送 */ myRequest.Headers.Add("X-NotificationClass", "2"); // 要發送的內容 txtValue1.Text:標題,txtValue2.Text:推送內容,txtParam.Text:當使用者點擊訊息的時候,導航的頁面,如mainpage.xaml string toastMessage = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<wp:Notification xmlns:wp=\"WPNotification\">" + "<wp:Toast>" + "<wp:Text1>" + txtValue1.Text + "</wp:Text1>" + "<wp:Text2>" + txtValue2.Text + "</wp:Text2>" + "<wp:Param>" + txtParam.Text + "</wp:Param>" + "</wp:Toast>" + "</wp:Notification>"; byte[] buffer = Encoding.UTF8.GetBytes(toastMessage);//注意此處官方是Encoding.default.GetBytes(toastMessage),我在使用的過程中,老是報錯,下面會說原因 myRequest.ContentLength = buffer.Length; myRequest.Method = "POST"; using (Stream stream = myRequest.GetRequestStream()) { stream.Write(buffer, 0, buffer.Length); } // 發送訊息和擷取回應 HttpWebResponse response = (HttpWebResponse)myRequest.GetResponse(); string notificationStatus = response.Headers["X-NotificationStatus"]; string notificationChannelStatus = response.Headers["X-SubscriptionStatus"]; string deviceConnectionStatus = response.Headers["X-DeviceConnectionStatus"]; //判斷是否成功推送到微軟推送服務中心 // TextBoxResponse.Text = notificationStatus + " | " + deviceConnectionStatus + " | " + notificationChannelStatus; if (notificationStatus == "Received" && deviceConnectionStatus == "Connected" && notificationChannelStatus == "Active") { success++; } }總結和注意
(1) 其中<wp:Param>" + txtParam.Text + "</wp:Param>,當param內容為空白時,可以省略不寫這一節點。同時,在xml中一些字元是要進行轉換的:
<Text1> 和 <Text2> 都採用字串格式。
<Param> 值允許以下格式:
/page1.xaml – 定義應用程式啟動時導航到的應用程式中的頁面。該頁面必須以“/”開頭。
/page1.xaml?value1=1234 &value2=9876 – 定義應用程式啟動時導航到的頁面,以及資訊的成對的名稱和數值。該頁面必須以“/”開頭。
?value1=1234 &value2=9876 – 包含傳遞給應用程式預設開始頁面的資訊成對的名稱和數值。該頁面必須以“?”開頭。
字元 |
XML 編碼 |
< |
< |
> |
> |
& |
& |
‘ |
' |
“ |
" |
(2) 當服務端發送的toast通知中有xml格式錯誤或者非法內容時,微軟推送服務會關閉此通道,並提示出錯。我在運行時老是報錯(“The XML payload contains invalid or improperly formatted XML or the notification type specified in the header does not match the payload type used. The channel has been closed. Check your XML payload for errors and reopen the channel to obtain a new URI.”)。 經過查資料,我把裡面的Encoding.default.GetBytes(toastMessage)改為Encoding.UTF8.GetBytes(toastMessage),這樣就把不報錯了,此處可能是官方範例程式碼有些問題。 (3) 我們Server端想統計推送的成敗情況的話,會比較困難。因為從微軟推送服務中返回的相應代碼中,只是簡單的反映了推播通知到達Proxy 伺服器的情況,而非通知到達用戶端時的結果。比如微軟的Proxy 伺服器返回了響應碼200,我們Server端只是知道了資訊已經成功到達了它那裡,並且符合轉寄到用戶端程式的條件;至於用戶端最終是否真的收到了通知,無法從這裡獲知。當然,當用戶端程式接收到了通知後,可以向Server端彙報,但這並不準確,因為有些資訊可能因為程式不在前台運行同時又被使用者忽略了,此處我直接以三個資訊頭X-NotificationStatus X-SubscriptionStatus X-DeviceConnectionStatus來判斷是否成功發到微軟的推送中心來判斷是否發送成功,至於有其他更準確方案,知道的話,請告訴我!