自訂要擷取的SMS-Windows Mobile
操作Windows Mobile的使用者都知道,不管來自於Email、SMS或MMS的訊息,都會統一進到訊息中心這個長的很像
Outlook的程式之中,你可以透過訊息中心讀取與控制與簡易版Outlook express差不多功能的操作,但是,它並沒有
辦法可以按照Outllook一樣幫你把特定的訊息處理到你想要的地方,或者說,如果你想要每次當你老婆傳過來的甜蜜
簡訊時,可以事先過濾出來顯示給你看,那麼你可能需要去找一下相關的軟體來安裝使用;如果你是特定公司的工程
師或學校的學生要做個產品,想要讓程式在手機收到特定簡訊時,可以做特別的事,例如:過濾只接收公司的簡訊等
那麼,你可以參考一下這一篇的說明,在.NET Compact Framework中,它提供了一個類例:MessageInterceptor,
協助處理這樣的需求。
那麼在說明程式怎麼使用.NET Compact Framwork所提供的MessageInterceptor時,我們可以先了解一些事情:
透過程式發出SMS,可以參考Microsoft.WindowsMobile.PocketOutlook.SMSMessage這個Class,那麼當簡訊送達手機時,
訊息中心或系統應該會觸發那些事情呢?
(1) 訊息接收者的State會改變。(這關於SystemState)
(2) 系統發出Notification告訴訊息中心。(System.Notification)
(3) 訊息中心將訊息讀取成要顯示的標題列、日期,並儲存ROM中。(Microsoft.WindowsMobile.PocketOutlook)
上述的說明,主要提供大家了解在訊息處理的主要流程與相對於.NET Compact Framework中所使用的類別。接下來,
下方將詳細說明如何完成在擷取訊息內容,並且讀取出訊息的內容與來源。
要使用MessageInterceptor,主要在VS2008專案中需要加入2個重要的參考元件庫:Microsoft.WindowsMobile與
Microsoft.WindowsMobile.PocketOutlook。
在使用MessageInterceptor時,需要注意二個重要的開發概念:
1) Deciding Whether to Share the Message
因為MessageInterceptor主要是協助我們開發程式,讓它觸發在訊息送到訊息中心或交給其他訊息處理程式處理之前,
因此,我們必需在設計時,先思考清楚是否訊息的處理只要在我們自行建立的程式就好,還是也要傳到訊息中心做處理。
如果,建立一個Interceptor程式,而且允許讓訊息往下交由其他訊息處理程式的話,記得在Instance該MessageInterceptor
時,記得加上InterceptionAction.Notify;相反的,如果不想再往下交出去,將傳入InterceptionAction.NotifyAndDelete,
在預設是使用InterceptionAction.Notify。
2) Filtering Messages
建立過濾訊息的條件,透過建立一個MessageCondition類別的Instance,做為MessageInterceptor中MessageCondition
屬性值,而MessageCondition類別需要4個重要的資訊來設定一個完整的條件:
a. 必須設定要用訊息的那個部分做為辨識的依據(MessageProperty enumeration),例如:電話號碼、寄件者、內容值等方式。
b. 設定要以那一種辨別的結果值當作擷取的依據(MessagePropertyComparisonType enumeration),例如:等於、大於等。
c. 設定要識別的值。例如:人名:Pou、電號:0932111111或內容包括:Test。
d. 設定要識別的值是否有大小寫之分。
針對MessageProperty與MessagePropertyComparsionType可用的值如下之列表:
‧MessageProperty enumeration values
Value | Description |
Body | 透過訊息內容做為完成識別的方式。 |
MessageClass | 透過訊息類別來做為識別的方式,其所有標準的SMS訊息都是相同的MessageClass,IPX.SMSText。 |
Sender | 使用Sender的資訊做為識別的方式,此Sender會參考該行動裝置中的通訊錄的人名為主。 |
Subject | 透過訊息的主旨做為識別的方式。但SMS訊息通常沒有主旨所以這個值不常使用 |
‧MessagePropertyComparsionType enumeration values
Value | Description |
Equal | 代表訊息屬性與比較值必需完全一致,使用此類型的比較,要特別注意細微的變化都視為不同。 |
NotEqual | 代表訊息屬性與比較值不相同。 |
Contains | 代表比較值出現於訊息屬性中。 |
StartsWith | 代表比較值出現於訊息屬性中最開頭。 |
EndWith | 代表比較值出現於訊息屬性中結尾。 |
上述二個表格就可以清楚知道要怎麼設定條件來過濾訊息內容。
另外,在處理訊息抵達時要做的事情時, 由MessageInterceptor該類別公開提供一個事件:MessageReceived,讓它可以
接收來自MesseageInterceptorEventHandler的委派,換句話說,當SMS訊息送達時,MessageReceived這個Event會被啟動,
並且丟出MessageInterceptorEventArgs的Reference到我們要處理的Method之中(或是直接Override本身的MessageReceived
事件),而MessageInterceptor只有一個公開的屬性:Message,代表收到訊息的內容,但Message屬性是來自於Message Class
而不是SmsMessage Class,所以必需做轉型才能取得SMS Body。
以下將舉一個簡單的例子說明實作MessageInterceptor:
1: using Microsoft.WindowsMobile;
2: using Microsoft.WindowsMobile.PocketOutlook;
3:
4: MessageInterceptor _smsInterceptor = null;
5:
6: private void Form1_Load(object sender, EventArgs e)
7: {
8: // 實例化MessageInterceptor類別,並且設定過濾條件為:
9: // 判斷訊息內容的傳送者為Smith, John的訊息。
10: _smsInterceptor = new MessageInterceptor();
11: _smsInterceptor.MessageCondition =
12: new MessageCondition(MessageProperty.Sender,
13: MessagePropertyComparisonType.Contains, "Smith, John", false);
14: // 修改MessageInterceptor類別中MessageReceived所要處理的事件內容。
15: _smsInterceptor.MessageReceived += SmsInterceptor_MessageReceived;
16: }
17:
18: void SmsInterceptor_MessageReceived(object sender, MessageInterceptorEventArgs e)
19: {
20: // 轉換Message內容為SmsMessage,才能取得訊息內容
21: SmsMessage newMessage = e.Message as SmsMessage;
22: if (newMessage != null)
23: {
24: statusBar1.Text = "From:" + newMessage.From.Address;
25: Debug.WriteLine(string.Format("Sender:{0} - Body:{1}", _
26: newMessage.From.Address, newMessage.Body));
27: }
28: }
29:
30: private void Form1_Closed(object sender, EventArgs e)
31: {
32: if (_smsInterceptor != null)
33: {
34: // 移除MessageInterceptor.MessageReceived的事件處理,並且清除註冊的服務,避免重覆開啟。
35: _smsInterceptor.MessageReceived -= SmsInterceptor_MessageReceived;
36: _smsInterceptor.Dispose();
37: }
38: }
從上述的程式,你可以看到第10~15段主要實作該MessageInterceptor、設定MessageCondition條件,並且提供MessageReceived
事件一個Event Hander:SmsInterceptor_MessageReceived;第21~27行則是該Event Handler要做的事情;最後第32行到37行,
則是Dispose該MessageInterceptor實作物件。接著下方將詳細說明這個範例的一些重要概念:
首先,當我們實作化一個MessageInterceptor類別時,除了擁有該類別的屬性與方法之外,該MessageInterceptor一個重要的事件
:MessageReceived,當我們實作他的Event Handler時,它會讓MessageInterceptor類別產生一個temporary registry entry(臨時
的註冊實體)並儲存於註冊表之中:HKLM\Software\Microsoft\Inbox\Rules,這個register entry包含關於該實作MessageInterceptor
的相關資訊,用來當訊息抵達系統時,Messaging Subsystem(你可以把他當成訊息中心)根據該register entry通知MessageInterceptor
可以執行它的活動。但是這裡要提及一個重點,在上一篇[]範例中,最後在Form_Close的事件時,執行了下面二段程式內容:
1: _smsInterceptor.MessageReceived -= SmsInterceptor_MessageReceived;
2: _smsInterceptor.Dispose();
這二段程式內容,主要是透過取消針對該MessageInterceptor中MessageReceiveed事件的Event Handler,讓MessageInterceptor
移除該register entry,並且通知GC(垃圾回收)回收該MessageInterceptor實例。這二段的原因在於,register entry不會因為關閉
程式後,MesageInterceptor就自動真的從註冊表中清除掉,而這些保留下來的register entry會一直存在,甚至接下來重覆執行的
MessageInterceptor都不會在用到它們,因此,這將會造成註冊表的混亂影響效能。這是要特別注意的。
針對這篇文章寫到最後,我發現,應該補充怎麼把寫好的App變成可以Background也可以執行,甚至變成一個服務的方式。
因此,接下來下一篇希望可以整理出相關的這篇文章後續處理MessageInterceptor註冊到註冊表與啟動時就要載入的方式,
繼續分享並且做為自己學習的筆記。
References:
http://msdn.microsoft.com/en-us/library/bb932385.aspx