I m creating an android app in java using nfc technology to read a nfc tag. I ve wrote a simple text on it thank to another app downloaded from play store, but I cant manage to make my app read that simple text.
- I inserted in the manifest permission to use NFC to the app
- I inserted intent filters for both nfc action NDEF and TAG. My tag results being able to use NfcA, MifareUltralight, Ndef according to the external NFC app I used
- Specified that my tag should contain MIME type text/plain
Here s the manifest
<?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-sdk android:minSdkVersion="31"/>
<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.AppCompat.DayNight"
tools:targetApi="31">
<activity
android:name="com.example.nfcreader.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.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" /> <!-- Adatta il MIME type se necessario -->
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
about the java code
- I created the NfcAdapter in onCreate()
- Created an IntentFilter[] with both ACTION_NDEF_DISCOVERED, and ACTION_TAG_DISCOVERED in a separated function createNFCIntentFilter() that I call in onResume()
- Handled Intents at the start of onResume()
- Applied enableForegroundDispatch() and disableForegroundDispatch() rispectevely in onResume() and onPause() to get the reading work just when the app is active
- Added Log.d to check the if the onNewIntent triggers, the type of Intent, and if the Intent contains something at all. In order: the onNewIntent triggers, the type is null, and neither NDEF nor TAG action is detected.
Looks like I m getting something wrong with the filters. Any suggestion?
Here s the java code
package com.example.nfcreader;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
import android.widget.Toast;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
public class MainActivity extends AppCompatActivity {
private NfcAdapter nfcAdapter;
private PendingIntent pendingIntent;
private IntentFilter[] nfcFilters;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
// Ottieni l'adattatore NFC
nfcAdapter = NfcAdapter.getDefaultAdapter(this);
}
@Override
protected void onResume() {
super.onResume();
// Configura un PendingIntent per gestire gli intent NFC
pendingIntent = PendingIntent.getActivity(
this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), PendingIntent.FLAG_IMMUTABLE);
// Richiama la funzione per ottenere i filtri NFC
nfcFilters = createNFCIntentFilter();
// Registra la modalità foreground dispatch per intercettare gli intent NFC quando l'app è in primo piano
if (nfcAdapter != null) {
nfcAdapter.enableForegroundDispatch(this, pendingIntent, nfcFilters, null);
Log.d("mytag", "Foreground dispatch enabled");
}
}
@Override
protected void onPause() {
super.onPause();
// Disabilita il foreground dispatch quando l'app non è in primo piano
if (nfcAdapter != null) {
nfcAdapter.disableForegroundDispatch(this);
}
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
// Gestisci l'intent NFC qui
String action = intent.getAction();
Log.d("mytag", "Intent Action: " + action);
if (action != null) {
switch (action) {
case NfcAdapter.ACTION_NDEF_DISCOVERED:
Log.d("mytag", "ACTION_NDEF_DISCOVERED detected");
break;
case NfcAdapter.ACTION_TAG_DISCOVERED:
Log.d("mytag", "ACTION_TAG_DISCOVERED detected");
break;
default:
Log.d("mytag", "Unknown NFC action: " + action);
break;
}
} else {
Log.d("mytag", "No NFC action detected");
}
/*if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
Log.d("mytag", "trovato nuovo intent");
Parcelable[] rawMessages = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if (rawMessages != null) {
Log.d("mytag", "il messaggio era non nullo");
NdefMessage[] messages = new NdefMessage[rawMessages.length];
for (int i = 0; i < rawMessages.length; i++) {
messages[i] = (NdefMessage) rawMessages[i];
}
// Ora puoi accedere ai record all'interno del messaggio NDEF
for (NdefMessage message : messages) {
NdefRecord[] records = message.getRecords();
for (NdefRecord record : records) {
// Processa ogni record, ad esempio, leggi un URI o un testo
if (record.getTnf() == NdefRecord.TNF_WELL_KNOWN &&
Arrays.equals(record.getType(), NdefRecord.RTD_TEXT)) {
byte[] payload = record.getPayload();
String text = new String(payload, StandardCharsets.UTF_8);
// Usa il testo letto dal record NDEF
Toast toast=Toast.makeText(getApplicationContext(),text,Toast.LENGTH_SHORT);
toast.show();
}
}
}
}
} else if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
Log.d("mytag", "Intent Action ACTION: " + intent.getAction());
}*/
}
private IntentFilter[] createNFCIntentFilter() {
IntentFilter ndefFilter = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
IntentFilter tagFilter = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
try {
ndefFilter.addDataType("text/plain");
} catch (IntentFilter.MalformedMimeTypeException e) {
throw new RuntimeException("Failed to add MIME type.", e);
}
return new IntentFilter[]{ndefFilter, tagFilter};
}
}
1