iOS Development

How HCE work with acr 122u nfc reader, When I’m attempting to work with under instance code It’s working like reader in android and ios

Spread the love


The code under is working after I emulate from android and iphone acts as a reader however not working with acr 122u usb nfc reader

Right here I’m posting the work round, any options or supply code could be actually useful.

KHostApduService


bundle com.instance.testnfcsunday

import android.app.Service
import android.content material.Intent
import android.nfc.NdefMessage
import android.nfc.NdefRecord
import android.nfc.cardemulation.HostApduService
import android.os.Bundle
import android.util.Log
import java.io.UnsupportedEncodingException
import java.math.BigInteger
import java.util.*

class KHostApduService : HostApduService() {

    non-public val TAG = "HostApduService"

    non-public val APDU_SELECT = byteArrayOf(
        0x00.toByte(), // CLA   - Class - Class of instruction
        0xA4.toByte(), // INS   - Instruction - Instruction code
        0x04.toByte(), // P1    - Parameter 1 - Instruction parameter 1
        0x00.toByte(), // P2    - Parameter 2 - Instruction parameter 2
        0x07.toByte(), // Lc discipline  - Variety of bytes current within the knowledge discipline of the command
        0xD2.toByte(),
        0x76.toByte(),
        0x00.toByte(),
        0x00.toByte(),
        0x85.toByte(),
        0x01.toByte(),
        0x01.toByte(), // NDEF Tag Software title
        0x00.toByte()  // Le discipline  - Most variety of bytes anticipated within the knowledge discipline of the response to the command
    )

    non-public val CAPABILITY_CONTAINER_OK = byteArrayOf(
        0x00.toByte(), // CLA   - Class - Class of instruction
        0xa4.toByte(), // INS   - Instruction - Instruction code
        0x00.toByte(), // P1    - Parameter 1 - Instruction parameter 1
        0x0c.toByte(), // P2    - Parameter 2 - Instruction parameter 2
        0x02.toByte(), // Lc discipline  - Variety of bytes current within the knowledge discipline of the command
        0xe1.toByte(), 0x03.toByte() // file identifier of the CC file
    )

    non-public val READ_CAPABILITY_CONTAINER = byteArrayOf(
        0x00.toByte(), // CLA   - Class - Class of instruction
        0xb0.toByte(), // INS   - Instruction - Instruction code
        0x00.toByte(), // P1    - Parameter 1 - Instruction parameter 1
        0x00.toByte(), // P2    - Parameter 2 - Instruction parameter 2
        0x0f.toByte()  // Lc discipline  - Variety of bytes current within the knowledge discipline of the command
    )

    // Within the situation that we have now finished a CC learn, the identical byte[] match
    // for ReadBinary would set off and we do not need that in succession
    non-public var READ_CAPABILITY_CONTAINER_CHECK = false

    non-public val READ_CAPABILITY_CONTAINER_RESPONSE = byteArrayOf(
        0x00.toByte(), 0x11.toByte(), // CCLEN size of the CC file
        0x20.toByte(), // Mapping Model 2.0
        0xFF.toByte(), 0xFF.toByte(), // MLe most
        0xFF.toByte(), 0xFF.toByte(), // MLc most
        0x04.toByte(), // T discipline of the NDEF File Management TLV
        0x06.toByte(), // L discipline of the NDEF File Management TLV
        0xE1.toByte(), 0x04.toByte(), // File Identifier of NDEF file
        0xFF.toByte(), 0xFE.toByte(), // Most NDEF file dimension of 65534 bytes
        0x00.toByte(), // Learn entry with none safety
        0xFF.toByte(), // Write entry with none safety
        0x90.toByte(), 0x00.toByte() // A_OKAY
    )

    non-public val NDEF_SELECT_OK = byteArrayOf(
        0x00.toByte(), // CLA   - Class - Class of instruction
        0xa4.toByte(), // Instruction byte (INS) for Choose command
        0x00.toByte(), // Parameter byte (P1), choose by identifier
        0x0c.toByte(), // Parameter byte (P1), choose by identifier
        0x02.toByte(), // Lc discipline  - Variety of bytes current within the knowledge discipline of the command
        0xE1.toByte(), 0x04.toByte() // file identifier of the NDEF file retrieved from the CC file
    )

    non-public val NDEF_READ_BINARY = byteArrayOf(
        0x00.toByte(), // Class byte (CLA)
        0xb0.toByte() // Instruction byte (INS) for ReadBinary command
    )

    non-public val NDEF_READ_BINARY_NLEN = byteArrayOf(
        0x00.toByte(), // Class byte (CLA)
        0xb0.toByte(), // Instruction byte (INS) for ReadBinary command
        0x00.toByte(), 0x00.toByte(), // Parameter byte (P1, P2), offset contained in the CC file
        0x02.toByte()  // Le discipline
    )

    non-public val A_OKAY = byteArrayOf(
        0x90.toByte(), // SW1   Standing byte 1 - Command processing standing
        0x00.toByte()   // SW2  Standing byte 2 - Command processing qualifier
    )

    non-public val A_ERROR = byteArrayOf(
        0x6A.toByte(), // SW1   Standing byte 1 - Command processing standing
        0x82.toByte()   // SW2  Standing byte 2 - Command processing qualifier
    )

    non-public val NDEF_ID = byteArrayOf(0xE1.toByte(), 0x04.toByte())

    non-public var NDEF_URI = NdefMessage(createTextRecord("en", "token", NDEF_ID))
    non-public var NDEF_URI_BYTES = NDEF_URI.toByteArray()
    non-public var NDEF_URI_LEN = fillByteArrayToFixedDimension(
        BigInteger.valueOf(NDEF_URI_BYTES.dimension.toLong()).toByteArray(), 2
    )


    override enjoyable onStartCommand(intent: Intent, flags: Int, startId: Int): Int {

        if (intent.hasExtra("ndefMessage")) {
            NDEF_URI =
                NdefMessage(createTextRecord("en",
                    intent.getStringExtra("ndefMessage").toString(), NDEF_ID))

            NDEF_URI_BYTES = NDEF_URI.toByteArray()
            NDEF_URI_LEN = fillByteArrayToFixedDimension(
                BigInteger.valueOf(NDEF_URI_BYTES.dimension.toLong()).toByteArray(), 2
            )
        }

        Log.i(TAG, "onStartCommand() | NDEF" + NDEF_URI.toString())

        return Service.START_STICKY
    }

    override enjoyable processCommandApdu(commandApdu: ByteArray, extras: Bundle?): ByteArray {

        //
        // The next stream relies on Appendix E "Instance of Mapping Model 2.0 Command Circulation"
        // within the NFC Discussion board specification
        //
        Log.i(TAG, "processCommandApdu() | incoming commandApdu: " + commandApdu.toHex())

        //
        // First command: NDEF Tag Software choose (Part 5.5.2 in NFC Discussion board spec)
        //
        if (Arrays.equals(APDU_SELECT, commandApdu)) {
            Log.i(TAG, "APDU_SELECT triggered. Our Response: " + A_OKAY.toHex())
            return A_OKAY
        }

        //
        // Second command: Functionality Container choose (Part 5.5.3 in NFC Discussion board spec)
        //
        if (Arrays.equals(CAPABILITY_CONTAINER_OK, commandApdu)) {
            Log.i(TAG, "CAPABILITY_CONTAINER_OK triggered. Our Response: " + A_OKAY.toHex())
            return A_OKAY
        }

        //
        // Third command: ReadBinary knowledge from CC file (Part 5.5.4 in NFC Discussion board spec)
        //
        if (Arrays.equals(
                READ_CAPABILITY_CONTAINER,
                commandApdu
            ) && !READ_CAPABILITY_CONTAINER_CHECK
        ) {
            Log.i(
                TAG,
                "READ_CAPABILITY_CONTAINER triggered. Our Response: " + READ_CAPABILITY_CONTAINER_RESPONSE.toHex()
            )
            READ_CAPABILITY_CONTAINER_CHECK = true
            return READ_CAPABILITY_CONTAINER_RESPONSE
        }

        //
        // Fourth command: NDEF Choose command (Part 5.5.5 in NFC Discussion board spec)
        //
        if (Arrays.equals(NDEF_SELECT_OK, commandApdu)) {
            Log.i(TAG, "NDEF_SELECT_OK triggered. Our Response: " + A_OKAY.toHex())
            return A_OKAY
        }

        if (Arrays.equals(NDEF_READ_BINARY_NLEN, commandApdu)) {
            // Construct our response
            val response = ByteArray(NDEF_URI_LEN.dimension + A_OKAY.dimension)
            System.arraycopy(NDEF_URI_LEN, 0, response, 0, NDEF_URI_LEN.dimension)
            System.arraycopy(A_OKAY, 0, response, NDEF_URI_LEN.dimension, A_OKAY.dimension)

            Log.i(TAG, "NDEF_READ_BINARY_NLEN triggered. Our Response: " + response.toHex())

            READ_CAPABILITY_CONTAINER_CHECK = false
            return response
        }

        if (Arrays.equals(commandApdu.sliceArray(0..1), NDEF_READ_BINARY)) {
            val offset = commandApdu.sliceArray(2..3).toHex().toInt(16)
            val size = commandApdu.sliceArray(4..4).toHex().toInt(16)

            val fullResponse = ByteArray(NDEF_URI_LEN.dimension + NDEF_URI_BYTES.dimension)
            System.arraycopy(NDEF_URI_LEN, 0, fullResponse, 0, NDEF_URI_LEN.dimension)
            System.arraycopy(
                NDEF_URI_BYTES,
                0,
                fullResponse,
                NDEF_URI_LEN.dimension,
                NDEF_URI_BYTES.dimension
            )

            Log.i(TAG, "NDEF_READ_BINARY triggered. Full knowledge: " + fullResponse.toHex())
            Log.i(TAG, "READ_BINARY - OFFSET: " + offset + " - LEN: " + size)

            val slicedResponse = fullResponse.sliceArray(offset till fullResponse.dimension)

            // Construct our response
            val realLength = if (slicedResponse.dimension <= size) slicedResponse.dimension else size
            val response = ByteArray(realLength + A_OKAY.dimension)

            System.arraycopy(slicedResponse, 0, response, 0, realLength)
            System.arraycopy(A_OKAY, 0, response, realLength, A_OKAY.dimension)

            Log.i(TAG, "NDEF_READ_BINARY triggered. Our Response: " + response.toHex())

            READ_CAPABILITY_CONTAINER_CHECK = false
            return response
        }

        //
        // We're doing one thing exterior our scope
        //
        Log.i(TAG, "processCommandApdu() | I do not know what is going on on!!!")
        return A_ERROR
    }

    override enjoyable onDeactivated(purpose: Int) {
        Log.i(TAG, "onDeactivated() Fired! Motive: $purpose")
    }


    non-public val HEX_CHARS = "0123456789ABCDEF".toCharArray()

    enjoyable ByteArray.toHex(): String {
        val outcome = StringBuffer()

        forEach {
            val octet = it.toInt()
            val firstIndex = (octet and 0xF0).ushr(4)
            val secondIndex = octet and 0x0F
            outcome.append(HEX_CHARS[firstIndex])
            outcome.append(HEX_CHARS[secondIndex])
        }

        return outcome.toString()
    }

    enjoyable createTextRecord(language: String, textual content: String, id: ByteArray): NdefRecord {
        val languageBytes: ByteArray
        val textBytes: ByteArray
        attempt {
            languageBytes = language.toByteArray(charset("US-ASCII"))
            textBytes = textual content.toByteArray(charset("UTF-8"))
        } catch (e: UnsupportedEncodingException) {
            throw AssertionError(e)
        }

        val recordPayload = ByteArray(1 + (languageBytes.dimension and 0x03F) + textBytes.dimension)

        recordPayload[0] = (languageBytes.dimension and 0x03F).toByte()
        System.arraycopy(languageBytes, 0, recordPayload, 1, languageBytes.dimension and 0x03F)
        System.arraycopy(
            textBytes,
            0,
            recordPayload,
            1 + (languageBytes.dimension and 0x03F),
            textBytes.dimension
        )

        return NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, id, recordPayload)
    }

    enjoyable fillByteArrayToFixedDimension(array: ByteArray, fixedSize: Int): ByteArray {
        if (array.dimension == fixedSize) {
            return array
        }

        val begin = byteArrayOf(0x00.toByte())
        val filledArray = ByteArray(begin.dimension + array.dimension)
        System.arraycopy(begin, 0, filledArray, 0, begin.dimension)
        System.arraycopy(array, 0, filledArray, begin.dimension, array.dimension)
        return fillByteArrayToFixedDimension(filledArray, fixedSize)
    }
}


My MainActivity is

class MainActivity : AppCompatActivity() {
    @RequiresApi(Construct.VERSION_CODES.M)
    @SuppressLint("MissingInflatedId")
    override enjoyable onCreate(savedInstanceState: Bundle?) {
        tremendous.onCreate(savedInstanceState)
        setContentView(R.structure.activity_main)
        val nfcavailibility:TextView=findViewById(R.id.nfcavailibility)
        val button: Button = findViewById(R.id.hellobutton);
        val editText: EditText = findViewById(R.id.editText);
        val nfcAdapter: NfcAdapter? = NfcAdapter.getDefaultAdapter(applicationContext)
        if (nfcAdapter != null && nfcAdapter.isEnabled()) {
           nfcavailibility.textual content="Avaliable"
        } else {
            nfcavailibility.textual content="Not avaliable or disabled"
        }
        button.setOnClickListener {
            if (editText.textual content.toString().size > 0) {
                val intent = Intent(this, KHostApduService::class.java)
                intent.putExtra("ndefMessage", editText.textual content.toString())
                startService(intent)
                showAlertDialog(editText.textual content.toString())
//                val nfcPendingIntent = PendingIntent.getService(this, 0, Intent(this, KHostApduService::class.java), PendingIntent.FLAG_IMMUTABLE)
//                intent.putExtra("ndefMessage", editText.textual content.toString())
//                if (nfcAdapter != null) {
//                    nfcAdapter.enableForegroundDispatch(this, nfcPendingIntent, null, null)
//                }

            } else {
                Toast.makeText(applicationContext, "Enter tag no", Toast.LENGTH_SHORT).present()
            }

        }
    }

    non-public enjoyable showAlertDialog(toString: String) {
        val alertDialog: AlertDialog.Builder = AlertDialog.Builder(this@MainActivity)
        alertDialog.setMessage("Emaulated Tag:-" + toString)
        alertDialog.setCancelable(false)
        alertDialog.setPositiveButton(
            "Cancel"
        ) { _, _ ->
            val intent = Intent(this, KHostApduService::class.java)
            stopService(intent)
        }

        val alert: AlertDialog = alertDialog.create()
        alert.setCanceledOnTouchOutside(false)
        alert.present()
    }
}

apduservice.xml

<?xml model="1.0" encoding="utf-8"?>

<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:description="@string/app_name" android:requireDeviceUnlock="false">

    <aid-group android:description="@string/app_name2"  android:class="different" >
        <aid-filter android:title="D2760000850101"/>

</host-apdu-service>

Coming to my AndroidManifest.xml is

<?xml model="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:instruments="http://schemas.android.com/instruments">
    <uses-permission android:title="android.permission.NFC"/>
    <uses-feature android:title="android.{hardware}.nfc.hce"
        android:required="true"/>
    <uses-feature
        android:title="android.{hardware}.nfc"
        android:required="true"/>

    <utility
        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="@type/Theme.TestNFCSunday"
        instruments:targetApi="31">
        <exercise
            android:title=".MainActivity"
            android:exported="true">
            <intent-filter>
                <motion android:title="android.intent.motion.MAIN" />

                <class android:title="android.intent.class.LAUNCHER" />
            </intent-filter>

            <meta-data
                android:title="android.app.lib_name"
                android:worth="" />
        </exercise>

        <service android:title=".KHostApduService"
            android:exported="true"
            android:enabled="true"
            android:permission="android.permission.BIND_NFC_SERVICE">

            <!-- Intent filter indicating that we assist card emulation. -->
            <intent-filter>
                <motion android:title="android.nfc.cardemulation.motion.HOST_APDU_SERVICE"/>
                <class android:title="android.intent.class.DEFAULT"/>
            </intent-filter>
            <!-- Required XML configuration file, itemizing the AIDs that we're emulating playing cards
                 for. This defines what protocols our card emulation service helps. -->
            <meta-data android:title="android.nfc.cardemulation.host_apdu_service"
                android:useful resource="@xml/apduservice"/>
        </service>
    </utility>

</manifest>

Above is the code that I applied and dealing as a NFC reader and it isn’t working with acr 122u usb* nfc reader

Leave a Reply

Your email address will not be published. Required fields are marked *