[英]I have a problem writting NFC Tag in Android
我正在開發一個在 Android Studio 中編寫 NFC 標簽的應用程序。 我的代碼:
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);
}
}
當我運行它並嘗試寫入 NFC 標簽時,我總是得到 myTag==null 所以我總是在這里:
if (myTag == null) { Toast.makeText(context, Error_dected, Toast.LENGTH_LONG).show();
我已經修改了“android.Manifest”中的用戶權限知道發生了什么嗎? 謝謝
任何 NFC 操作的唯一起點是系統 NFC 應用程序為您提供Tag
object 作為與它檢測到的 NFC 標簽交互的起點。
有很多方法可以做到這一點,而enableForgroundDispatch
是您已經在使用的一種方法,但在實際使用中,這是使用 NFC 的非常不可靠的方式,並且會導致大量寫入錯誤和 NFC 標簽上的數據損壞。
更好的方法是使用較新的 API enableReaderMode
,在https://stackoverflow.com/a/64921434/2373819中找到了一個示例,它解釋了為什么它更好。
但是對於這兩個 API,當檢測到標簽並通知您標簽已進入范圍時,您與標簽的所有交互都需要完成(對於您正在使用的當前 API,它位於onNewIntent
中)
因此,當用戶單擊ActivateButton
時,處理此問題的一種簡單方法是設置全局 boolean 以指示下次檢測到Tag
時您應該寫入它而不是嘗試從中讀取(並且您將存儲要寫入的字符串一個全局字符串)
下面是一些代碼更改,可以讓您了解但這是一個簡單的示例,因為它沒有顯示任何 UI 更改以提示用戶將 NFC 卡帶入范圍,並且它不包括您可能需要的任何重試成功寫入 NFC 卡。
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);
}
}
我非常喜歡在下一個Tag
檢測時設置一個標志來寫入標簽以實際創建一個新的 Activity 只是為了處理 UI 並重試邏輯和Tag
寫入,這樣可以保持邏輯更清晰並且可以在其他情況下重復使用應用程序的一部分。
然后您的ActivateButton.setOnClickListener
只是啟動新的 Activity 並將字符串傳遞給它以通過 Intent 寫入。
請注意,您是否一直在從 web 上的不良示例中復制和粘貼代碼,因為您使用的是WriteModeOn
和WriteModeOff
方法:-)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.