這很重要
本主題僅適用於 Windows 10 行動裝置版。
本主題描述如何使用主機卡模擬(HCE)直接與近距離通信(NFC)卡片閱讀機通訊,並讓客戶透過手機(而不是實體卡)存取您的服務,而不需要移動網路運營商(MNO)。
開發 HCE 應用程式所需的條件
若要開發 HCE 型卡片模擬應用程式,您必須安裝 Microsoft Visual Studio 2015(請參閱 Visual Studio 下載頁面)(包括 Windows 開發人員工具)和 Windows 10 行動裝置版模擬器。
如需取得設定的詳細資訊,請參閱 使用適用於 Windows 10 行動裝置版的 Microsoft 模擬器測試。
或者,如果您想要使用實際的 Windows 10 行動裝置版裝置進行測試,而不是附帶的 Windows 10 行動裝置版模擬器,您也需要下列物件。
- 具有 NFC HCE 支援的 Windows 10 Mobile 裝置。
- 支援 ISO/IEC 14443-4 和 ISO/IEC 7816-4 通訊協定的讀取器終端機
Windows 10 行動裝置版會實作 HCE 服務,以提供下列功能。
- 應用程式可以針對想要模仿的卡片註冊小程式識別碼(AID)。
- 應用程式通訊協議數據單位(APDU)命令和回應對的衝突解決與路由,根據外部讀取卡的選擇和使用者的偏好,將其分配給其中一個已註冊的應用程式。
- 因使用者動作而處理應用程式的事件和通知。
Windows 10 支援根據 ISO-DEP(ISO-IEC 14443-4)的智慧卡模擬,並使用 ISO-IEC 7816-4 規格中所定義的 APDU 進行通訊。 Windows 10 支援適用於 HCE 應用程式的 ISO/IEC 14443-4 Type A 技術。 類型 B、類型 F 和非ISO-DEP(例如 MIFARE)技術預設會導向至 SIM。
只有 Windows 10 行動裝置版裝置已啟用卡片模擬功能。 其他版本的 Windows 10 無法使用 SIM 型和 HCE 型卡片模擬。
下圖顯示 HCE 和 SIM 卡模擬支援的架構。
應用程式選取和 AID 路由
若要開發 HCE 應用程式,您必須瞭解 Windows 10 行動裝置版裝置如何將 AID 路由傳送至特定應用程式,因為使用者可以安裝多個不同的 HCE 應用程式。 每個應用程式都可以註冊多個 HCE 和 SIM 卡。
當使用者點選其 Windows 10 行動裝置版裝置到終端機時,數據會自動路由傳送到裝置上安裝的適當應用程式。 此路由是以小程式識別碼(AID),即一個由5至16位元組組成的識別碼,為基礎的。 在點選期間,外部終端機會傳送 SELECT 命令的 APDU 以指定 AID,將所有後續的 APDU 命令路由至該 AID。 後續的 SELECT 命令將會再次變更路由。 根據應用程式和用戶設定所註冊的 AID,APDU 流量會被路由到特定應用程式,該應用程式會發送回應 APDU。 請注意,終端機可能會想要在相同的點選期間與數個不同的應用程式通訊。 因此,您必須確保應用程式的背景工作在停用時儘快結束,讓另一個應用程式的背景工作騰出空間以回應APDU。 我們將在本主題稍後討論背景工作。
HCE 應用程式必須將自己註冊到特定的、可以處理的 AID,以便接收相應 AID 的 APDU。 應用程式會使用 AID 群組宣告 AID。 AID 群組在概念上相當於個別實體卡片。 例如,一張信用卡是使用 AID 群組來宣告,而來自不同銀行的第二張信用卡則以不同的第二個 AID 群組來宣告,即使兩者可能具有相同的 AID。
付款 AID 群組的衝突解決方案
當應用程式註冊實體卡片(AID 群組)時,可以將AID群組類別宣告為「付款」或「其他」。雖然在任何指定時間可以註冊多個付款 AID 群組,但一次只能針對 Tap 和 Pay 啟用其中一個付款 AID 群組,用戶選取此群組。 此行為存在,因為使用者期待能夠自主管控地選擇使用某一種付款方式、信用卡或轉帳卡,以確保在將裝置感應到終端機時,不會使用到意外的其他卡片進行付款。
不過,可以同時啟用註冊為「其他」的多個AID群組,而不需要用戶互動。 因為其他類型的卡片,例如會員卡、優惠券或交通卡,預期能在無需任何操作或提醒的情況下,只要他們刷手機就能正常運作,所以會有這種行為。
所有註冊為「付款」的 AID 群組都會出現在 NFC 設定頁面的卡片清單中,用戶可以選取其預設付款卡。 選取預設付款卡時,註冊此付款 AID 群組的應用程式會變成預設付款應用程式。 默認付款應用程式可以啟用或停用其任何 AID 群組,而不需要用戶互動。 如果使用者拒絕預設付款應用程式提示,則目前的預設付款應用程式(如果有的話)會繼續維持為預設值。 下列螢幕快照顯示 [NFC 設定] 頁面。
使用上述範例螢幕快照,如果使用者將預設付款卡變更為 「HCE 應用程式 1」未註冊的另一張卡片,系統就會為使用者的同意建立確認提示。 不過,如果使用者將預設付款卡變更為 「HCE 應用程式 1」所註冊的另一張卡片,系統就不會為使用者建立確認提示,因為 「HCE Application1」 已經是預設付款應用程式。
未付款援助群組的衝突解決
分類為「其他」的非付款卡不會出現在 NFC 設定頁面中。
您的應用程式可以使用與付款 AID 群組相同的方式建立、註冊及啟用非付款 AID 群組。 主要差異在於,針對非付款 AID 群組,模擬類別會設定為 「其他」,而不是「付款」。 向系統註冊 AID 群組之後,您必須讓 AID 群組接收 NFC 流量。 當您嘗試啟用非付款 AID 群組以接收流量時,除非與系統中已由不同應用程式註冊的其中一個 AID 發生衝突,否則不會提示使用者進行確認。 如果發生衝突,系統會提示使用者,告知哪些卡片及其相關聯的應用程式將會被停用,若使用者選擇啟用新註冊的AID群組。
與 SIM 型 NFC 應用程式共存
在 Windows 10 行動裝置版中,系統會設定 NFC 控制器路由表,用來在控制器層進行路由決策。 數據表包含下列專案的路由資訊。
- 個別 AID 路徑。
- 通訊協定型路由(ISO-DEP)。
- 以技術為基礎的路由(NFC-A/B/F)。
當外部讀取器傳送 「SELECT AID」 命令時,NFC 控制器會先檢查路由表中的 AID 路由是否有相符專案。 如果無匹配項,將使用協定路由作為 ISO-DEP(14443-4-A)流量的預設路由。 對於任何其他非ISO-DEP 流量,它會使用以技術為基礎的路由。
Windows 10 行動裝置版會在 NFC 設定頁面中提供功能表選項 「SIM 卡」,以繼續使用舊版 Windows Phone 8.1 SIM 型應用程式,而不會向系統註冊其 AID。 如果使用者選取 [SIM 卡] 作為預設付款卡,則 ISO-DEP 路由會設定為 UICC;對於下拉選單中所有其他選擇,ISO-DEP 路由會傳送至主機。
當裝置第一次使用 Windows 10 Mobile 開機時,對於具備 SE 兼容 SIM 卡的裝置, ISO-DEP 路由會設定為「SIM 卡」模式。 當使用者安裝已啟用 HCE 的應用程式,且該應用程式啟用任何 HCE AID 群組註冊時,會將 ISO-DEP 路由指向主機。 新的 SIM 卡型應用程式需要在 SIM 卡中註冊 AID,才能在控制器路由表中填入特定的 AID 路由。
建立以 HCE 為基礎的應用程式
您的 HCE 應用程式有兩個部分。
- 用戶互動的主要前台應用程式。
- 由系統觸發的背景工作,用於處理指定 AID 的 APDU。
由於載入背景作業以回應 NFC 觸碰的效能需求非常嚴格,因此建議您在 C++/CX 原生碼中實作整個背景作業(包括任何相依項目、參考或程式庫),而不是使用 C# 或受控的程式碼。 雖然 C# 和受控代碼通常執行良好,但有額外負荷,例如載入 .NET CLR,可以透過使用 C++/CX 來避免。
建立和註冊背景任務
您必須在 HCE 應用程式中建立背景任務,以處理和響應由系統路由至該應用程式的 APDU。 第一次啟動您的應用程式時,應用程式的前台會註冊 HCE 背景工作,以實作 IBackgroundTaskRegistration 介面,如下列程式碼所示。
var taskBuilder = new BackgroundTaskBuilder();
taskBuilder.Name = bgTaskName;
taskBuilder.TaskEntryPoint = taskEntryPoint;
taskBuilder.SetTrigger(new SmartCardTrigger(SmartCardTriggerType.EmulatorHostApplicationActivated));
bgTask = taskBuilder.Register();
請注意,任務觸發器已設定為 SmartCardTriggerType。 EmulatorHostApplicationActivated。 這表示,每當 OS 將 SELECT AID 命令 APDU 解析至您的應用程式時,就會啟動您的背景工作。
接收和回應APDU
當有針對您的應用程式的 APDU 時,系統會啟動您的背景工作。 您的背景工作會接收透過 SmartCardEmulatorApduReceivedEventArgs 傳遞的 APDU,並透過 物件的 CommandApdu 屬性,並使用相同物件的 TryRespondAsync 方法回應 APDU。 出於效能考慮,請考慮將背景工作保持在輕量操作的水平。 例如,立即回應APTU,並在所有處理完成時結束背景工作。 由於 NFC 交易的性質,使用者通常只會將裝置靠近讀取器持續非常短的時間。 您的背景任務會繼續接收來自讀取器的請求,直到您的連線被停用為止,這種情況下,您會收到 SmartCardEmulatorConnectionDeactivatedEventArgs 物件。 您的連線可能會被停用,因為在 SmartCardEmulatorConnectionDeactivatedEventArgs.Reason 屬性中所述的下列原因。
- 如果使用 ConnectionLost 值停用連線,這表示使用者已將裝置從讀取器中移除。 如果您的應用程式需要使用者點選到終端機的時間較長,您可以考慮提示他們提供意見反應。 您應該快速終止背景工作(完成延遲),以確保它們是否再次點選,不會延遲等候先前的背景工作結束。
- 如果使用 ConnectionRedirected停用連線,則表示終端機傳送了導向至不同 AID 的新 SELECT AID 命令 APDU。 在此情況下,您的應用程式應該立即結束背景工作(完成延遲),以允許另一個背景工作執行。
背景工作也應該在 IBackgroundTaskInstance 介面註冊 Canceled 事件,並同樣快速地結束背景工作(藉由完成延遲),因為當系統完成背景工作時會引發此事件。 以下是示範 HCE 應用程式背景工作的程序代碼。
void BgTask::Run(
IBackgroundTaskInstance^ taskInstance)
{
m_triggerDetails = static_cast<SmartCardTriggerDetails^>(taskInstance->TriggerDetails);
if (m_triggerDetails == nullptr)
{
// May be not a smart card event that triggered us
return;
}
m_emulator = m_triggerDetails->Emulator;
m_taskInstance = taskInstance;
switch (m_triggerDetails->TriggerType)
{
case SmartCardTriggerType::EmulatorHostApplicationActivated:
HandleHceActivation();
break;
case SmartCardTriggerType::EmulatorAppletIdGroupRegistrationChanged:
HandleRegistrationChange();
break;
default:
break;
}
}
void BgTask::HandleHceActivation()
{
try
{
auto lock = m_srwLock.LockShared();
// Take a deferral to keep this background task alive even after this "Run" method returns
// You must complete this deferral immediately after you have done processing the current transaction
m_deferral = m_taskInstance->GetDeferral();
DebugLog(L"*** HCE Activation Background Task Started ***");
// Set up a handler for if the background task is cancelled, we must immediately complete our deferral
m_taskInstance->Canceled += ref new Windows::ApplicationModel::Background::BackgroundTaskCanceledEventHandler(
[this](
IBackgroundTaskInstance^ sender,
BackgroundTaskCancellationReason reason)
{
DebugLog(L"Cancelled");
DebugLog(reason.ToString()->Data());
EndTask();
});
if (Windows::Phone::System::SystemProtection::ScreenLocked)
{
auto denyIfLocked = Windows::Storage::ApplicationData::Current->RoamingSettings->Values->Lookup("DenyIfPhoneLocked");
if (denyIfLocked != nullptr && (bool)denyIfLocked == true)
{
// The phone is locked, and our current user setting is to deny transactions while locked so let the user know
// Denied
DoLaunch(Denied, L"Phone was locked at the time of tap");
// We still need to respond to APDUs in a timely manner, even though we will just return failure
m_fDenyTransactions = true;
}
}
else
{
m_fDenyTransactions = false;
}
m_emulator->ApduReceived += ref new TypedEventHandler<SmartCardEmulator^, SmartCardEmulatorApduReceivedEventArgs^>(
this, &BgTask::ApduReceived);
m_emulator->ConnectionDeactivated += ref new TypedEventHandler<SmartCardEmulator^, SmartCardEmulatorConnectionDeactivatedEventArgs^>(
[this](
SmartCardEmulator^ emulator,
SmartCardEmulatorConnectionDeactivatedEventArgs^ eventArgs)
{
DebugLog(L"Connection deactivated");
EndTask();
});
m_emulator->Start();
DebugLog(L"Emulator started");
}
catch (Exception^ e)
{
DebugLog(("Exception in Run: " + e->ToString())->Data());
EndTask();
}
}
建立和註冊 AID 群組
在應用程式的第一次啟動,卡片配置時,會使用系統建立並註冊 AID 群組。 系統根據已註冊的 AID 和使用者設定,判斷外部讀取器想要與之通訊的應用程式,並以此路由傳送 APDU。
大部分的付款卡都會註冊相同的 AID、鄰近付款系統環境 (PPSE),以及額外的付款網路卡特定 AID。 每個 AID 群組都代表卡片,當使用者啟用卡片時,群組中的所有 AI 都會啟用。 同樣地,當使用者停用卡片時,群組中的所有AID都會停用。
若要註冊 AID 群組,您必須建立 SmartCardAppletIdGroup 物件,並設定其屬性以反映這是以 HCE 為基礎的付款卡。 您的顯示名稱應該對使用者有描述性,因為它會顯示在 NFC 設定功能表中,以及使用者提示。 針對 HCE 付款卡, SmartCardEmulationCategory 屬性應設定為 Payment , 且 SmartCardEmulationType 屬性應設定為 Host。
public static byte[] AID_PPSE =
{
// File name "2PAY.SYS.DDF01" (14 bytes)
(byte)'2', (byte)'P', (byte)'A', (byte)'Y',
(byte)'.', (byte)'S', (byte)'Y', (byte)'S',
(byte)'.', (byte)'D', (byte)'D', (byte)'F', (byte)'0', (byte)'1'
};
var appletIdGroup = new SmartCardAppletIdGroup(
"Example DisplayName",
new List<IBuffer> {AID_PPSE.AsBuffer()},
SmartCardEmulationCategory.Payment,
SmartCardEmulationType.Host);
針對非支付用途的 HCE 卡,SmartCardEmulationCategory 属性應設定為 Other,且 SmartCardEmulationType 属性應設定為 Host。
public static byte[] AID_OTHER =
{
(byte)'1', (byte)'2', (byte)'3', (byte)'4',
(byte)'5', (byte)'6', (byte)'7', (byte)'8',
(byte)'O', (byte)'T', (byte)'H', (byte)'E', (byte)'R'
};
var appletIdGroup = new SmartCardAppletIdGroup(
"Example DisplayName",
new List<IBuffer> {AID_OTHER.AsBuffer()},
SmartCardEmulationCategory.Other,
SmartCardEmulationType.Host);
每個 AID 群組最多可以包含 9 個 AID(長度為 5-16 個字節)。
使用 RegisterAppletIdGroupAsync 方法向系統註冊您的 AID 群組,這會傳回 SmartCardAppletIdGroupRegistration 物件。 根據預設,註冊物件的 ActivationPolicy 屬性會設定為 Disabled。 這表示即使您的 AID 已向系統註冊,但尚未啟用它們,而且不會接收流量。
reg = await SmartCardEmulator.RegisterAppletIdGroupAsync(appletIdGroup);
您可以使用SmartCardAppletIdGroupRegistration 類別的 RequestActivationPolicyChangeAsync 方法來啟用已註冊的卡片 (AID 群組),如下所示。 因為系統一次只能啟用單一付款卡,因此將付款 AID 群組的 ActivationPolicy 設定為 Enabled ,與設定預設付款卡相同。 無論是否已選取預設付款卡,都會提示用戶允許此卡片作為預設付款卡。 如果您的應用程式已經是預設付款應用程式,而且只是在它自己的AID群組之間變更,則此陳述不是真的。 每個應用程式最多可以註冊 10 個 AID 群組。
reg.RequestActivationPolicyChangeAsync(AppletIdGroupActivationPolicy.Enabled);
您可以使用 OS 查詢應用程式的已註冊 AID 群組,並使用 GetAppletIdGroupRegistrationsAsync 方法來檢查其啟用原則。
當您將付款卡的啟用原則從 [停用 ] 變更為 [已啟用] 時,系統才會提示使用者,只有當您的應用程式還不是預設付款應用程式時。 只有在發生 AID 衝突時,才會提示使用者將非付款卡的啟用原則從 Disabled 變更為 Enabled。
var registrations = await SmartCardEmulator.GetAppletIdGroupRegistrationsAsync();
foreach (var registration in registrations)
{
registration.RequestActivationPolicyChangeAsync (AppletIdGroupActivationPolicy.Enabled);
}
啟用原則變更時的事件通知
在您的背景工作中,您可以註冊以接收事件,當應用程式外部之其中一個AID群組註冊的啟用原則發生變更時。 例如,使用者可能會透過NFC 設定功能表,將預設付款應用程式從其中一張卡片變更為另一個應用程式裝載的另一張卡片。 如果您的應用程式需要知道此變更,例如更新動態磚等內部設定,您可以接收此變更的事件通知,並據以採取動作。
var taskBuilder = new BackgroundTaskBuilder();
taskBuilder.Name = bgTaskName;
taskBuilder.TaskEntryPoint = taskEntryPoint;
taskBuilder.SetTrigger(new SmartCardTrigger(SmartCardTriggerType.EmulatorAppletIdGroupRegistrationChanged));
bgTask = taskBuilder.Register();
前景覆寫行為
您可以將任何 AID 群組註冊的 ActivationPolicy 變更為 ForegroundOverride,而您的應用程式位於前景,而不提示使用者。 當使用者在應用程式處於前景時,將裝置靠近終端機,即使使用者沒有選擇您的任何付款卡作為默認付款卡,資料流仍然會被路由到您的應用程式。 當您將卡片的啟用原則變更為 ForegroundOverride時,此變更只會是暫時性的,直到您的應用程式離開前景,且不會變更用戶設定的目前的預設付款卡。 您可以從前景應用程式變更您的付款或非付款卡的 激活策略,如下所示。 請注意,RequestActivationPolicyChangeAsync 方法只能從前景應用程式呼叫,而且無法從背景工作呼叫。
reg.RequestActivationPolicyChangeAsync(AppletIdGroupActivationPolicy.ForegroundOverride);
此外,您可以註冊包含單一 0 長度 AID 的 AID 群組,這會導致系統路由傳送所有 APDU,而不論 AID 為何,即使是 SELECT AID 命令接收之前發送的任何命令 APDU 也會被路由。 不過,這類 AID 群組只能在您的應用程式處於前景時運作,因為它只能設定為 ForegroundOverride 且無法永久啟用。 此外,此機制也適用於 主機 和 UICC 的 SmartCardEmulationType 列舉數值,以便將所有流量路由到 HCE 背景工作或 SIM 卡。
public static byte[] AID_Foreground =
{};
var appletIdGroup = new SmartCardAppletIdGroup(
"Example DisplayName",
new List<IBuffer> {AID_Foreground.AsBuffer()},
SmartCardEmulationCategory.Other,
SmartCardEmulationType.Host);
reg = await SmartCardEmulator.RegisterAppletIdGroupAsync(appletIdGroup);
reg.RequestActivationPolicyChangeAsync(AppletIdGroupActivationPolicy.ForegroundOverride);
檢查 NFC 和 HCE 支援
您的應用程式應該先檢查裝置是否有 NFC 硬體、支援卡片模擬功能,以及支援主機卡模擬,再向使用者提供這類功能。
NFC 智慧卡模擬功能只在 Windows 10 行動裝置版上啟用,因此嘗試在任何其他版本的 Windows 10 中使用智慧卡模擬器 API 將會導致錯誤。 您可以在下列代碼段中檢查智慧卡 API 支援。
Windows.Foundation.Metadata.ApiInformation.IsTypePresent("Windows.Devices.SmartCards.SmartCardEmulator");
您也可以檢查裝置是否有 NFC 硬體能夠進行某種形式的卡片模擬,方法是檢查 SmartCardEmulator.GetDefaultAsync 方法是否傳回 Null。 如果這樣做,則裝置上不支援 NFC 卡模擬。
var smartcardemulator = await SmartCardEmulator.GetDefaultAsync();<
HCE 和 AID 型 UICC 路由的支援僅適用於最近啟動的裝置,例如 Lumia 730、830、640 和 640 XL。 任何執行 Windows 10 行動裝置版及更新版本的新 NFC 功能裝置都應該支援 HCE。 您的應用程式可以檢查 HCE 支援,如下所示。
Smartcardemulator.IsHostCardEmulationSupported();
螢幕鎖定及螢幕關閉行為
Windows 10 行動裝置版具有裝置層級卡片模擬設定,可由電信業者或裝置製造商設定。 根據預設,除非MO或OEM覆寫這些值,否則[點擊支付]切換已停用,且[裝置層級啟用政策]會設定為“始終”。
您的應用程式可以在裝置層級查詢 EnablementPolicy 的值,然後根據應用程式在每個狀態下所需的行為,針對每個案例採取相應的行動。
SmartCardEmulator emulator = await SmartCardEmulator.GetDefaultAsync();
switch (emulator.EnablementPolicy)
{
case Never:
// you can take the user to the NFC settings to turn "tap and pay" on
await Windows.System.Launcher.LaunchUriAsync(new Uri("ms-settings-nfctransactions:"));
break;
case Always:
return "Card emulation always on";
case ScreenOn:
return "Card emulation on only when screen is on";
case ScreenUnlocked:
return "Card emulation on only when screen unlocked";
}
即使手機已鎖定和/或螢幕關閉,只要外部讀取器選取一個解析至您的應用程式的 AID,您的應用程式的背景工作就會啟動。 您可以在背景任務中回應讀者的命令,但如果您需要使用者的任何輸入或想要顯示訊息給使用者,您可以使用一些參數來啟動前景應用程式。 您的背景執行緒可以具有以下行為來啟動您的前景應用程式。
- 在裝置鎖定畫面下(使用者只有在解除鎖定裝置之後,才會看到前景應用程式)
- 在裝置鎖定畫面上方(使用者關閉您的應用程式之後,裝置仍處於鎖定狀態)
if (Windows::Phone::System::SystemProtection::ScreenLocked)
{
// Launch above the lock with some arguments
var result = await eventDetails.TryLaunchSelfAsync("app-specific arguments", SmartCardLaunchBehavior.AboveLock);
}
SIM 卡型應用程式的 AID 註冊和其他更新
使用 SIM 卡模擬應用程式作為安全元素,可以向 Windows 服務註冊,以宣告 SIM 卡上支援的 AID。 此註冊與 HCE 型應用程式註冊非常類似。 唯一的差異在於 SmartCardEmulationType,它應該設定為基於 SIM 的應用程式的 Uicc。 由於付款卡註冊的結果,卡片的顯示名稱也會填入NFC 設定功能表中。
var appletIdGroup = new SmartCardAppletIdGroup(
"Example DisplayName",
new List<IBuffer> {AID_PPSE.AsBuffer()},
SmartCardEmulationCategory.Payment,
SmartCardEmulationType.Uicc);