HarmonyOS Learning Road 개발 - 네트워크 및 연결(NFC Development 2)

카드 에뮬레이션 기능

장면 소개

이 장치는 카드를 시뮬레이션하여 카드를 교체하여 액세스 제어 카드, 버스 카드 등 시뮬레이션과 같은 해당 작업을 완료할 수 있습니다. 애플리케이션 또는 기타 모듈은 인터페이스를 통해 다음 기능을 완료할 수 있습니다.

  1. 지정된 보안 장치의 카드 에뮬레이션 기능 지원 여부를 쿼리합니다. 보안 장치에는 HCE(Host Card Emulation), ESE(Embedded Secure Element) 및 SIM(Subscriber Identity Module) 카드가 포함됩니다.
  2. 지정된 기술 유형의 카드 에뮬레이션을 켜거나 끄고 카드 에뮬레이션 상태를 쿼리합니다.
  3. 현재 활성화된 보안 장치, Hisee 전원 켜짐 상태, RSSI(Received Signal Strength Indication) 쿼리 지원 여부 등 NFC 정보를 얻습니다.
  4. NFC 서비스의 종류에 따라 결제(Payment) 유형과 미결제(Other) 유형으로 카드를 스와이프할 때 서비스를 선택하는 방법을 얻습니다.
  5. 전경 우선 앱을 동적으로 설정하고 로그아웃합니다.
  6. 애플리케이션 AID 등록 및 삭제, 애플리케이션이 지정된 AID의 기본 애플리케이션인지 여부 조회, 애플리케이션의 AID 획득 등 NFC 애플리케이션의 AID(Application Identifier, 애플리케이션 식별) 관련 작업
  7. Host 및 OffHost 서비스의 추상 클래스를 정의하고 응용 프로그램은 추상 클래스를 상속하여 NFC 카드 시뮬레이션 기능을 구현할 수 있습니다.

인터페이스 설명

NFC 카드 에뮬레이션 기능의 주요 인터페이스를 설명하면 해당 인터페이스를 사용하기 전에 ohos.permission.NFC_CARD_EMULATION 권한을 신청해야 합니다.

표 1  NFC 카드 시뮬레이션 기능의 주요 인터페이스

클래스 이름

인터페이스 이름

기능 설명

카드에뮬레이션

getInstance(NfcController 컨트롤러)

카드 시뮬레이션 클래스의 인스턴스를 만듭니다.

isSupported(정수 기능)

카드 에뮬레이션 기능이 지원되는지 쿼리합니다.

setListenMode(정수 모드)

카드 에뮬레이션 모드를 설정합니다.

isListenModeEnabled()

카드 에뮬레이션 기능이 활성화되어 있는지 쿼리합니다.

getNfcInfo(문자열 키)

NFC 정보를 가져옵니다.

getSelectionType(문자열 카테고리)

NFC 서비스의 종류에 따라 카드를 스와이프할 때 서비스를 선택하는 방법을 습득합니다.

registerForegroundPreferred(능력 appAbility, ElementName appName)

포그라운드 우선순위 애플리케이션을 동적으로 설정합니다.

unregisterForegroundPreferred(능력 appAbility)

포그라운드 우선 앱을 설정 해제합니다.

isDefaultForAid(ElementName appName, String aid)

애플리케이션이 지정된 AID에 대한 기본 처리 애플리케이션인지 여부를 판별하십시오.

registerAids(ElementName appName, String type, List<String> aids)

애플리케이션에 지정된 유형의 AID를 등록합니다.

removeAids(ElementName appName, 문자열 유형)

애플리케이션에서 지정된 유형의 AID를 삭제합니다.

getAids(ElementName appName, 문자열 유형)

애플리케이션에서 지정된 유형의 AID 목록을 가져옵니다.

호스트 서비스

sendResponse(바이트[] 응답)

피어 장치에 응답 데이터를 보냅니다.

handleRemoteCommand(byte[] cmd, IntentParams params)

피어 장치에서 보낸 명령을 처리합니다.

disabledCallback(int errCode)

연결 예외에 대한 콜백.

카드 에뮬레이션 기능 지원 여부 쿼리

  1. NfcController 인스턴스를 얻기 위해 NfcController 클래스의 getInstance(Context context) 인터페이스를 호출합니다.
  2. CardEmulation 클래스의 getInstance(NfcController 컨트롤러) 인터페이스를 호출하여 로컬 카드 시뮬레이션 모듈의 작업을 관리하기 위한 CardEmulation 인스턴스를 가져옵니다.
  3. 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);

스위치 카드 시뮬레이션 및 쿼리 카드 시뮬레이션 상태

  1. NfcController 인스턴스를 얻기 위해 NfcController 클래스의 getInstance(Context context) 인터페이스를 호출합니다.
  2. CardEmulation 클래스의 getInstance(NfcController 컨트롤러) 인터페이스를 호출하여 로컬 카드 시뮬레이션 모듈의 작업을 관리하기 위한 CardEmulation 인스턴스를 가져옵니다.
  3. setListenMode(int mode) 인터페이스를 호출하여 카드 에뮬레이션을 활성화 또는 비활성화합니다.
  4. 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 정보 얻기

  1. NfcController 인스턴스를 얻기 위해 NfcController 클래스의 getInstance(Context context) 인터페이스를 호출합니다.
  2. CardEmulation 클래스의 getInstance(NfcController 컨트롤러) 인터페이스를 호출하여 로컬 카드 시뮬레이션 모듈의 작업을 관리하기 위한 CardEmulation 인스턴스를 가져옵니다.
  3. 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 서비스의 종류에 따라 카드를 스와이프할 때 서비스를 선택하는 방법을 얻습니다.

  1. NfcController 인스턴스를 얻기 위해 NfcController 클래스의 getInstance(Context context) 인터페이스를 호출합니다.
  2. CardEmulation 클래스의 getInstance(NfcController 컨트롤러) 인터페이스를 호출하여 로컬 카드 시뮬레이션 모듈의 작업을 관리하기 위한 CardEmulation 인스턴스를 가져옵니다.
  3. getSelectionType(문자열 범주) 인터페이스를 호출하여 선택 서비스 메서드를 가져옵니다.
// 获取NFC控制对象
NfcController nfcController = NfcController.getInstance(context);
// 获取卡模拟控制对象
CardEmulation cardEmulation = CardEmulation.getInstance(nfcController);
// 获取选择服务的方式
int result = cardEmulation.getSelectionType(CardEmulation.CATEGORY_PAYMENT); // SELECTION_TYPE_PREFER_DEFAULT
result = cardEmulation.getSelectionType(CardEmulation.CATEGORY_OTHER); // SELECTION_TYPE_ASK_IF_CONFLICT

포그라운드 우선 애플리케이션에서 동적으로 설정 및 로그아웃

  1. NfcController 인스턴스를 얻기 위해 NfcController 클래스의 getInstance(Context context) 인터페이스를 호출합니다.
  2. CardEmulation 클래스의 getInstance(NfcController 컨트롤러) 인터페이스를 호출하여 로컬 카드 시뮬레이션 모듈의 작업을 관리하기 위한 CardEmulation 인스턴스를 가져옵니다.
  3. 전경 우선 애플리케이션을 동적으로 설정하려면 registerForegroundPreferred(Ability appAbility, ElementName appName) 인터페이스를 호출합니다.
  4. 포그라운드 선호 애플리케이션 설정을 취소하려면 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 애플리케이션을 위한 AID 관련 작업

정적 등록 AID

  1. 구성 파일 config.json에 HCE 서비스를 등록합니다. 자세한 내용은 능력을 참조하십시오 .
  2. 구성 파일의 모듈에서 metaData 개체를 추가하고 customizeData를 구성합니다.
    • paymentAid 필드를 사용하여 지불 유형의 AID를 정적으로 등록하고 '|' 기호를 사용하여 지불 유형의 여러 AID를 구분하십시오.
    • otherAid 필드를 사용하여 다른 유형의 AID를 정적으로 등록하고 '|' 기호를 사용하여 다른 여러 유형의 AID를 구분하십시오.

    샘플 코드는 다음과 같습니다.

"metaData": {
  "customizeData": [
    {
      "name": "paymentAid",
      "value": "325041592E5359532E4444463031"    
    },
    {
      "name": "otherAid",
      "value": "0123456789|535558494E2E4D46|1234567890"
     }  
  ]
}

동적으로 AID 등록

  1. NfcController 인스턴스를 얻기 위해 NfcController 클래스의 getInstance(Context context) 인터페이스를 호출합니다.
  2. CardEmulation 클래스의 getInstance(NfcController 컨트롤러) 인터페이스를 호출하여 로컬 카드 시뮬레이션 모듈의 작업을 관리하기 위한 CardEmulation 인스턴스를 가져옵니다.
  3. registerAids(ElementName appName, String type, List<String> aids) 인터페이스를 호출하여 애플리케이션에 지정된 유형의 AID를 등록합니다.
  4. removeAids(ElementName appName, String type) 인터페이스를 호출하여 애플리케이션의 지정된 유형의 AID를 삭제합니다.
// 获取NFC控制对象
NfcController nfcController = NfcController.getInstance(context);
// 获取卡模拟控制对象
CardEmulation cardEmulation = CardEmulation.getInstance(nfcController);
// 给应用注册指定类型的AID
List<String> aids = new ArrayList<String>();
aids.add(0, "A0028321901280");
aids.add(1, "A0028321901281");
Element element = new ElementName();
try {
    cardEmulation.registerAids(element, CardEmulation.CATEGORY_PAYMENT, aids);
} catch (IllegalArgumentException e) {
    HiLog.error(TAG, "IllegalArgumentException when registerAids");
}
// 删除应用的指定类型的AID
cardEmulation.removeAids(element, CardEmulation.CATEGORY_PAYMENT);
cardEmulation.removeAids(element, CardEmulation.CATEGORY_OTHER);

AID 쿼리

isDefaultForAid(ElementName appName, String aid) 인터페이스를 호출하여 애플리케이션이 지정된 AID에 대한 기본 처리 애플리케이션인지 여부를 판별하십시오.

// 判断应用是否是指定AID的默认处理应用
String aid = "A0028321901280";
cardEmulation.isDefaultForAid(element, aid);

getAids(ElementName appName, String type) 인터페이스를 호출하여 애플리케이션에서 지정된 유형의 AID 목록을 가져옵니다.

// 获取应用中指定类型的AID列表
try {
    cardEmulation.getAids(element, CardEmulation.CATEGORY_PAYMENT);
} catch (IllegalArgumentException e) {
    HiLog.error(TAG, "IllegalArgumentException when getAids");
}

호스트 서비스의 추상 클래스

  1. 애플리케이션 서비스는 HCE 카드 시뮬레이션 기능을 구현하기 위해 HostService를 상속합니다.
  2. 추상 메서드 handleRemoteCommand(byte[] cmd, IntentParams params) 및 disabledCallback()의 사용자 지정 구현을 적용합니다.
  3. 사용자 지정 기능을 적용합니다.
// HCE应用的服务继承HostService,实现HCE卡模拟功能
public class AppService extends HostService {
    @Override
    public byte[] handleRemoteCommand(byte[] cmd, IntentParams params) {
        HiLog.info(TAG, "handleRemoteCommand" );
        if (Arrays.equals(SELECT_PPSE, cmd)) {
            HiLog.info(TAG, "Matched PPSE select" );
            return PPSE_RESP;
        } else if (Arrays.equals(SELECT_MASTERCARD, cmd)) {
            HiLog.info(TAG, "Matched Mastercard select" );
            return SELECT_MASTERCARD_RESP;
        } else if (Arrays.equals(GET_PROC_OPT, cmd)) {
            HiLog.info(TAG, "Matched get processing options" );
            return GET_PROC_OPT_RESP;
        } else if (Arrays.equals(READ_REC, cmd)) {
            HiLog.info(TAG, "Matched read rec" );
            return READ_REC_RESP;
        } else if (cmd.length >= 5 && cmd[0] == (byte)0x80 && cmd[1] == (byte)0x2a
            && cmd[2] == (byte)0x8e && cmd[3] == (byte)0x80 && cmd[4] == 0x0f) {
            return COMPUTE_CHECKSUM_RESP;
        } else {
            return new byte[] {(byte)0x90, 0x00};
        }
    }
    
    @Override
    public void disabledCallback(int errCode) {
    // 应用自定义接口实现。
    }

    // 应用自定义功能
}

NFC 메시지 알림

장면 소개

NFC 메시지 알림은 HarmonyOS 내에서 또는 애플리케이션과의 프로세스 간 통신을 위한 메커니즘입니다 등록자가 메시지 알림에 등록한 후 인증된 메시지가 전송되면 등록자는 메시지를 받을 수 있습니다.

인터페이스 설명

표 1  NFC 메시지 알림 관련 브로드캐스트 소개

설명하다

알림 이름

추가 매개변수

NFC 상태

보통.event.nfc.action.ADAPTER_STATE_CHANGED

extra_nfc_state

참가 소식

보통.event.nfc.action.RF_FIELD_ON_DETECTED

extra_nfc_transaction

출발 메시지

보통.event.nfc.action.RF_FIELD_OFF_DETECTED

-

등록하고 NFC 상태 변경 메시지 받기

  1. 메시지 알림 수신자 NfcStateEventSubscriber를 빌드합니다.
  2. NFC 상태 변경 메시지를 등록합니다.
  3. NfcStateEventSubscriber는 NFC 상태 변경 메시지를 수신하고 처리합니다.
// 构建消息接收者/注册者
class NfcStateEventSubscriber extends CommonEventSubscriber {
    NfcStateEventSubscriber (CommonEventSubscribeInfo info) {
        super(info);
    }

    @Override
    public 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 전계 강도 소식 받기

  1. 메시지 알림 수신자 NfcFieldOnAndOffEventSubscriber를 빌드합니다.
  2. NFC 전계 강도 메시지에 등록하십시오.
  3. NfcFieldOnAndOffEventSubscriber는 NFC 전계 강도 메시지를 수신하고 처리합니다.
// 构建消息接收者/注册者
class NfcFieldOnAndOffEventSubscriber extends CommonEventSubscriber {
    NfcFieldOnAndOffEventSubscriber (CommonEventSubscribeInfo info) {
        super(info);
    }

    @Override
    public 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());
}

추천

출처blog.csdn.net/weixin_47094733/article/details/131469047