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}")
}
})