一、簡介
- NFC(Near Field Communication,近距離無線通信技術) 是一種非接觸式識別和互聯技術,讓移動設備、消費類電子產品、PC 和智能設備之間可以進行近距離無線通信。
- HarmonyOS 的 NFC 提供的功能有:
-
- NFC 基礎查詢:在進行 NFC 功能開發之前,開發者應該先確認設備是否支持 NFC 功能、NFC 是否打開等基本信息。
-
- 訪問安全單元(Secure Element,簡稱為 SE):SE 可用于保存重要信息,應用可以訪問指定 SE,并發送數據到 SE 上。
-
- 卡模擬:設備可以模擬卡片,替代卡片完成對應操作,如模擬門禁卡、公交卡等。
-
- NFC 消息通知:通過這個模塊,開發者可以獲取 NFC 開關狀態改變的消息以及 NFC 的場強消息。
二、NFC 基礎查詢
- 要進行 NFC 功能開發,需要設備支持 NFC 功能。
- 開發者可以通過 NfcController 類的方法 isNfcAvailable() 來確認設備是否支持 NFC 功能。如果設備支持 NFC 功能,可通過 isNfcOpen() 來查詢 NFC 的開關狀態。
- 示例代碼如下:
// 查詢本機是否支持NFCif (context != null) {NfcController nfcController = NfcController.getInstance(context);} else {return;}boolean isAvailable = nfcController.isNfcAvailable();if (isAvailable) {// 調用查詢NFC是否打開接口,返回值為NFC是否是打開的狀態boolean isOpen = nfcController.isNfcOpen();}
三、訪問安全單元
① 應用場景
- 安全單元(Secure Element,簡稱為 SE)可用于保存重要信息,應用或者其他模塊可以通過接口完成以下功能:
-
-
-
-
-
- 發送 APDU(Application Protocol Data Unit)數據到安全單元上。
② API 說明
類名接口名功能描述
SEServiceSEService()創建一個安全單元服務的實例
isConnected()查詢安全單元服務是否已連接
shutdown()關閉安全單元服務
getReaders()獲取全部安全單元
getVersion()獲得安全單元服務的版本
OnCallback用于回調的內部類,用于定義回調接口。
在服務連接成功后,回調該接口通知應用
ReadergetName()獲取安全單元的名稱
isSecureElementPresent()檢查安全單元是否在位
openSession()打開當前安全單元上的session
closeSession()關閉當前安全單元上的所有session
SessionopenBasicChannel(Aid aid)打開基礎通道
openLogicalChannel(Aid aid)創建邏輯通道
getATR()獲得重設安全單元指令的響應
closeSessionChannels()關閉當前session的所有通道
ChannelisClosed()判斷通道是否關閉
isBasicChannel()判斷是否是基礎通道
transmit(byte[] command)發送指令到安全單元
getSelectResponse()獲得應用程序選擇指令的響應
closeChannel()關閉通道
AidAid(byte[] aid, int offset, int length)構造一個AID類的實例
isAidValid()查詢AID是否有效
getAidBytes()獲取AID的字節數組形式的值
③ 使用流程
- 調用 SEService 類的構造函數,創建一個安全單元服務的實例,用于訪問安全單元。
- 調用 isConnected() 接口,查詢安全單元服務的連接狀態。
- 調用 getReaders() 接口,獲取本機的全部安全單元。
- 調用 Reader 類的 openSession() 接口打開 Session,返回一個打開的 Session 實例。
- 調用 Session 類的 openBasicChannel(Aid aid) 接口打開基礎通道,或者調用 openLogicalChannel(Aid aid) 接口打開邏輯通道,返回一個打開通道 Channel 實例。
- 調用 Channel 類的 transmit(byte[] command),發送 APDU 到安全單元。
- 調用 Channel 類的 closeChannel() 接口關閉通道。
- 調用 Session 類的 closeSessionChannels() 接口關閉 Session 的所有通道。
- 調用 Reader 類的 closeSessions() 接口關閉安全單元的所有 Session。
- 調用 SEService 類的 shutdown() 接口關閉安全單元服務。
private static final String ESE = "eSE";private class AppServiceConnectedCallback implements SEService.OnCallback {@Overridepublic void serviceConnected() {// 應用自實現}}// 創建安全單元服務實例SEService sEService = new SEService(context, new AppServiceConnectedCallback());// 查詢安全單元服務的連接狀態boolean isConnected = sEService.isConnected();// 獲取本機的全部安全單元,并獲取指定的安全單元eSEReader[] elements = sEService.getReaders();Reader eSe = null;for (int i = 0; i < elements.length; i++) {if (ESE.equals(elements[i].getName())) {eSe = elements[i];break;}}if (eSe == null) {return;}// 查詢安全單元是否在位boolean isPresent = eSe.isSecureElementPresent();// 打開SessionOptional
<Session> optionalSession = eSe.openSession();Session session = optionalSession.orElse(null);if (session == null) {return;}// 打開通道if (eSe != null) {byte[] aidValue = new byte[]{(byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05};// 創建Aid實例Aid aid = new Aid(aidValue, 0, aidValue.length); // 打開基礎通道Optional
<Channel> optionalChannel = session.openBasicChannel(aid);Channel basicChannel = optionalChannel.orElse(null);// 打開邏輯通道optionalChannel = session.openLogicalChannel(aid);Channel logicalChannel = optionalChannel.orElse(null);// 發送指令給安全單元,返回值為安全單元對指令的響應byte[] resp = logicalChannel.transmit(new byte[]{(byte)0x00, (byte)0xa4, (byte)0x00, (byte)0x00, (byte)0x02, (byte)0x00, (byte)0x00});// 關閉通道資源if (basicChannel.isPresent()) {basicChannel.closeChannel();}if (logicalChannel.isPresent()) {logicalChannel.closeChannel();}// 關閉Session資源session.close();// 關閉安全單元資源eSe.closeSessions();// 關閉安全單元服務資源sEService.shutdown();
四、卡模擬功能
① 應用場景
- 設備可以模擬卡片,替代卡片完成對應操作,如模擬門禁卡、公交卡等。
- 應用或者其他模塊可以通過接口完成以下功能:
-
- 查詢是否支持指定安全單元的卡模擬功能,安全單元包括 HCE(Host Card Emulation)、ESE(Embedded Secure Element)和 SIM(Subscriber Identity Module)卡。
-
- 打開或關閉指定技術類型的卡模擬,并查詢卡模擬狀態。
-
- 獲取 NFC 信息,包括當前激活的安全單元、Hisee 上電狀態、是否支持RSSI(Received Signal Strength Indication)查詢等。
-
- 根據 NFC 服務的類型獲取刷卡時選擇服務的方式,包括支付(Payment)類型和非支付(Other)類型。
-
-
- NFC 應用的 AID(Application Identifier,應用標識)相關操作,包括注冊和刪除應用的 AID、查詢應用是否是指定 AID 的默認應用、獲取應用的 AID 等。
-
- 定義 Host 和 OffHost 服務的抽象類,應用可以通過繼承抽象類來實現 NFC 卡模擬功能。
② API 說明
- NFC 卡模擬功能的主要接口說明如下,在使用對應的接口前,需要申請 ohos.permission.NFC_CARD_EMULATION 權限。
- NFC 卡模擬功能的主要接口如下表所示:
類名接口名功能描述
CardEmulationgetInstance(NfcController controller)創建一個卡模擬類的實例
isSupported(int feature)查詢是否支持卡模擬功能
setListenMode(int mode)設置卡模擬模式
isListenModeEnabled()查詢卡模擬功能是否打開
getNfcInfo(String key)獲取NFC的信息
getSelectionType(String category)根據NFC服務的類型獲取刷卡時選擇服務的方式
registerForegroundPreferred(Ability appAbility, ElementName appName)動態設置前臺優先應用
unregisterForegroundPreferred(Ability appAbility)取消設置前臺優先應用
isDefaultForAid(ElementName appName, String aid)判斷應用是否是指定AID的默認處理應用
registerAids(ElementName appName, String type, List aids)給應用注冊指定類型的AID
removeAids(ElementName appName, String type)刪除應用的指定類型的AID
getAids(ElementName appName, String type)獲取應用中指定類型的AID列表
HostServicesendResponse(byte[] response)發送響應的數據到對端設備
handleRemoteCommand(byte[] cmd, IntentParams params)處理對端設備發送的命令
disabledCallback(int errCode)連接異常的回調
③ 查詢是否支持卡模擬功能
- 調用 NfcController 類的 getInstance(Context context) 接口,獲取 NfcController 實例。
- 調用 CardEmulation 類的 getInstance(NfcController controller) 接口,獲取 CardEmulation 實例,去管理本機卡模擬模塊操作。
- 調用 isSupported(int feature) 接口去查詢是否支持 HCE、UICC、ESE 卡模擬。
// 獲取NFC控制對象NfcController nfcController = NfcController.getInstance(context);// 獲取卡模擬控制對象CardEmulation cardEmulation = CardEmulation.getInstance(nfcController);// 查詢是否支持HCE、UICC、ESE卡模擬,返回值表示是否支持對應安全單元的卡模擬boolean isSupportedHce = cardEmulation.isSupported(CardEmulation.FEATURE_HCE);boolean isSupportedUicc = cardEmulation.isSupported(CardEmulation.FEATURE_UICC);boolean isSupportedEse = cardEmulation.isSupported(CardEmulation.FEATURE_ESE);
④ 開關卡模擬及查詢卡模擬狀態
- 調用 NfcController 類的 getInstance(Context context) 接口,獲取 NfcController 實例。
- 調用 CardEmulation 類的 getInstance(NfcController controller) 接口,獲取 CardEmulation 實例,去管理本機卡模擬模塊操作。
- 調用 setListenMode(int mode) 接口去打開或者關閉卡模擬。
- 調用 isListenModeEnabled() 接口去查詢卡模擬是否打開。
// 獲取NFC控制對象NfcController nfcController = NfcController.getInstance(context);// 獲取卡模擬控制對象CardEmulation cardEmulation = CardEmulation.getInstance(nfcController);// 打開卡模擬cardEmulation.setListenMode(CardEmulation.ENABLE_MODE_ALL);// 調用查詢卡模擬開關狀態的接口,返回值為卡模擬是否是打開的狀態boolean isEnabled = cardEmulation.isListenModeEnabled(); // 關閉卡模擬cardEmulation.setListenMode(CardEmulation.DISABLE_MODE_A_B);// 調用查詢卡模擬開關狀態的接口,返回值為卡模擬是否是打開的狀態isEnabled = cardEmulation.isListenModeEnabled();
⑤ 獲取 NFC 信息
- 調用 NfcController 類的 getInstance(Context context) 接口,獲取 NfcController 實例。
- 調用 CardEmulation 類的 getInstance(NfcController controller) 接口,獲取 CardEmulation 實例,去管理本機卡模擬模塊操作。
- 調用 getNfcInfo(String key) 接口去獲取 NFC 信息。
// 獲取NFC控制對象NfcController nfcController = NfcController.getInstance(context);// 獲取卡模擬控制對象CardEmulation cardEmulation = CardEmulation.getInstance(nfcController);// 查詢本機當前使能的安全單元類型String seType = cardEmulation.getNfcInfo(CardEmulation.KEY_ENABLED_SE_TYPE); // ENABLED_SE_TYPE_ESE// 查詢Hisee上電狀態String hiseeState = cardEmulation.getNfcInfo(CardEmulation.KEY_HISEE_READY);// 查詢是否支持RSSI的查詢String rssiAbility = cardEmulation.getNfcInfo(CardEmulation.KEY_RSSI_SUPPORTED);
⑥ 根據 NFC 服務的類型獲取刷卡時選擇服務的方式
- 調用 NfcController 類的 getInstance(Context context) 接口,獲取 NfcController 實例。
- 調用 CardEmulation 類的 getInstance(NfcController controller) 接口,獲取 CardEmulation 實例,去管理本機卡模擬模塊操作。
- 調用 getSelectionType(Sring category) 接口去獲取選擇服務的方式。
// 獲取NFC控制對象NfcController nfcController = NfcController.getInstance(context);// 獲取卡模擬控制對象CardEmulation cardEmulation = CardEmulation.getInstance(nfcController);// 獲取選擇服務的方式int result = cardEmulation.getSelectionType(CardEmulation.CATEGORY_PAYMENT); // SELECTION_TYPE_PREFER_DEFAULTresult = cardEmulation.getSelectionType(CardEmulation.CATEGORY_OTHER); // SELECTION_TYPE_ASK_IF_CONFLICT
⑦ 動態設置和注銷前臺優先應用
- 調用 NfcController 類的 getInstance(Context context) 接口,獲取 NfcController 實例。
- 調用 CardEmulation 類的 getInstance(NfcController controller) 接口,獲取 CardEmulation 實例,去管理本機卡模擬模塊操作。
- 調用 registerForegroundPreferred(Ability appAbility, ElementName appName) 接口去動態設置前臺優先應用。
- 調用 unregisterForegroundPreferred(Ability appAbility) 接口去取消設置前臺優先應用。
// 獲取NFC控制對象NfcController nfcController = NfcController.getInstance(context);// 獲取卡模擬控制對象CardEmulation cardEmulation = CardEmulation.getInstance(nfcController);// 動態設置前臺優先應用Ability ability = new Ability();cardEmulation.registerForegroundPreferred(ability, new ElementName());// 注銷前臺優先應用cardEmulation.unregisterForegroundPreferred(ability);
⑧
五、NFC 消息通知
① 應用場景
- NFC 消息通知是 HarmonyOS 內部或者與應用之間跨進程通訊的機制,注冊者在注冊消息通知后,一旦符合條件的消息被發出,注冊者即可接收到該消息。
② API 說明
描述通知名附加參數
| NFC狀態 | usual.event.nfc.action.ADAPTER_STATE_CHANGED | extra_nfc_state |
| 進場消息 | usual.event.nfc.action.RF_FIELD_ON_DETECTED | extra_nfc_transaction |
| 離場消息 | usual.event.nfc.action.RF_FIELD_OFF_DETECTED | - |
③ 注冊并獲取 NFC 狀態改變消息
- 構建消息通知接收者 NfcStateEventSubscriber。
- 注冊 NFC 狀態改變消息。
- NfcStateEventSubscriber 接收并處理 NFC 狀態改變消息。
// 構建消息接收者/注冊者class NfcStateEventSubscriber extends CommonEventSubscriber {NfcStateEventSubscriber (CommonEventSubscribeInfo info) {super(info);}@Overridepublic void onReceiveEvent(CommonEventData commonEventData) {if (commonEventData == null || commonEventData.getIntent() == null) {return;}if (NfcController.STATE_CHANGED.equals(commonEventData.getIntent().getAction())) {IntentParams params = commonEventData.getIntent().getParams();int currState = commonEventData.getIntent().getIntParam(NfcController.EXTRA_NFC_STATE, NfcController.STATE_OFF);}}}// 注冊消息MatchingSkills matchingSkills = new MatchingSkills();// 增加獲取NFC狀態改變消息matchingSkills.addEvent(NfcController.STATE_CHANGED);matchingSkills.addEvent(CommonEventSupport.COMMON_EVENT_NFC_ACTION_ADAPTER_STATE_CHANGED);CommonEventSubscribeInfo subscribeInfo = new CommonEventSubscribeInfo(matchingSkills);NfcStateEventSubscriber subscriber = new NfcStateEventSubscriber(subscribeInfo);try {CommonEventManager.subscribeCommonEvent(subscriber);} catch (RemoteException e) {HiLog.error(TAG, "doSubscribe occur exception: %{public}s" ,e.toString());}
④ 注冊并獲取 NFC 場強消息
- 構建消息通知接收者 NfcFieldOnAndOffEventSubscriber。
- 注冊 NFC 場強消息。
- NfcFieldOnAndOffEventSubscriber 接收并處理 NFC 場強消息。
// 構建消息接收者/注冊者class NfcFieldOnAndOffEventSubscriber extends CommonEventSubscriber {NfcFieldOnAndOffEventSubscriber (CommonEventSubscribeInfo info) {super(info);}@Overridepublic void onReceiveEvent(CommonEventData commonEventData) {if (commonEventData == null || commonEventData.getIntent() == null) {return;}if (NfcController.FIELD_ON_DETECTED.equals(commonEventData.getIntent().getAction())) {IntentParams params = commonEventData.getIntent().getParams();if (params == null) {HiLog.info(TAG, "Pure FIELD_ON_DETECTED");} else {HiLog.info(TAG, "Transaction FIELD_ON_DETECTED"); Intent transactionIntent = (Intent) params.getParam("transactionIntent");}} else if (NfcController.FIELD_OFF_DETECTED.equals(commonEventData.getIntent().getAction())) {HiLog.info(TAG, "FIELD_OFF_DETECTED");}HiLog.info(TAG, "NfcFieldOnAndOffEventSubscriber onReceiveEvent: %{public}s", commonEventData.getIntent().getAction());}}// 注冊消息MatchingSkills matchingSkills = new MatchingSkills();// 增加獲取NFC狀態改變消息matchingSkills.addEvent(NfcController.FIELD_ON_DETECTED);matchingSkills.addEvent(NfcController.FIELD_OFF_DETECTED);CommonEventSubscribeInfo subscribeInfo = new CommonEventSubscribeInfo(matchingSkills);HiLog.info(TAG, "subscribeInfo permission: %{public}s", subscribeInfo.getPermission());NfcFieldOnAndOffEventSubscriber subscriber = new NfcFieldOnAndOffEventSubscriber(subscribeInfo);try {CommonEventManager.subscribeCommonEvent(subscriber);} catch (RemoteException e) {HiLog.error(TAG, "doSubscribe occur exception: %{public}s", e.toString());}
總結
以上是生活随笔為你收集整理的HarmonyOS之深入解析NFC的功能和使用的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。