问题
Hey guys im testing NFC and i have an issue with i think it is formating..
I added a string value in the tag with an app to write.
when i scan it with that same store app it shows ok...
when i scan with my app it shows the correct name in the app but adds a "en" before the message..
and a white space.. so if i add a name in the tag then scan and get a API it shows 404 cause there is an en and white space..
http://myapisite.com/API/getdevice.php?id= enTagString
before the = space and then en before the id or even name i put..
i tried a few ways..
public class MainActivity extends Activity {
// list of NFC technologies detected:
private final String[][] techList = new String[][]{
new String[]{
NfcA.class.getName (),
NfcB.class.getName (),
NfcF.class.getName (),
NfcV.class.getName (),
IsoDep.class.getName (),
MifareClassic.class.getName (),
MifareUltralight.class.getName (), Ndef.class.getName ()
}
};
private TextView mTextView;
private ImageView mImageView;
private String ID, machineName, MachineImg, MachinePart, level;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate (savedInstanceState);
setContentView (R.layout.activity_main);
mImageView = findViewById (R.id.imageView);
mTextView = findViewById (R.id.textView_explanation);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater ().inflate (R.menu.menu, menu);
return true;
}
@Override
protected void onResume() {
super.onResume ();
PendingIntent pendingIntent = PendingIntent.getActivity (this, 0, new Intent (this, getClass ()).addFlags (Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
// creating intent receiver for NFC events:
IntentFilter filter = new IntentFilter ();
filter.addAction (NfcAdapter.ACTION_TAG_DISCOVERED);
filter.addAction (NfcAdapter.ACTION_NDEF_DISCOVERED);
filter.addAction (NfcAdapter.ACTION_TECH_DISCOVERED);
// enabling foreground dispatch for getting intent from NFC event:
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter (this);
nfcAdapter.enableForegroundDispatch (this, pendingIntent, new IntentFilter[]{filter}, this.techList);
}
@Override
protected void onPause() {
super.onPause ();
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter (this);
nfcAdapter.disableForegroundDispatch (this);
}
void parseNdefMessage(Intent intent) {
Parcelable[] ndefMessageArray = intent.getParcelableArrayExtra (
NfcAdapter.EXTRA_NDEF_MESSAGES);
NdefMessage ndefMessage = (NdefMessage) ndefMessageArray[0];
String text = new String (ndefMessage.getRecords ()[0].getPayload ());
Log.d (TAG, "PAYLOAD MESS" + text);
ID = text;
getApiInfos ();
}
@Override
protected void onNewIntent(Intent intent) {
parseNdefMessage (intent);
if (intent.getAction ().equals (NfcAdapter.ACTION_TAG_DISCOVERED)) {
mTextView.setText ("NFC Tag\n" + ByteArrayToHexString (intent.getByteArrayExtra (NfcAdapter.EXTRA_ID)));
Parcelable tagN = intent.getParcelableExtra (NfcAdapter.EXTRA_TAG);
if (tagN != null) {
NdefMessage[] msgs;
byte[] empty = new byte[0];
byte[] id = intent.getByteArrayExtra (NfcAdapter.EXTRA_ID);
byte[] payload = dumpTagData (tagN).getBytes ();
NdefRecord record = new NdefRecord (NdefRecord.TNF_UNKNOWN, empty, id, payload);
NdefMessage msg = new NdefMessage (new NdefRecord[]{record});
msgs = new NdefMessage[]{msg};
Log.d (TAG, msgs[0].toString ());
} else {
Log.d (TAG, "Parcelable NULL");
}
Parcelable[] messages1 = intent.getParcelableArrayExtra (NfcAdapter.EXTRA_NDEF_MESSAGES);
if (messages1 != null) {
Log.d (TAG, "Found " + messages1.length + " NDEF messages");
for (int i = 0; i < messages1.length; ++i) {
Log.d (TAG, "Found M " + messages1[i].toString ());
}
} else {
Log.d (TAG, "Not EXTRA_NDEF_MESSAGES");
}
Tag tag = intent.getParcelableExtra (NfcAdapter.EXTRA_TAG);
Ndef ndef = Ndef.get (tag);
if (ndef != null) {
Parcelable[] messages = intent.getParcelableArrayExtra (NfcAdapter.EXTRA_NDEF_MESSAGES);
if (messages != null) {
Log.d (TAG, "Found " + messages.length + " NDEF messages");
}
} else {
Log.d (TAG, "Write to an unformatted tag not implemented");
}
}
}
private String dumpTagData(Parcelable p) {
StringBuilder sb = new StringBuilder ();
Tag tag = (Tag) p;
byte[] id = tag.getId ();
sb.append ("Tag ID (hex): ").append (getHex (id)).append ("\n");
sb.append ("Tag ID (dec): ").append (getDec (id)).append ("\n");
sb.append ("ID (reversed): ").append (getReversed (id)).append ("\n");
String prefix = "android.nfc.tech.";
sb.append ("Technologies: ");
for (String tech : tag.getTechList ()) {
sb.append (tech.substring (prefix.length ()));
sb.append (", ");
}
sb.delete (sb.length () - 2, sb.length ());
for (String tech : tag.getTechList ()) {
if (tech.equals (MifareClassic.class.getName ())) {
sb.append ('\n');
MifareClassic mifareTag = MifareClassic.get (tag);
String type = "Unknown";
switch (mifareTag.getType ()) {
case MifareClassic.TYPE_CLASSIC:
type = "Classic";
break;
case MifareClassic.TYPE_PLUS:
type = "Plus";
break;
case MifareClassic.TYPE_PRO:
type = "Pro";
break;
}
sb.append ("Mifare Classic type: ");
sb.append (type);
sb.append ('\n');
sb.append ("Mifare size: ");
sb.append (mifareTag.getSize () + " bytes");
sb.append ('\n');
sb.append ("Mifare sectors: ");
sb.append (mifareTag.getSectorCount ());
sb.append ('\n');
sb.append ("Mifare blocks: ");
sb.append (mifareTag.getBlockCount ());
}
if (tech.equals (MifareUltralight.class.getName ())) {
sb.append ('\n');
MifareUltralight mifareUlTag = MifareUltralight.get (tag);
String type = "Unknown";
switch (mifareUlTag.getType ()) {
case MifareUltralight.TYPE_ULTRALIGHT:
type = "Ultralight";
break;
case MifareUltralight.TYPE_ULTRALIGHT_C:
type = "Ultralight C";
break;
}
sb.append ("Mifare Ultralight type: ");
sb.append (type);
}
}
DateFormat TIME_FORMAT = SimpleDateFormat.getDateTimeInstance ();
Date now = new Date ();
mTextView.setText (TIME_FORMAT.format (now) + '\n' + sb.toString ());
return sb.toString ();
}
private String getHex(byte[] bytes) {
StringBuilder sb = new StringBuilder ();
for (int i = bytes.length - 1; i >= 0; --i) {
int b = bytes[i] & 0xff;
if (b < 0x10)
sb.append ('0');
sb.append (Integer.toHexString (b));
if (i > 0) {
sb.append (" ");
}
}
return sb.toString ();
}
private long getDec(byte[] bytes) {
long result = 0;
long factor = 1;
for (int i = 0; i < bytes.length; ++i) {
long value = bytes[i] & 0xffl;
result += value * factor;
factor *= 256l;
}
return result;
}
private long getReversed(byte[] bytes) {
long result = 0;
long factor = 1;
for (int i = bytes.length - 1; i >= 0; --i) {
long value = bytes[i] & 0xffl;
result += value * factor;
factor *= 256l;
}
return result;
}
private String ByteArrayToHexString(byte[] inarray) {
int i, j, in;
String[] hex = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"};
String out = "";
for (j = 0; j < inarray.length; ++j) {
in = (int) inarray[j] & 0xff;
i = (in >> 4) & 0x0f;
out += hex[i];
i = in & 0x0f;
out += hex[i];
}
Log.d ("ByteArrayToHexString", String.format ("%0" + (inarray.length * 2) + "X", new BigInteger (1, inarray)));
return out;
}
enter code here
回答1:
Most likely this is because the App writing is storing it as a "WELL_KNOWN" type of text/plain
The specs for NFC Text format can be found at NFCForum-TS-RTD_Text_1.0.pdf.
The extra characters in the payload are as below:
- language length (1 byte) + language (n bytes) + Text
So the space is the actually a non printable size of the language.
The "en" is defining that the text is English.
https://developer.android.com/reference/android/nfc/NdefRecord#getPayload() returns a byte array.
So below should work to trim it (tested) as there don't seem to be nice helper methods to decode it, only create this format.
// Create Test Record
NdefRecord record = NdefRecord.createTextRecord("en", "Hello");
//Get Bytes of payload
// byte[] payload = ndefMessage.getRecords ()[0].getPayload ();
// Get Bytes of test NDEF Record
byte[] payload = record.getPayload ();
// Read First Byte and then trim off the right length
byte[] textArray = Arrays.copyOfRange(payload, (int) payload[0] + 1 , payload.length);
// Convert to Text
String text = new String(textArray);
UPDATE: As the code given in the question is a bit of a mess and you do things you don't need to do and don't do things you do need to do (e.g. you have asked to be sent data from cards that won't have NDef data in them and then you parse for Ndef data without checking there is some data to parse)
I've simplified the code just to read a text NDEF record (Note not tested, but based on how I used to read NDEF data, I now use a better method to read cards that is more reliable especially if you want to write to cards as well)
public class MainActivity extends Activity {
private TextView mTextView;
private ImageView mImageView;
private String ID, machineName, MachineImg, MachinePart, level;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = findViewById(R.id.imageView);
mTextView = findViewById(R.id.textView_explanation);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu, menu);
return true;
}
@Override
protected void onResume() {
super.onResume();
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
// creating intent receiver for NFC events:
IntentFilter filter = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
// enabling foreground dispatch for getting intent from NFC event:
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
nfcAdapter.enableForegroundDispatch(this, pendingIntent, new IntentFilter[]{filter}, null);
}
@Override
protected void onPause() {
super.onPause();
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
nfcAdapter.disableForegroundDispatch(this);
}
void parseNdefMessage(Intent intent) {
Parcelable[] ndefMessageArray = intent.getParcelableArrayExtra(
NfcAdapter.EXTRA_NDEF_MESSAGES);
// Test if there is actually a NDef message passed via the Intent
if (ndefMessageArray != null) {
NdefMessage ndefMessage = (NdefMessage) ndefMessageArray[0];
//Get Bytes of payload
byte[] payload = ndefMessage.getRecords()[0].getPayload();
// Read First Byte and then trim off the right length
byte[] textArray = Arrays.copyOfRange(payload, (int) payload[0] + 1, payload.length);
// Convert to Text
String text = new String(textArray);
ID = text;
getApiInfos();
}
}
@Override
protected void onNewIntent(Intent intent) {
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
parseNdefMessage(intent);
}
}
}
回答2:
Ok thx to @Andrew i used part of your code and adapted it to my tests.. it works great now i can clean it up and removed what is not used or needed.Thx happy holidays!:)
void parseNdefMessage(Intent intent) {
Parcelable[] ndefMessageArray = intent.getParcelableArrayExtra(
NfcAdapter.EXTRA_NDEF_MESSAGES);
// Test if there is actually a NDef message passed via the Intent
if (ndefMessageArray != null) {
NdefMessage ndefMessage = (NdefMessage) ndefMessageArray[0];
//Get Bytes of payload
byte[] payload = ndefMessage.getRecords()[0].getPayload();
// Read First Byte and then trim off the right length
byte[] textArray = Arrays.copyOfRange(payload, (int) payload[0] + 1, payload.length);
// Convert to Text
String text = new String(textArray);
ID = text;
getApiInfos();
}
}
来源:https://stackoverflow.com/questions/59515271/why-android-nfc-reader-adds-en-before-the-message