当我尝试写入 NFC 标签时出现标签丢失异常
I'm getting a tag lost exception when I try writing to an NFC tag
我希望有人能告诉我我在这里缺少什么。也许这是我的连接方式。我的标签实际上是 Mifare Ultralight,所以我没有弄错。我调试了,连接到标签是成功的——一切似乎都很好。但是日志一直在说:
android.nfc.TagLostException: 标签丢失。
public class MainActivity extends Activity {
NfcAdapter mNfcAdapter;
TextView displayInfo;
Tag mNfcTag;
NdefMessage mNdefMessage;
IntentFilter [] intentFiltersArray;
String [] [] techListsArray;
PendingIntent pendingIntent;
String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
displayInfo = (TextView) findViewById(R.id.displayInfo);
NdefRecord application = NdefRecord.createApplicationRecord("com.studios.nfcdemo");
Locale locale = new Locale("en");
NdefRecord textText = createTextRecord("pleaseWork", locale, true);
mNdefMessage = new NdefMessage(textText);
pendingIntent = PendingIntent.getActivity(
this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
try {
ndef.addDataType("*/*"); /* Handles all MIME based dispatches.
You should specify only the ones that you need. */
}
catch (IntentFilter.MalformedMimeTypeException e) {
throw new RuntimeException("fail", e);
}
intentFiltersArray = new IntentFilter[] {ndef};
techListsArray = new String[][] { new String[] { MifareUltralight.class.getName() } };
}
public NdefRecord createTextRecord(String payload, Locale locale, boolean encodeInUtf8) {
byte[] langBytes = locale.getLanguage().getBytes(Charset.forName("US-ASCII"));
Charset utfEncoding = encodeInUtf8 ? Charset.forName("UTF-8") : Charset.forName("UTF-16");
byte[] textBytes = payload.getBytes(utfEncoding);
int utfBit = encodeInUtf8 ? 0 : (1 << 7);
char status = (char) (utfBit + langBytes.length);
byte[] data = new byte[1 + langBytes.length + textBytes.length];
data[0] = (byte) status;
System.arraycopy(langBytes, 0, data, 1, langBytes.length);
System.arraycopy(textBytes, 0, data, 1 + langBytes.length, textBytes.length);
NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN,
NdefRecord.RTD_TEXT, new byte[0], data);
return record;
}
@Override
public void onNewIntent(Intent intent) {
Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
MifareUltralight ultralight = MifareUltralight.get(tagFromIntent);
write(ultralight);
}
private void write(MifareUltralight lol) {
try{
lol.connect();
lol.writePage(0, "please work".getBytes(Charset.forName("US-ASCII")));
Toast.makeText(this, "Tag written", Toast.LENGTH_LONG).show();
}
catch (Exception e){
Log.d(TAG, "no " + e.toString());
}
finally{
try{
lol.close();
}
catch (Exception e){
Log.d(TAG, e.toString());
}
}
}
public void onPause() {
super.onPause();
mNfcAdapter.disableForegroundDispatch(this);
}
public void onResume() {
super.onResume();
mNfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray);
}
}
您调用 writePage()
方法有两个问题:
MIFARE Ultralight 标签的第 0 页是只读的。您不能写入该页面。这同样适用于第 1 页和第 2 页的部分内容(尽管对第 2 页的写命令应该成功并且将设置锁定位)。
写入命令需要 4 个字节(正好 4 个字节,不多也不少)但您尝试传递 11 个字节("please work"在 US-ASCII 中)。
我发现了我的错误。我想编写 Ndef 消息并使用标签,因为 MifareUltralight 有点傻,因为它只会使一切复杂化。相反,我将标签转换为 Ndef。这是我的代码:
private void write(Tag tag) {
Ndef ndef = Ndef.get(tag);
Locale locale = Locale.ENGLISH;
NdefRecord hi = createTextRecord("hello world", locale, true);
mNdefMessage = new NdefMessage(hi);
try{
ndef.connect();
ndef.writeNdefMessage(mNdefMessage);
Toast.makeText(this, "Message Written", Toast.LENGTH_LONG).show();
}
catch (Exception e){
Log.d(TAG, "Exception: " + e.toString());
}
finally {
try{
ndef.close();
}
catch(Exception e){
Log.d(TAG, ":( no " + e.toString());
}
}
}
如果有人需要弄清楚如何创建文本记录(以 UTF 8 编码)并从 Ndef 支持的标签中读取,我也为这些添加了我的方法:
正在创建文本记录:
public NdefRecord createTextRecord(String payload, Locale locale, boolean encodeInUtf8) {
byte[] langBytes = locale.getLanguage().getBytes(Charset.forName("US-ASCII"));
Charset utfEncoding = encodeInUtf8 ? Charset.forName("UTF-8") : Charset.forName("UTF-16");
byte[] textBytes = payload.getBytes(utfEncoding);
int utfBit = encodeInUtf8 ? 0 : (1 << 7);
char status = (char) (utfBit + langBytes.length);
byte[] data = new byte[1 + langBytes.length + textBytes.length];
data[0] = (byte) status;
System.arraycopy(langBytes, 0, data, 1, langBytes.length);
System.arraycopy(textBytes, 0, data, 1 + langBytes.length, textBytes.length);
NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN,
NdefRecord.RTD_TEXT, new byte[0], data);
return record;
}
正在读取 NDEF 标签:
private void read(Tag tagFromIntent) {
Ndef ndef = Ndef.get(tagFromIntent);
try{
ndef.connect();
mNdefMessage = ndef.getNdefMessage();
NdefRecord [] records = mNdefMessage.getRecords();
byte [] payload = records[0].getPayload();
String displayString = getTextFromNdefRecord(records[0]);
displayInfo.setText(displayString);
Toast.makeText(this, "String read", Toast.LENGTH_LONG).show();
}
catch (Exception e){
Log.d(TAG, e.toString());
}
finally {
try{
ndef.close();
}
catch (Exception e){
Log.d(TAG, e.toString());
}
}
正在从 NdefRecords 读取文本:
public String getTextFromNdefRecord(NdefRecord ndefRecord)
{
String tagContent = null;
try {
byte[] payload = ndefRecord.getPayload();
String textEncoding = "UTF-8";
int languageSize = payload[0] & 0063;
tagContent = new String(payload, languageSize + 1,
payload.length - languageSize - 1, textEncoding);
} catch (UnsupportedEncodingException e) {
Log.e("getTextFromNdefRecord", e.getMessage(), e);
}
return tagContent;
}
我希望这对其他使用 NFC 的人有所帮助。这些简单的方法应该在 Android 内为您提供所需的所有功能。
我希望有人能告诉我我在这里缺少什么。也许这是我的连接方式。我的标签实际上是 Mifare Ultralight,所以我没有弄错。我调试了,连接到标签是成功的——一切似乎都很好。但是日志一直在说:
android.nfc.TagLostException: 标签丢失。
public class MainActivity extends Activity {
NfcAdapter mNfcAdapter;
TextView displayInfo;
Tag mNfcTag;
NdefMessage mNdefMessage;
IntentFilter [] intentFiltersArray;
String [] [] techListsArray;
PendingIntent pendingIntent;
String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
displayInfo = (TextView) findViewById(R.id.displayInfo);
NdefRecord application = NdefRecord.createApplicationRecord("com.studios.nfcdemo");
Locale locale = new Locale("en");
NdefRecord textText = createTextRecord("pleaseWork", locale, true);
mNdefMessage = new NdefMessage(textText);
pendingIntent = PendingIntent.getActivity(
this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
try {
ndef.addDataType("*/*"); /* Handles all MIME based dispatches.
You should specify only the ones that you need. */
}
catch (IntentFilter.MalformedMimeTypeException e) {
throw new RuntimeException("fail", e);
}
intentFiltersArray = new IntentFilter[] {ndef};
techListsArray = new String[][] { new String[] { MifareUltralight.class.getName() } };
}
public NdefRecord createTextRecord(String payload, Locale locale, boolean encodeInUtf8) {
byte[] langBytes = locale.getLanguage().getBytes(Charset.forName("US-ASCII"));
Charset utfEncoding = encodeInUtf8 ? Charset.forName("UTF-8") : Charset.forName("UTF-16");
byte[] textBytes = payload.getBytes(utfEncoding);
int utfBit = encodeInUtf8 ? 0 : (1 << 7);
char status = (char) (utfBit + langBytes.length);
byte[] data = new byte[1 + langBytes.length + textBytes.length];
data[0] = (byte) status;
System.arraycopy(langBytes, 0, data, 1, langBytes.length);
System.arraycopy(textBytes, 0, data, 1 + langBytes.length, textBytes.length);
NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN,
NdefRecord.RTD_TEXT, new byte[0], data);
return record;
}
@Override
public void onNewIntent(Intent intent) {
Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
MifareUltralight ultralight = MifareUltralight.get(tagFromIntent);
write(ultralight);
}
private void write(MifareUltralight lol) {
try{
lol.connect();
lol.writePage(0, "please work".getBytes(Charset.forName("US-ASCII")));
Toast.makeText(this, "Tag written", Toast.LENGTH_LONG).show();
}
catch (Exception e){
Log.d(TAG, "no " + e.toString());
}
finally{
try{
lol.close();
}
catch (Exception e){
Log.d(TAG, e.toString());
}
}
}
public void onPause() {
super.onPause();
mNfcAdapter.disableForegroundDispatch(this);
}
public void onResume() {
super.onResume();
mNfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray);
}
}
您调用 writePage()
方法有两个问题:
MIFARE Ultralight 标签的第 0 页是只读的。您不能写入该页面。这同样适用于第 1 页和第 2 页的部分内容(尽管对第 2 页的写命令应该成功并且将设置锁定位)。
写入命令需要 4 个字节(正好 4 个字节,不多也不少)但您尝试传递 11 个字节("please work"在 US-ASCII 中)。
我发现了我的错误。我想编写 Ndef 消息并使用标签,因为 MifareUltralight 有点傻,因为它只会使一切复杂化。相反,我将标签转换为 Ndef。这是我的代码:
private void write(Tag tag) {
Ndef ndef = Ndef.get(tag);
Locale locale = Locale.ENGLISH;
NdefRecord hi = createTextRecord("hello world", locale, true);
mNdefMessage = new NdefMessage(hi);
try{
ndef.connect();
ndef.writeNdefMessage(mNdefMessage);
Toast.makeText(this, "Message Written", Toast.LENGTH_LONG).show();
}
catch (Exception e){
Log.d(TAG, "Exception: " + e.toString());
}
finally {
try{
ndef.close();
}
catch(Exception e){
Log.d(TAG, ":( no " + e.toString());
}
}
}
如果有人需要弄清楚如何创建文本记录(以 UTF 8 编码)并从 Ndef 支持的标签中读取,我也为这些添加了我的方法:
正在创建文本记录:
public NdefRecord createTextRecord(String payload, Locale locale, boolean encodeInUtf8) {
byte[] langBytes = locale.getLanguage().getBytes(Charset.forName("US-ASCII"));
Charset utfEncoding = encodeInUtf8 ? Charset.forName("UTF-8") : Charset.forName("UTF-16");
byte[] textBytes = payload.getBytes(utfEncoding);
int utfBit = encodeInUtf8 ? 0 : (1 << 7);
char status = (char) (utfBit + langBytes.length);
byte[] data = new byte[1 + langBytes.length + textBytes.length];
data[0] = (byte) status;
System.arraycopy(langBytes, 0, data, 1, langBytes.length);
System.arraycopy(textBytes, 0, data, 1 + langBytes.length, textBytes.length);
NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN,
NdefRecord.RTD_TEXT, new byte[0], data);
return record;
}
正在读取 NDEF 标签:
private void read(Tag tagFromIntent) {
Ndef ndef = Ndef.get(tagFromIntent);
try{
ndef.connect();
mNdefMessage = ndef.getNdefMessage();
NdefRecord [] records = mNdefMessage.getRecords();
byte [] payload = records[0].getPayload();
String displayString = getTextFromNdefRecord(records[0]);
displayInfo.setText(displayString);
Toast.makeText(this, "String read", Toast.LENGTH_LONG).show();
}
catch (Exception e){
Log.d(TAG, e.toString());
}
finally {
try{
ndef.close();
}
catch (Exception e){
Log.d(TAG, e.toString());
}
}
正在从 NdefRecords 读取文本:
public String getTextFromNdefRecord(NdefRecord ndefRecord)
{
String tagContent = null;
try {
byte[] payload = ndefRecord.getPayload();
String textEncoding = "UTF-8";
int languageSize = payload[0] & 0063;
tagContent = new String(payload, languageSize + 1,
payload.length - languageSize - 1, textEncoding);
} catch (UnsupportedEncodingException e) {
Log.e("getTextFromNdefRecord", e.getMessage(), e);
}
return tagContent;
}
我希望这对其他使用 NFC 的人有所帮助。这些简单的方法应该在 Android 内为您提供所需的所有功能。