[Android] 모바일 결제와 HostApduService

incava·2024년 6월 4일
0

모바일 결제

여러분들은 휴대폰에 리더기를 갖다대면 문이열리거나 요금정산이 되는 경험을 해보신 적이 있나요?
이 결제 시스템은 앱 설치 시에 NFC를 이용해 실행 되는데, 앱을 실행하지 않고도 결제를 이용할 수 있어야 합니다.

따라서 저희는 HCE라는 호스트 기반 카드 에뮬레이션을 사용 해야합니다.

HCE

💡 HCE란 호스트 카드 에뮬레이션은 소프트웨어만을 사용하여 다양한 전자 식별자의 정확한 가상 표현을 제공하는 소프트웨어 구조이다.

HCE을 통해 전자 식별자를 이용해 리더기에 결과값을 넘겨줄 수 있도록 할 수 있는 것이죠.

먼저 HCE의 실행 흐름을 먼저 파악해봅시다.

  1. NFC Reader에 휴대폰을 갖다대면
  2. Host CPU에 대해 반응을 하게 된다.
  3. 그리고 NFC Controller인 앱에 대해 해당 값이 들어오게 된다.

그렇다면 앱은 모든 NFC Reader에 대해 반응 할까요?

아닙니다. 아까도 언급했듯 전자 식별자를 이용한다고 했는데요. 이 식별자는 AID라고 불리는 것으로 식별이 됩니다.

이 AID는 어떻게 추가하고 사용해야 할까요?

HostApduService

HCE를 사용하기 위해서는 Service를 Extends한 HostApduService라는 것을 사용해야 합니다.

이 HostApduService는 등록한 AID신호를 받았을 경우, 앱 실행 없이도 Service를 통해 해당 클래스가 실행됩니다.

HostApduService 코드를 들여다봅시다

public abstract class HostApduService extends Service {
    public static final int DEACTIVATION_DESELECTED = 1;
    public static final int DEACTIVATION_LINK_LOSS = 0;
    public static final String SERVICE_INTERFACE = "android.nfc.cardemulation.action.HOST_APDU_SERVICE";
    public static final String SERVICE_META_DATA = "android.nfc.cardemulation.host_apdu_service";

    public HostApduService() {
        throw new RuntimeException("Stub!");
    }

    public final IBinder onBind(Intent intent) {
        throw new RuntimeException("Stub!");
    }

    public final void sendResponseApdu(byte[] responseApdu) {
        throw new RuntimeException("Stub!");
    }

    public final void notifyUnhandled() {
        throw new RuntimeException("Stub!");
    }

    public abstract byte[] processCommandApdu(byte[] var1, Bundle var2);

    public abstract void onDeactivated(int var1);
}

몇가지의 메서드가 존재하는데, processCommandApdu는 NFC를통해 AID값을 읽었을 때, 해당 AID값이 byte[]타입인 var1로 들어오게 됩니다.

이 값을 통해 여러 AID값을 분기처리 할 수 있게 됩니다.

그리고 반환값이 존재하는데 이 반환값을 NFC에 전달하게 됨으로써, 서비스는 종료됩니다.

즉 HostApduService는 processCommandApdu라는 메서드를 오버라이딩 하여 해당 부분에 어떤 값을 반환할 것인지에 대해 로직을 추가해야 한다는 것이죠.

Service인 만큼 우리는 매니페스트에 Service에 대한 정의를 해주어야 하는데 매니페스트에는 어떻게 적어야 할까요?

Manifest

<service android:name=".MyHostApduService" android:exported="true"
         android:permission="android.permission.BIND_NFC_SERVICE">
    <intent-filter>
        <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/>
    </intent-filter>
    <meta-data android:name="android.nfc.cardemulation.host_apdu_service"
               android:resource="@xml/apduservice"/>
</service>

위의 코드는 HostApduService에 대한 Manifest 작성 예시입니다.

예시 처럼 Service안에 해당 부분처럼 채워주면 되는데, 다만 여기서 meta-data 안에 있는 resource에 대해 서는 xml을 하나 추가해 등록할 AID에 대한 정보를 제공해야 합니다.

XML

<?xml version="1.0" encoding="utf-8"?>
<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:description="@string/service_name"
    android:requireDeviceUnlock="false">

    <aid-group android:description="@string/card_title" android:category="other">
        <aid-filter android:name="F222222222"/> 
    </aid-group>
</host-apdu-service>

XML에 대해 < host-apdu-service> 에 대한 태그를 작성해줘야 하는데, 이 안에는 < aid-group>에 대해 정의를 해주어야 합니다.

  • description은 해당 부분에 대한 명칭을
  • category에 대해서는 “other” 와 “payment” 두 개의 선택지 만이 존재합니다.
    • “모바일 결제”에 대해서는 “payment”라는 카테고리를
    • 이 외의 “기타”에 대해서는 “other”라는 카테고리로 들어가게 된다.
  • aid-filter에 대해서는 NFC에 대해 어떤 신호를 받을 것인지에 대해 식별값을 정의하도록 합니다.

그리고 < host-apdu-service> 에 대해 requireDeviceUnlock 설정은 기기 화면이 꺼져 있을 때도 NFC신호를 받을 것인지에 대한 부분인데, 필요에 따라 true, false를 통해 정의해줄 수 있습니다.

이로써, 모바일 결제에 대한 구현부는 모두 구현하였습니다. 앱이 설치되면 NFC를 통해 사용해보실 수 있습니다.

동적인 AID 추가

응용 버전으로 AID는 보통 정적인 경우가 많을텐데,솔루션이 필요할 경우에 혹은 하이브리드웹뷰인 경우에는 AID를 동적으로도 추가 할 수가 있는데, 방법은 이렇습니다.

List<String> aids = new ArrayList<>();
        aids.add("F0010203040506"); // 예시 AID

        // 등록할 AID와 서비스를 지정
ComponentName serviceComponent = new ComponentName(this, MyHostApduService.class);
CardEmulation cardEmulation = CardEmulation.getInstance(NfcAdapter.getDefaultAdapter(this));
cardEmulation.registerAidsForService(serviceComponent, "payment", aids); // payment 혹은 other

등록할 aidList를 작성하고, 카드에뮬레이션에 등록하면 카드 결제서비스에 대한 AID를 덮어쓰기 할 수 있습니다. 보통은 정적으로 xml을 불러오는 것이 좋겠지만 동적으로 사용하고 싶을 때 유용할만 합니다.

사실 자료가 많이 없는 마이너한 클래스라 정보가 틀린 부분이 있을 수도 있습니다. 오류인 부분이 있다면 언제든지 피드백 주시면 다시 검토 후 수정하도록 하겠습니다. 즐거운 코딩되세요 :D

profile
근거있는 코딩하고 싶은 개발자

1개의 댓글

comment-user-thumbnail
2024년 6월 9일

👎👎

답글 달기

관련 채용 정보