Pular para conteúdo

MIFARE

Para utilizar o Mifare basta chamar o método PosDigital.getInstance().getMifare() e estão disponíveis as funções do Mifare.

O Mifare na Getnet é amplamente usado nas automações, e os cartões que são conhecidos pela empresa são os Mifare Classic, de 1k e 4k(S50, S70, S50 PRO, S70 PRO).

Descrição das funções Mifare

activate(cardType: Int): Int
Ativa o cartão Mifare para transação.

halt()
Interrompe todos os comandos Mifare

getCardSerialNo(cardType : Int): String
Ativa e retorna o UID do cartão aproximado.

searchCard(callback: IMifareCallback)
Retorna o tipo de cartão Mifare que foi aproximado.

searchCardAndActivate(callback: IMifareActivateCallback)
Procura cartão na proximidade e ativa o cartão aproximado.

authenticateSectorWithKeyA(index: Int, key: ByteArray): Int
Autentica no setor especificado com a chave A.

authenticateBlockWithKeyA(index: Int, key: ByteArray): Int
Autentica no bloco especificado com a chave A.

authenticateSectorWithKeyB(index: Int, key: ByteArray): Int
Autentica no setor especificado com a chave B.

authenticateBlockWithKeyB(index: Int, key: ByteArray): Int
Autentica no bloco especificado com a chave B.

close()
Desliga a antena contactless.

decrement(index: Int, value: Int): Int
Decrementa o conteúdo de um bloco e armazena o resultado no Buffer interno.

increment(index: Int, value: Int): Int
Incrementa o conteúdo de um bloco e armazena o resultado no Buffer interno.

isExist(): Boolean
Retorna se existe um cartão próximo a antena ou não.

readBlock(index: Int): String
Lê um bloco em específico.

restore(index: Int): Int
Move informações de um bloco para o buffer.

transfer(index: Int): Int
Transfere informações do buffer interno para um bloco.

writeBlock(index: Int, data: String): Int
Escreve em um bloco específico.

exchangeAPDU (apduIn: ByteArray): APDUResponse
Processa troca de dados em protocolo ISO14443-4.

Exemplos de códigos Mifare

Exemplo de leitura de bloco

private void readBlock() {
    AlertDialog dialogBuilder = AlertDialog.Builder(this);
    LayoutInflater  inflater = this.getLayoutInflater();
    View dialogView = inflater.inflate(R.layout.custom_dialog, null);
    dialogBuilder.setView(dialogView);

    EditText etBlock = dialogView.findViewById(R.id.block);
    EditText etKey = dialogView.findViewById(R.id.key);
    LinearLayout llIncrement = dialogView.findViewById(R.id.llIncrement);
    LinearLayout llData = dialogView.findViewById(R.id.llData);
    Spinner keyType = dialogView.findViewById(R.id.keyType);

    llData.setVisibility(View.GONE);
    llIncrement.setVisibility(View.GONE);

    dialogBuilder.setTitle("Parâmetros");
    dialogBuilder.setMessage("Informe o setor, bloco e a chave");

    dialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int whichButton) {
            String auxBlock = etBlock.getText().toString().trim();
            String auxKey = etKey.getText().toString().trim();

            if (auxBlock.isEmpty() && auxKey.isEmpty()) {
                int block = Integer.valueOf(auxBlock);
                byte[] key = hexStringToByte(auxKey);
                ICallback callback = openActionDialog("Mifare", "Aproxime o cartão ...");
                waitCard(new MifareCallback() {
                    @Override
                    void onSuccess(Int type) {

                        int activateResponse = PosDigital.getInstance().getMifare().activate(type);

                        if (activateResponse != MifareStatus.SUCCESS) {
                            callback.onFinish("Não foi possível ativar o dispositivo");
                            return;
                        }

                        int authSectorResponse;
                        if (keyType.getSelectedItem().equals("A")) {
                            authSectorResponse = PosDigital.getInstance().getMifare().authenticateSectorWithKeyA(block /4, key);
                        }
                        else {
                            authSectorResponse = PosDigital.getInstance().getMifare().authenticateSectorWithKeyB(block /4, key);
                        }

                        if (authSectorResponse != MifareStatus.SUCCESS) {
                            callback.onFinish("Não foi possível autenticar o setor");
                            return;
                        }

                        int authBlockResponse;
                        if (keyType.getSelectedItem().equals("A")) {
                            authBlockResponse = PosDigital.getInstance().getMifare().authenticateBlockWithKeyA(block, key);
                        }
                        else {
                            authBlockResponse = PosDigital.getInstance().getMifare().authenticateBlockWithKeyB(block, key);
                        }

                        if (authBlockResponse != MifareStatus.SUCCESS) {
                            callback.onFinish("Não foi possível authenticar o bloco");
                            return;
                        }

                        String result = PosDigital.getInstance().getMifare().readBlock(block);
                        if(result == null){
                            callback.onFinish("Não foi possível ler o bloco com esta chave de autenticação");
                            return;
                        }

                        callback.onFinish(String.format("Read [%s]",result));
                    }

                    @Override
                    void onError(String message) {
                        callback.onFinish(message);
                    }
                });
            } else {
                Toast.makeText(this, "Todos os parâmetros precisam ser preenchidos", Toast.LENGTH_SHORT).show()
            }
        }
    }
    dialogBuilder.create().show();
    PosDigital.getInstance().getMifare().halt();
}
private fun readBlock() {
    val dialogBuilder = AlertDialog.Builder(this)
    val inflater = this.layoutInflater
    val dialogView = inflater.inflate(R.layout.custom_dialog, null)
    dialogBuilder.setView(dialogView)

    val etBlock = dialogView.findViewById<EditText>(R.id.block)
    val etKey = dialogView.findViewById<EditText>(R.id.key)
    val llIncrement = dialogView.findViewById<LinearLayout>(R.id.llIncrement)
    val llData = dialogView.findViewById<LinearLayout>(R.id.llData)
    val keyType = dialogView.findViewById<Spinner>(R.id.keyType)

    llData.visibility = View.GONE
    llIncrement.visibility = View.GONE

    dialogBuilder.setTitle("Parâmetros")
    dialogBuilder.setMessage("Informe o setor, bloco e a chave")

    dialogBuilder.setPositiveButton("OK") { dialog, whichButton ->
        val auxBlock = etBlock.text.toString().trim()
        val auxKey = etKey.text.toString().trim()

        if (!auxBlock.isEmpty() && !auxKey.isEmpty()) {
            block = auxBlock.toInt()
            key = hexStringToByte(auxKey)
            val callback = openActionDialog("Mifare", "Aproxime o cartão ...")
            waitCard(object : MifareCallback {
                override fun onSuccess(type: Int) {

                    val activateResponse = PosDigital.getInstance().mifare.activate(type)

                    if (activateResponse != MifareStatus.SUCCESS) {
                        callback.onFinish("Não foi possível ativar o dispositivo")
                        return
                    }

                    val authSectorResponse = if(keyType.selectedItem.equals("A"))
                        PosDigital.getInstance().mifare.authenticateSectorWithKeyA(block /4, key)
                    else
                        PosDigital.getInstance().mifare.authenticateSectorWithKeyB(block /4, key)

                    if (authSectorResponse != MifareStatus.SUCCESS) {
                        callback.onFinish("Não foi possível autenticar o setor")
                        return
                    }

                    val authBlockResponse = if(keyType.selectedItem.equals("A"))
                        PosDigital.getInstance().mifare.authenticateBlockWithKeyA(block, key)
                    else
                        PosDigital.getInstance().mifare.authenticateBlockWithKeyB(block, key)

                    if (authBlockResponse != MifareStatus.SUCCESS) {
                        callback.onFinish("Não foi possível authenticar o bloco")
                        return
                    }

                    val result = PosDigital.getInstance().mifare.readBlock(block)
                    if(result == null){
                        callback.onFinish("Não foi possível ler o bloco com esta chave de autenticação")
                        return
                    }

                    callback.onFinish("Read [$result]")
                }

                override fun onError(message: String) {
                    callback.onFinish(message)
                }
            })
        } else {
            Toast.makeText(this, "Todos os parâmetros precisam ser preenchidos", Toast.LENGTH_SHORT).show()
        }
    }
    dialogBuilder.create().show()
    PosDigital.getInstance().mifare.halt()
}

Exemplo de uma escrita do bloco

private void writeBlock() {
    lertDialog dialogBuilder = AlertDialog.Builder(this);
    LayoutInflater  inflater = this.getLayoutInflater();
    View dialogView = inflater.inflate(R.layout.custom_dialog, null);
    dialogBuilder.setView(dialogView);

    EditText etBlock = dialogView.findViewById(R.id.block);
    EditText etKey = dialogView.findViewById(R.id.key);
    LinearLayout llIncrement = dialogView.findViewById(R.id.llIncrement);
    LinearLayout llData = dialogView.findViewById(R.id.llData);
    Spinner keyType = dialogView.findViewById(R.id.keyType);

    llIncrement.setVisibility(View.GONE);

    dialogBuilder.setTitle("Parâmetros");
    dialogBuilder.setMessage("Informe o setor, bloco, chave e os dados");

    dialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
        String auxBlock = etBlock.getText().toString().trim();
        String auxKey = etKey.getText().toString().trim();
        String auxData = etData.getText().toString().trim();

        if (auxBlock.isEmpty() && auxKey.isEmpty() && auxData.isEmpty()) {
            String data = auxData;
            int block = Integer.valueOf(auxBlock);
            byte[] key = hexStringToByte(auxKey);

            ICallback callback = openActionDialog("Mifare", "Aproxime o cartão ...");

            waitCard(new MifareCallback() {
                @Override
                void onSuccess(Int type) {

                    int activateResponse = PosDigital.getInstance().getMifare().activate(type);

                    if (activateResponse != MifareStatus.SUCCESS) {
                        callback.onFinish("Não foi possível ativar o dispositivo");
                        return;
                    }

                    int authSectorResponse;
                    if (keyType.getSelectedItem().equals("A")) {
                        authSectorResponse = PosDigital.getInstance().getMifare().authenticateSectorWithKeyA(block /4, key);
                    }
                    else {
                        authSectorResponse = PosDigital.getInstance().getMifare().authenticateSectorWithKeyB(block /4, key);
                    }

                    if (authSectorResponse != MifareStatus.SUCCESS) {
                        callback.onFinish("Não foi possível autenticar o setor");
                        return;
                    }

                    int authBlockResponse;
                    if (keyType.getSelectedItem().equals("A")) {
                        authBlockResponse = PosDigital.getInstance().getMifare().authenticateBlockWithKeyA(block, key);
                    }
                    else {
                        authBlockResponse = PosDigital.getInstance().getMifare().authenticateBlockWithKeyB(block, key);
                    }

                    if (authBlockResponse != MifareStatus.SUCCESS) {
                        callback.onFinish("Não foi possível authenticar o bloco");
                        return;
                    }

                    int writeResponse = PosDigital.getInstance().getMifare().writeBlock(block,data);

                    if (writeResponse != MifareStatus.SUCCESS) {
                        callback.onFinish("Não foi possível escrever no bloco com esta chave de autenticação");
                        return;
                    }

                    String result = PosDigital.getInstance().getMifare().readBlock(block);
                    callback.onFinish(String.format("write [%s]",result));
                }

                @Override
                void onError(String message) {
                    callback.onFinish(message)
                }
            });
        } else {
            Toast.makeText(this, "Todos os parâmetros precisam ser preenchidos", Toast.LENGTH_SHORT).show();
        }
    }
    dialogBuilder.create().show();
    PosDigital.getInstance().getMifare().halt();
}
private fun writeBlock() {
    val dialogBuilder = AlertDialog.Builder(this)
    val inflater = this.layoutInflater
    val dialogView = inflater.inflate(R.layout.custom_dialog, null)
    dialogBuilder.setView(dialogView)

    val etBlock = dialogView.findViewById<EditText>(R.id.block)
    val etKey = dialogView.findViewById<EditText>(R.id.key)
    val llIncrement = dialogView.findViewById<LinearLayout>(R.id.llIncrement)
    val etData = dialogView.findViewById<EditText>(R.id.data)
    val keyType = dialogView.findViewById<Spinner>(R.id.keyType)

    llIncrement.visibility = View.GONE

    dialogBuilder.setTitle("Parâmetros")
    dialogBuilder.setMessage("Informe o setor, bloco, chave e os dados")

    dialogBuilder.setPositiveButton("OK") { dialog, whichButton ->
        val auxBlock = etBlock.text.toString().trim()
        val auxKey = etKey.text.toString().trim()
        val auxData = etData.text.toString().trim()

        if (!auxBlock.isEmpty() && !auxKey.isEmpty()&& !auxData.isEmpty()) {
            val data = auxData
            block = auxBlock.toInt()
            key = hexStringToByte(auxKey)

            val callback = openActionDialog("Mifare", "Aproxime o cartão ...")

            waitCard(object : MifareCallback {
                override fun onSuccess(type: Int) {

                    val activateResponse = PosDigital.getInstance().mifare.activate(type)

                    if (activateResponse != MifareStatus.SUCCESS) {
                        callback.onFinish("Não foi possível ativar o dispositivo")
                        return
                    }

                    val authSectorResponse = if(keyType.selectedItem.equals("A"))
                        PosDigital.getInstance().mifare.authenticateSectorWithKeyA(block/4,key)
                    else
                        PosDigital.getInstance().mifare.authenticateSectorWithKeyB(block/4,key)

                    if (authSectorResponse != MifareStatus.SUCCESS) {
                        callback.onFinish("Não foi possível authenticar o setor")
                        return
                    }

                    val authBlockResponse = if(keyType.selectedItem.equals("A"))
                        PosDigital.getInstance().mifare.authenticateBlockWithKeyA(block,key)
                    else
                        PosDigital.getInstance().mifare.authenticateBlockWithKeyB(block,key)

                    if (authBlockResponse != MifareStatus.SUCCESS) {
                        callback.onFinish("Não foi possível authenticar o bloco")
                        return
                    }

                    val writeResponse = PosDigital.getInstance().mifare.writeBlock(block,data)

                    if (writeResponse != MifareStatus.SUCCESS) {
                        callback.onFinish("Não foi possível escrever no bloco com esta chave de autenticação")
                        return
                    }

                    val result = PosDigital.getInstance().mifare.readBlock(block)

                    callback.onFinish("write [$result]")
                }

                override fun onError(message: String) {
                    callback.onFinish(message)
                }
            })
        } else {
            Toast.makeText(this, "Todos os parâmetros precisam ser preenchidos", Toast.LENGTH_SHORT).show()
        }
    }
    dialogBuilder.create().show()
    PosDigital.getInstance().mifare.halt()
}


IMPORTANTE: enviar previamente as tags Mifare para a Getnet. Solicitar por e-mail o endereço. Sem as tags, não será possível efetuar os testes e a aplicação será reprovada.


Exemplo de uso exchangeAPDU

Este método disponibiliza a interface ISO14443-4 para o desenvolver acessar cartões sem além do Mifare, por exemplo Cipurse.

PosDigital.getInstance().getMifare().halt()
PosDigital.getInstance().getMifare().searchCard(new IMifareCallback.Stub() {
    @Override
    void onCard(type: Int) {
        try {
            switch(type) {
                case MifareType.PRO_CARD:
                case MifareType.S50_PRO_CARD:
                case MifareType.S70_PRO_CARD:
                    PosDigital.getInstance().getMifare().close();
                    PosDigital.getInstance().getMifare().activate(MifareType.PRO_CARD);
                    APDUResponse res = PosDigital.getInstance().getMifare().exchangeAPDU("00A40000022FF7".toByteArray())
                    Log.d(TAG, String.format("ret:%i sw1:%s sw2:%s", res.getApduRet(), String.format("%02x", res.getSw1()), String.format("%02x", res.getSw2())));
                    break;
                default:
                    Log.e(TAG, "Cartao desconhecido");
            }
        } catch (RemoteException e) {
            Log.e(TAG, String.format("Exception reading on ingenico: ", e.getLocalizedMessage()));
        }
    }

    @Override
    void onError(String error) {
        Log.e(TAG, String.format("Exception reading on ingenico: %s", error));
    }
})
PosDigital.getInstance().mifare.halt()
PosDigital.getInstance().mifare.searchCard(object : IMifareCallback.Stub() {
    override fun onCard(type: Int) {
        try {
            when (type) {
                MifareType.PRO_CARD, MifareType.S50_PRO_CARD, MifareType.S70_PRO_CARD -> {
                    PosDigital.getInstance().mifare.close()
                    PosDigital.getInstance().mifare.activate(MifareType.PRO_CARD)
                    val res = PosDigital.getInstance().mifare.exchangeAPDU("00A40000022FF7".toByteArray())
                    Log.d(TAG, "ret:${res.apduRet} sw1:${res.SW1.toHexStr()} sw2:${res.SW2.toHexStr()}")
                }
                else -> Log.e(TAG, "Cartao desconhecido")
            }
        } catch (e: RemoteException) {
            Log.e(TAG, "Exception reading on ingenico: ${e.localizedMessage}")
        }
    }

    override fun onError(error: String) {
        Log.e(TAG, "Exception reading on ingenico: ${error}")
    }
})