I just want to get AID from scanned debit/credit card, many apps are available on Google play store that easily gets the info on scan but i am unable to get the same. The purpose of getting the AID instead of actual Card Information (Card Number , Expiry etc) is that the client has received a legal notice to use AID instead of the card info.
Here is what i've tried so far:
- Added Service reference in Manifest file
- Created apduservice.xml and added reference in Menifest file as available on internet.
AndroidMenifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.NFC" />
<uses-feature
android:name="android.hardware.nfc.hce"
android:required="true" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.NFC"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.TECH_DISCOVERED"/>
<!-- <action android:name="android.nfc.action.NDEF_DISCOVERED"/>-->
<!-- Default category is required for the intent filter to work -->
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<!-- Default category is required for the intent filter to work -->
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<!-- Also register for the URL if it appears outside of NFC tags -->
</activity>
<service
android:name=".NdefHostApduService"
android:exported="true"
android:permission="android.permission.BIND_NFC_SERVICE">
<intent-filter>
<action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE" />
<!-- <category android:name="android.intent.category.DEFAULT" />-->
</intent-filter>
<meta-data
android:name="android.nfc.cardemulation.host_apdu_service"
android:resource="@xml/apduservice" />
</service>
</application>
</manifest>
apduservice.xml
<?xml version="1.0" encoding="utf-8"?>
<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/servicedesc"
android:requireDeviceUnlock="false">
<aid-group android:description="@string/aiddescription"
android:category="other">
<aid-filter android:name="A0000002471001"/>
<aid-filter android:name="F00000000A0101"/>
<!-- <aid-filter android:name="F0010203040506"/>-->
<aid-filter android:name="F0394148148100"/>
<aid-filter android:name="D2760000850101"/>
<aid-filter android:name="A0000000041010"/>
<aid-filter android:name="A0000000031010"/> <!-- Visa -->
<aid-filter android:name="A0000000041010"/> <!-- Mastercard -->
<aid-filter android:name="A00000002501"/> <!-- American Express -->
<aid-filter android:name="A0000000042203"/> <!-- Discover -->
<aid-filter android:name="A0000000651010"/> <!-- JCB -->
<aid-filter android:name="A0000003330101"/> <!-- UnionPay -->
</aid-group>
</host-apdu-service>
NdefHostApduService.java // processCommandApdu Never triggers
package com.example.nfc;
import android.content.Context;
import android.content.Intent;
import android.nfc.NdefRecord;
import android.nfc.cardemulation.HostApduService;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.widget.Toast;
import java.math.BigInteger;
import java.nio.charset.Charset;
public class NdefHostApduService extends HostApduService {
public NdefHostApduService(){
}
private static final String TAG = "NdefHostApduService";
String STATUS_SUCCESS = "9000";
String STATUS_FAILED = "6F00";
String CLA_NOT_SUPPORTED = "6E00";
String INS_NOT_SUPPORTED = "6D00";
String AID = "A0000002471001";
String SELECT_INS = "A4";
String DEFAULT_CLA = "00";
int MIN_APDU_LENGTH = 12;
private static final byte[] NDEF_ID = {
(byte)0xE1,
(byte)0x04
};
private NdefRecord NDEF_URI = new NdefRecord(
NdefRecord.TNF_WELL_KNOWN,
NdefRecord.RTD_TEXT,
NDEF_ID,
"Hello world!".getBytes(Charset.forName("UTF-8"))
);
private byte[] NDEF_URI_BYTES = NDEF_URI.toByteArray();
private byte[] NDEF_URI_LEN = BigInteger.valueOf(NDEF_URI_BYTES.length).toByteArray();
@Override
public byte[] processCommandApdu(byte[] commandApdu, Bundle extras) {
// Convert the command APDU to a hexadecimal string for easier manipulation
String commandApduHex = toHexString(commandApdu);
// Check if the command APDU is a SELECT APDU
if (commandApduHex.startsWith("00A404")) {
// Extract the AID from the SELECT APDU
String aid = commandApduHex.substring(6);
Log.d(TAG, "Selected AID: " + aid);
// You can further process or use the AID as needed
}
// Handle other APDU commands as needed
// Return a response APDU if necessary
return new byte[0];
}
@Override
public void onDeactivated(int reason)
{
Log.d(TAG, "Deactivated: " + reason);
}
private static String toHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X", b));
}
return sb.toString();
}
}