I'm working on an app to write NFC tag in Android Studio. My code:
public class MainActivity extends AppCompatActivity {
public static final String Error_dected = "No NFC Tag Detected";
public static final String Write_Success = "Text Written Succesfully";
public static final String Write_Error = "Error during writtin, Try again";
NfcAdapter nfcAdapter;
PendingIntent pendingIntent;
IntentFilter writingTagFilters[];
boolean writeMode;
Tag myTag;
Context context;
EditText edit_message;
TextView nfc_contents;
Button ActivateButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edit_message = (EditText) findViewById(R.id.edit_message);
nfc_contents = (TextView) findViewById(R.id.nfc_content);
ActivateButton = (Button) findViewById(R.id.ActivateButton);
context = this;
ActivateButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String mensaje=edit_message.getText().toString();
try {
if (myTag == null) {
Toast.makeText(context, Error_dected, Toast.LENGTH_LONG).show();
} else {
write("PlainText|" + edit_message.getText().toString(), myTag);
Toast.makeText(context, Write_Success, Toast.LENGTH_LONG).show();
}
} catch (IOException e) {
Toast.makeText(context, Write_Error, Toast.LENGTH_LONG).show();
e.printStackTrace();
} catch (FormatException e) {
Toast.makeText(context, Write_Error, Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
});
nfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (nfcAdapter == null) {
Toast.makeText(this, "this device does not support NFC", Toast.LENGTH_LONG).show();
}
readfromIntent(getIntent());
pendingIntent = pendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
tagDetected.addCategory(Intent.CATEGORY_DEFAULT);
writingTagFilters = new IntentFilter[]{tagDetected};
}
public void readfromIntent(Intent intent) {
String action = intent.getAction();
if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)
|| NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)
|| NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
Parcelable[] rawMsg = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
NdefMessage[] msgs = null;
if (rawMsg != null) {
msgs = new NdefMessage[rawMsg.length];
for (int i = 0; i < rawMsg.length; i++) {
msgs[i] = (NdefMessage) rawMsg[i];
}
buildTagView(msgs);
}
}
}
private void buildTagView(NdefMessage[] msgs) {
if (msgs == null || msgs.length == 0) return;
String text = "";
byte[] payload = msgs[0].getRecords()[0].getPayload();
String textEncodgin = ((payload[0] & 128) == 0) ? "UTF-8" : "UTF-16"; //Get the text encoding
int languageCodeLength = payload[0] & 0063;
try {
text = new String(payload, languageCodeLength + 1, payload.length - languageCodeLength - 1, textEncodgin);
} catch (UnsupportedEncodingException e) {
Log.e("UnsupportedEncoding", e.toString());
}
nfc_contents.setText("NFC Content: " + text);
}
private void write(String text, Tag tag) throws IOException, FormatException {
NdefRecord[] records = {createRecord(text)};
NdefMessage message = new NdefMessage(records);
//Get an instance os Ndef for the tag
Ndef ndef = Ndef.get(tag);
//Enable I/0
ndef.connect();
//Write the message
ndef.writeNdefMessage(message);
//Clase de connection
ndef.close();
}
private NdefRecord createRecord(String text) throws UnsupportedEncodingException {
String lang ="en";
byte[] textBytes=text.getBytes();
byte[] langBytes=lang.getBytes("US-ASCII");
int langLength=langBytes.length;
int textLength=textBytes.length;
byte[] payload =new byte[1+langLength+textLength];
//set status byte (see NDEF spec for actual bits
payload[0]= (byte) langLength;
//copy langbytes and textbytes into payload
System.arraycopy(langBytes,0,payload,1,langLength);
System.arraycopy(textBytes,0,payload,1+langLength,textLength);
NdefRecord recordNFC =new NdefRecord(NdefRecord.TNF_WELL_KNOWN,NdefRecord.RTD_TEXT,new byte[0],payload);
return recordNFC;
}
@Override
protected void onNewIntent(Intent intent)
{
super.onNewIntent(intent);
setIntent(intent);
readfromIntent(intent);
if(NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction()))
{
myTag=intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
}
}
@Override
public void onPause()
{
super.onPause();
WriteModeOff();
}
@Override
public void onResume()
{
super.onResume();
WriteModeOn();
}
/********ENABLE WRITE*****/
private void WriteModeOn()
{
writeMode=true;
nfcAdapter.enableForegroundDispatch(this,pendingIntent,writingTagFilters,null);
}
/*******DISABLE WRITE*****/
private void WriteModeOff()
{
writeMode=false;
nfcAdapter.disableForegroundDispatch(this);
}
}
When I run it and try to write in a NFC tag I always get myTag==null so I'm always here:
if (myTag == null) { Toast.makeText(context, Error_dected, Toast.LENGTH_LONG).show();
I've modified the user-permission in "android.Manifest" Any idea of what is happening? Thank you
The only starting point for any NFC operation is when the System NFC App gives you a Tag
object as a starting point to interact with the NFC Tag it has detected.
There are a number of ways to do that and enableForgroundDispatch
is one method you are already using, But in real life usage this is very unreliable way to work with NFC and will lead to lots of write errors and corrupted data on NFC Tags.
Much better method is to use the newer API enableReaderMode
and an example of that is found at https://stackoverflow.com/a/64921434/2373819 and it explains why it is better.
But for both API's all your interaction with the Tag needs to be done when a Tag is detected and you are notified a Tag has come in to range (for the current API you are using that is in onNewIntent
)
So a simple way to handle this when the user clicks the ActivateButton
is to set a global boolean to indicate the next time a Tag
is detected you should write to it instead of trying to read from it (and you would store the string to write in a global String as well)
Below is some code changes that give you the idea BUT this is a bare bones example as it does not show any UI changes to prompt the user to bring an NFC card in to range and it does not cover any re-tries you might need to successfully write to an NFC card.
public class MainActivity extends AppCompatActivity {
public static final String Error_dected = "No NFC Tag Detected";
public static final String Write_Success = "Text Written Succesfully";
public static final String Write_Error = "Error during writtin, Try again";
NfcAdapter nfcAdapter;
PendingIntent pendingIntent;
IntentFilter writingTagFilters[];
boolean writeMode;
Tag myTag;
Context context;
EditText edit_message;
TextView nfc_contents;
Button ActivateButton;
//New code below
boolean someThingToWrite;
String stringToWrite;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edit_message = (EditText) findViewById(R.id.edit_message);
nfc_contents = (TextView) findViewById(R.id.nfc_content);
ActivateButton = (Button) findViewById(R.id.ActivateButton);
context = this;
ActivateButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Changed Code
stringToWrite = edit_message.getText().toString();
someThingToWrite = true;
});
nfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (nfcAdapter == null) {
Toast.makeText(this, "this device does not support NFC", Toast.LENGTH_LONG).show();
}
readfromIntent(getIntent());
pendingIntent = pendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
tagDetected.addCategory(Intent.CATEGORY_DEFAULT);
writingTagFilters = new IntentFilter[]{tagDetected};
}
public void readfromIntent(Intent intent) {
String action = intent.getAction();
if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)
|| NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)
|| NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
Parcelable[] rawMsg = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
NdefMessage[] msgs = null;
if (rawMsg != null) {
msgs = new NdefMessage[rawMsg.length];
for (int i = 0; i < rawMsg.length; i++) {
msgs[i] = (NdefMessage) rawMsg[i];
}
buildTagView(msgs);
}
}
}
private void buildTagView(NdefMessage[] msgs) {
if (msgs == null || msgs.length == 0) return;
String text = "";
byte[] payload = msgs[0].getRecords()[0].getPayload();
String textEncodgin = ((payload[0] & 128) == 0) ? "UTF-8" : "UTF-16"; //Get the text encoding
int languageCodeLength = payload[0] & 0063;
try {
text = new String(payload, languageCodeLength + 1, payload.length - languageCodeLength - 1, textEncodgin);
} catch (UnsupportedEncodingException e) {
Log.e("UnsupportedEncoding", e.toString());
}
nfc_contents.setText("NFC Content: " + text);
}
private void write(String text, Tag tag) throws IOException, FormatException {
NdefRecord[] records = {createRecord(text)};
NdefMessage message = new NdefMessage(records);
//Get an instance os Ndef for the tag
Ndef ndef = Ndef.get(tag);
//Enable I/0
ndef.connect();
//Write the message
ndef.writeNdefMessage(message);
//Clase de connection
ndef.close();
}
private NdefRecord createRecord(String text) throws UnsupportedEncodingException {
String lang ="en";
byte[] textBytes=text.getBytes();
byte[] langBytes=lang.getBytes("US-ASCII");
int langLength=langBytes.length;
int textLength=textBytes.length;
byte[] payload =new byte[1+langLength+textLength];
//set status byte (see NDEF spec for actual bits
payload[0]= (byte) langLength;
//copy langbytes and textbytes into payload
System.arraycopy(langBytes,0,payload,1,langLength);
System.arraycopy(textBytes,0,payload,1+langLength,textLength);
NdefRecord recordNFC =new NdefRecord(NdefRecord.TNF_WELL_KNOWN,NdefRecord.RTD_TEXT,new byte[0],payload);
return recordNFC;
}
@Override
protected void onNewIntent(Intent intent)
{
super.onNewIntent(intent);
//New code
if(someThingToWrite) {
// Is it an NDEF tag
if(NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction()))
{
myTag=intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
write("PlainText|" + stringToWrite, myTag);
// Don't want to continue with reading so return
return;
}
// Really should handle NDEF formatable tags as well
// Just in case it's a blank unformatted tag
// but that is relevant for this example.
}
setIntent(intent);
readfromIntent(intent);
if(NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction()))
{
myTag=intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
}
}
@Override
public void onPause()
{
super.onPause();
WriteModeOff();
}
@Override
public void onResume()
{
super.onResume();
WriteModeOn();
}
/********ENABLE WRITE*****/
private void WriteModeOn()
{
writeMode=true;
nfcAdapter.enableForegroundDispatch(this,pendingIntent,writingTagFilters,null);
}
/*******DISABLE WRITE*****/
private void WriteModeOff()
{
writeMode=false;
nfcAdapter.disableForegroundDispatch(this);
}
}
I quite like instead of setting a flag to say on next Tag
detection to write to Tag to actually create a new Activity just to handle the UI and re-try logic and Tag
writing, this keeps the logic cleaner and is re-useable in other parts of your App.
Then your ActivateButton.setOnClickListener
just starts the new Activity and passes it the string to write via the Intent.
Note I can you you have been copying and pasting code from poor examples on the web because you use the WriteModeOn
and WriteModeOff
method:-)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.