開發應用程式以處理MobileOperatorNotification事件
本主題說明如何開發可處理 MobileOperatorNotification 事件的行動寬頻應用程式。
最佳做法
針對背景事件處理,您應該使用下列最佳做法:
請勿註冊您無法採取動作的背景事件。 處理這些事件將不需要取用應用程式配額。
在收到背景事件時,請勿執行大量的處理。
請考慮在下次啟動應用程式時延遲處理。
請考慮顯示快顯通知和更新磚以回應背景事件。 您的行動寬頻應用程式可以處理背景事件承載。
步驟 1:背景工作合約宣告
若要讓 Windows 辨識行動寬頻應用程式所提供的背景工作體驗,應用程式必須宣告它正在提供系統功能的擴充功能。
若要在 Visual Studio 專案的 package.appxmanifest 檔案中建立宣告,請執行下列步驟:
宣告背景工作合約
在 方案總管 中,按兩下專案的 package.appxmanifest 檔案。
在 [ 宣告] 索引標籤 的 [可用宣告] 中,選取 [ 背景工作 ],然後按兩下 [ 新增]。
在 [ 屬性] 標題下,輸入下列應用程式資訊:
在 [應用程式設定] 下的 [開始] 頁面方塊中,針對使用 JavaScript 和 HTML 的行動寬带應用程式,輸入處理 (應用程式背景工作的檔名,例如 ,backgroundtask.js) 。
在 [ 支援的工作類型] 標題下,按兩下 [ 系統事件 ] 複選框。
如果正確完成,您應該會在 package.appxmanifest 檔案中擁有類似下列的延伸專案。
<Extension Category="windows.backgroundTasks" StartPage="backgroundtask.js">
<BackgroundTasks>
<Task Type="systemEvent" />
</BackgroundTasks>
</Extension>
步驟 2:背景工作處理程式
如果您的應用程式提供電信業者通知宣告,它必須提供背景工作啟用的處理程式。 處理程式會從 Windows.Networking.NetworkOperators.NetworkOperatorNotificationEventDetails 取得電信業者網路帳戶標識符和事件數據。
因為背景工作唯一支援的UI是 快顯通知,背景工作處理程式可以顯示快顯通知或將 NetworkOperatorNotificationEventDetails 儲存到本機記憶體。
下列程式代碼範例示範一項背景工作,其設計目的是在收到新的系統管理 SMS 通知時執行。
C#
using Windows.Networking.NetworkOperators;
namespace MNOMessageBackground
{
public sealed class MNOBackgroundTask : IBackgroundTask
{
public void Run(Windows.ApplicationModel.Background.IBackgroundTaskInstance taskInstance)
{
NetworkOperatorNotificationEventDetails notifyData = (NetworkOperatorNotificationEventDetails)taskInstance.TriggerDetails;
//The network account ID is stored in notifyData.NetworkAccountId
switch (notifyData.NotificationType)
{
case NetworkOperatorEventMessageType.Gsm: // 0
break;
case NetworkOperatorEventMessageType.Cdma: // 1
break;
case NetworkOperatorEventMessageType.Ussd: // 2
break;
case NetworkOperatorEventMessageType.DataPlanThresholdReached: // 3
break;
case NetworkOperatorEventMessageType.DataPlanReset: //4
break;
case NetworkOperatorEventMessageType.DataPlanDeleted: //5
break;
case NetworkOperatorEventMessageType.ProfileConnected: //6
break;
case NetworkOperatorEventMessageType.ProfileDisconnected: //7
break;
case NetworkOperatorEventMessageType.RegisteredRoaming: //8
break;
case NetworkOperatorEventMessageType.RegisteredHome: ///9
break;
case NetworkOperatorEventMessageType.TetheringEntitlementCheck: //10
break;
default:
break;
}
// Add code to save the message to app local storage, and optionally show toast notification and tile updates.
}
}
}
JavaScript
(function () {
"use strict";
//
// The background task instance's activation parameters are available via
// Windows.UI.WebUI.WebUIBackgroundTaskInstance.current.
//
var backgroundTaskInstance = Windows.UI.WebUI.WebUIBackgroundTaskInstance.current,
networkOperatorEventType = Windows.Networking.NetworkOperators.NetworkOperatorEventMessageType,
key = null,
settings = Windows.Storage.ApplicationData.current.localSettings;
try {
var details = backgroundTaskInstance.triggerDetails;
// The network account ID is stored in details.networkAccountId.
switch (details.notificationType) {
case networkOperatorEventType.gsm:
showToast("Mobile Broadband message", details.message);
break;
case networkOperatorEventType.cdma:
showToast("Mobile Broadband message", details.message);
break;
case networkOperatorEventType.ussd:
showToast("Mobile Broadband message", details.message);
break;
case networkOperatorEventType.dataPlanThresholdReached:
showToast("Mobile Broadband message", "Data plan threshold reached");
break;
case networkOperatorEventType.dataPlanReset:
showToast("Mobile Broadband message", "Data plan reset");
break;
case networkOperatorEventType.dataPlanDeleted:
showToast("Mobile Broadband message", "Data plan deleted");
break;
case networkOperatorEventType.profileConnected:
showToast("Mobile Broadband message", "Profile connected");
break;
case networkOperatorEventType.profileDisconnected:
showToast("Mobile Broadband message", "Profile disconnected");
break;
case networkOperatorEventType.registeredRoaming:
showToast("Mobile Broadband message", "Registered roaming");
break;
case networkOperatorEventType.registeredHome:
showToast("Mobile Broadband message", "Registered home");
break;
case networkOperatorEventType.tetheringEntitlementCheck:
showToast("Mobile Broadband message", "Entitlement check completed");
break;
default:
showToast("Mobile Broadband message", "Unknown message");
break;
}
//
// A JavaScript background task must call close when it is done.
//
close();
}
catch (exception) {
// Display error message.
close();
}
顯示磚和快顯通知
我們建議您在行動寬頻應用程式中同時顯示快顯通知和磚通知,因為使用者可能會因為暫時性而遺漏快顯通知。 如需快顯通知和磚更新體驗設計指導方針,請參閱 設計行動寬頻應用程式的用戶體驗。
啟用快顯通知
在 方案總管 中,按兩下專案的 package.appxmanifest 檔案。
在 [ 應用程式 UI] 索引 標籤的 [ 通知] 標題下,將 [支援快顯 通知] 設定為 [是]。
如果正確完成,您應該會在 package.appxmanifest 檔案中擁有類似下列的延伸專案。
<VisualElements … ToastCapable="true"… />
下列程式代碼示範如何在背景工作句柄中顯示快顯通知:
JavaScript
function showToast(title, body) {
var notifications = Windows.UI.Notifications;
var toastNotificationManager = Windows.UI.Notifications.ToastNotificationManager;
var toastXml = toastNotificationManager.getTemplateContent(notifications.ToastTemplateType.toastText02);
var temp = "the parameter will pass to app when app activated from tap Toast ";
toastXml.selectSingleNode("/toast").setAttribute("launch", temp);
var textNodes = toastXml.getElementsByTagName("text");
textNodes[0].appendChild(toastXml.createTextNode(title));
textNodes[1].appendChild(toastXml.createTextNode(body));
var toast = new notifications.ToastNotification(toastXml);
toastNotificationManager.createToastNotifier().show(toast);
}
取得簡訊簡訊
如果背景工作是由傳入的SMS訊息所觸發,背景工作詳細數據將會在其承載中攜帶SMS物件。
JavaScript
(function () {
"use strict";
//
// The background task instance's activation parameters are available via
// Windows.UI.WebUI.WebUIBackgroundTaskInstance.current.
//
var backgroundTaskInstance = Windows.UI.WebUI.WebUIBackgroundTaskInstance.current,
try {
var details = backgroundTaskInstance.triggerDetails;
if (details.notificationType === networkOperatorEventType.gsm
|| details.notificationType === networkOperatorEventType.cdma)
{
var textMessage = new Windows.Devices.Sms.SmsTextMessage.fromBinaryMessage(details.smsMessage);
// textMessage can be used to get other SmsMessage properties
// like sender number, timestamp, message part count etc.
showToast("From: " + textMessage.from + "; TimeStamp: " + textMessage.timestamp, details.message);
}
使用本機記憶體
背景工作可以使用本機記憶體來儲存您從背景事件取得的訊息,讓應用程式稍後可以使用該資訊。
JavaScript
//
// Save the message
//
var settings = Windows.Storage.ApplicationData.current.localSettings;
var keyMessage = "BA5857FA-DE2C-4A4A-BEF2-49D8B4130A39";
//
// The background task instance's activation parameters are available via
// Windows.UI.WebUI.WebUIBackgroundTaskInstance.current
//
var backgroundTaskInstance = Windows.UI.WebUI.WebUIBackgroundTaskInstance.current;
var details = backgroundTaskInstance.triggerDetails;
settings.values[keyMessage] = details.message;
下列程式代碼示範如何擷取應用程式中背景工作處理程式所儲存的訊息:
JavaScript
var settings = Windows.Storage.ApplicationData.current.localSettings;
var keyMessage = "BA5857FA-DE2C-4A4A-BEF2-49D8B4130A39";
var operatorMessage = settings.values[keyMessage];
步驟 3:處理啟用事件
如果快顯通知設定參數,則會透過 detail.arguments傳遞至應用程式。
在 JavaScript 或 C# 中,您可以處理 WinJS.Application.onactivated 事件,然後檢查傳遞至事件處理程式的事件自變數。 從快顯通知啟用會傳遞 類型為 Windows.UI.WebUI.WebUILaunchActivatedEventArgs 的事件自變數。 如果事件自變數的 detail.kind 屬性是 Windows.ApplicationModel.Activation.ctivationKind。啟動,應用程式會根據事件自變數 的 detail.argument 屬性是否設定為 null,提供 \[開始\] 體驗或 \[通知\] 體驗。
JavaScript
WinJS.Application.addEventListener("activated", activated; false);
function activated(eventArgs)
{
if (eventArgs.detail.kind == Windows.ApplicationModel.Activation.ActivationKind.launch)
{
if (!eventArgs.detail.arguments)
{
// Initialize logic for the Start experience here.
}
else
{
// Initialize logic for the Notification experience here.
}
}
}
步驟 4:處理背景工作完成處理程式
前景應用程式也可以註冊完成處理程式,以在背景工作完成時收到通知。 在背景工作的 Run 方法中發生的完成狀態或任何例外狀況,都會傳遞至前景應用程式中的完成處理程式。 如果應用程式在工作完成時暫停,則會在下一次應用程式繼續時收到完成通知。 如果應用程式處於 「已終止 」狀態,則不會收到完成通知。 如果背景工作需要保留成功執行的資訊,則必須使用狀態管理員或其他方法保存資訊,例如當應用程式回到 執行 中狀態時可以讀取的檔案。
重要 雖然系統會自動向應用程式註冊電信業者背景事件,但應用程式仍然需要至少執行一次,才能註冊背景完成或進度處理程式。
C#
foreach (var cur in BackgroundTaskRegistration.AllTasks)
{
if(cur.Value.Name == “MobileOperatorNotificationHandler”)
{
cur.Value.Progress += new BackgroundTaskProgressEventHandler(OnProgress);
cur.Value.Completed += new BackgroundTaskCompletedEventHandler(OnCompleted);
}
}
//
// Handle background task completion.
private void OnCompleted(IBackgroundTaskRegistration sender, BackgroundTaskCompletedEventArgs e)
{
var taskCompletion = task as IBackgroundTaskRegistration;
var completionArgs = args.Context as BackgroundTaskCompletedEventArgs;
//
// If the background task threw an exception, display the exception in the error text box.
if (completionArgs.Status != null)
{
throw completionArgs.Status;
}
}
// Handle background task progress.
private void OnProgress(IBackgroundTaskRegistration sender, BackgroundTaskProgressEventArgs e)
{
var taskRegistration = task as IBackgroundTaskRegistration;
var progressArgs = args.Context as BackgroundTaskProgressEventArgs;
// progressArgs.Progress has the progress percentage
}
JavaScript
var iter = Windows.ApplicationModel.Background.BackgroundTaskRegistration.allTasks.first();
var hascur = iter.hasCurrent;
while (hascur) {
var cur = iter.current.value;
if (cur.name === “MobileOperatorNotificationHandler”) {
cur.addEventListener("progress", new ProgressHandler(cur).onProgress);
cur.addEventListener("completed", new CompleteHandler(cur).onCompleted);
}
hascur = iter.moveNext();
}
//
// Handle background task progress.
//
function ProgressHandler(task) {
this.onProgress = function (args) {
try {
var progress = "Progress: " + args.progress + "%";
} catch (ex) {
displayError(ex);
}
};
}
//
// Handle background task completion.
//
function CompleteHandler(task) {
this.onCompleted = function (args) {
try {
var key = task.taskId;
} catch (ex) {
displayError(ex);
}
};
}
疑難排解
使用這些區段來協助疑難解答可能發生的問題。
觸發元數據剖析以註冊背景工作
對於使用者,當行動寬頻裝置連線時,Windows 8、Windows 8.1 和 Windows 10 會自動安裝行動寬頻應用程式和相關聯的服務元數據,並註冊服務元數據中定義的背景工作。 不過,在 Windows 8.1 中,應用程式不會自動釘選到 [開始] 畫面。
開發人員可以手動觸發 Windows 8、Windows 8.1 和 Windows 10 來剖析服務元數據並註冊背景工作,方法是按下 F5 鍵 (或按擊滑鼠右鍵,然後選取桌面上 [裝置和印表機] 視窗中的 [重新整理) ]。 只有在部署應用程式時,才會成功透過服務元數據剖析進行背景工作註冊。
確認已正確註冊背景工作
開發人員可以檢視 Application and Services Logs\Microsoft\Windows\DeviceSetupManager 底下的事件記錄檔,以確認 DSM (DSM) 已正確剖析服務元數據。
開啟 [事件檢視器]。
在 [ 功能表] 索引標籤 上,選取 [ 檢視],然後按兩下 [ 顯示分析和偵錯記錄]。
流覽至 [應用程式和服務記錄]\Microsoft\Windows\DeviceSetupManager。
感興趣的事件包括事件標識碼 220,指出 DSM 已成功註冊 MobileOperatorNotification 事件的背景工作,以及事件標識碼 7900,指出元數據套件中找到的任何錯誤。
確認已成功套用布建元數據
套用布建元數據時,請確認 ProvisionFromXmlDocumentResults.AllElementsProvisioned 為 true。 如果沒有,請檢查 ProvisionResultsXml 以取得錯誤的詳細數據。 常見的行動寬頻錯誤包括:
計算機中的 SIM 卡與布建檔案 (配置檔不符,並ERROR_NOT_FOUND) 失败。
布建檔案中的 CarrierId 與體驗元數據中的服務號碼不符。
確認系統事件代理程式正在執行背景工作
您可以藉由檢查 事件檢視器,確認 Windows 正在產生 MobileOperatorNotification 事件,以及應用程式的背景工作正在由事件代理程序執行。 預設會關閉這些事件的記錄,而且可以透過執行下列步驟來啟用:
開啟 [事件檢視器]。
在 [ 功能表] 索引標籤 上,選取 [ 檢視],然後按兩下 [ 顯示分析和偵錯記錄]。
流覽至 [應用程式和服務記錄]\Microsoft\Windows\BackgroundTaskInfrastructure。
以滑鼠右鍵按兩下 [診斷記錄] ,然後選取 [ 啟用記錄]。
啟用記錄之後,成功執行背景工作會導致事件標識碼 = 1 的事件,其描述如下:「具有進入點<的背景工作實例background_task_namespace_name>。<> background_task_class_name和名稱MobileOperatorNotificationHandler已在會話 1 中建立,並指定識別碼為 {11111111-1111-1111-1111-111111111111}。
如果未執行背景工作,請先確認服務元數據中指定的背景工作名稱符合封裝 AppXManifest.xml 檔案中的名稱。 確認部署應用程式之後,會觸發剖析服務元數據,並插入行動寬頻裝置。
確認 Windows 收到 SMS 和 USSD 通知
您可以在 事件檢視器 中檢查 SmsRouter 事件,以確認 Windows 正在接收 SMS 和 USSD 通知。
在 事件檢視器,在 [應用程式和服務記錄]\Microsoft\Windows \Mobile-Broadband-Experience-SmsRouter\Microsoft-Windows-SMSRouter 下,是「SMSRouter 收到 SMS 操作員通知訊息」和「SMSRouter 已收到簡訊」等專案。 在 [應用程式和服務記錄]\Microsoft\Windows \Mobile-Broadband-Experience-SmsApi\SMSApi 底下,是「應用程式:Microsoft.SDKSamples.SmsSendReceive 在行動寬带裝置 {11111111-1111-1111-1111-111111111111}上傳送 SMS 簡訊:」等專案。
未偵測到接收的SMS訊息為操作員通知
如果未偵測到收到SMS作為操作員通知,請確認帳戶布建元數據中系統管理SMS通知的自定義篩選規則。 如需布建元數據的詳細資訊,請參閱 帳戶布建。
特別是,如果帳戶布建元數據指定寄件者電話號碼,請使用SMS API,確認指定的號碼格式符合所接收訊息中的號碼。 若要確認這是否正確相符,請暫時將模式變更為 [^]\* 以符合來自此寄件者的所有訊息。
範例 backgroundtask.js 檔案
//
// A JavaScript background task runs a specified JavaScript file.
//
(function () {
"use strict";
//
// The background task instance's activation parameters are available via Windows.UI.WebUI.WebUIBackgroundTaskInstance.current.
//
var backgroundTaskInstance = Windows.UI.WebUI.WebUIBackgroundTaskInstance.current,
networkOperatorEventType = Windows.Networking.NetworkOperators.NetworkOperatorEventMessageType,
key = null,
settings = Windows.Storage.ApplicationData.current.localSettings;
try {
var details = backgroundTaskInstance.triggerDetails;
switch (details.notificationType) {
case networkOperatorEventType.gsm:
var textMessage = new Windows.Devices.Sms.SmsTextMessage.fromBinaryMessage(details.smsMessage);
showToast("Gsm Msg From: " + textMessage.from + "; TimeStamp: " + textMessage.timestamp, details.message);
break;
case networkOperatorEventType.cdma:
showToast("Mobile Broadband message", details.message);
break;
case networkOperatorEventType.ussd:
showToast("Mobile Broadband message", details.message);
break;
case networkOperatorEventType.dataPlanThresholdReached:
showToast("Mobile Broadband message", "Data plan threshold reached");
break;
case networkOperatorEventType.dataPlanReset:
showToast("Mobile Broadband message", "Data plan reset");
break;
case networkOperatorEventType.dataPlanDeleted:
showToast("Mobile Broadband message", "Data plan deleted");
break;
case networkOperatorEventType.profileConnected:
showToast("Mobile Broadband message", "Profile connected");
break;
case networkOperatorEventType.profileDisconnected:
showToast("Mobile Broadband message", "Profile disconnected");
break;
case networkOperatorEventType.registeredRoaming:
showToast("Mobile Broadband message", "Registered roaming");
break;
case networkOperatorEventType.registeredHome:
showToast("Mobile Broadband message", "Registered home");
break;
case networkOperatorEventType.tetheringEntitlementCheck:
showToast("Mobile Broadband message", "Entitlement check completed");
break;
default:
showToast("Mobile Broadband message", "Unknown message");
break;
}
taskSucceeded();
}
catch (exception) {
taskFailed();
}
function showToast(title, body) {
var notifications = Windows.UI.Notifications;
var toastNotificationManager = Windows.UI.Notifications.ToastNotificationManager;
var toastXml = toastNotificationManager.getTemplateContent(notifications.ToastTemplateType.toastText02);
//
// Pass to app through eventArguments.arguments.
//
var temp = "\"Title\"" + ":" + "\"" + title + "\"" + "," + "\"Message\"" + ":" + "\"" + body + "\"";
if (temp.length > 251) {
temp = temp.substring(0, 251);
}
toastXml.selectSingleNode("/toast").setAttribute("launch", "'{" + temp + "}'");
var textNodes = toastXml.getElementsByTagName("text");
textNodes[0].appendChild(toastXml.createTextNode(title));
textNodes[1].appendChild(toastXml.createTextNode(body));
var toast = new notifications.ToastNotification(toastXml);
toastNotificationManager.createToastNotifier().show(toast);
}
//
// This function is called when the background task is completed successfully.
//
function taskSucceeded() {
//
// Use the succeeded property to indicate that this background task completed successfully.
//
backgroundTaskInstance.succeeded = true;
backgroundTask.taskInstance.progress = 100;
console.log("Background " + backgroundTask.taskInstance.task.name + " Completed");
//
// Write to localSettings to indicate that this background task completed.
//
key = backgroundTaskInstance.task.taskId.toString();
settings.values[key] = "Completed";
//
// A JavaScript background task must call close when it is done.
//
close();
}
//
// If the task was canceled or failed, stop the background task.
//
function taskFailed() {
console.log("Background " + backgroundTask.taskInstance.task.name + " Failed");
backgroundTaskInstance.succeeded = false;
key = backgroundTaskInstance.task.taskId.toString();
settings.values[key] = "Failed";
close();
}
})();