我首先要考虑如何存储数据。
数据是为您的应用定制的,还是您想与其他应用共享?
应用程序会只写入一次数据还是会更新它(想要将数据附加到存储在卡上的现有数据中?
更新:来自您的 cmets 关于数据类型的信息,您可能最好使用更高级别的 NDEF 格式来使用自定义 mime 类型存储您的数据。这是假设您选择的卡类型支持这一点。
请注意,我给出的示例是使用低级命令读取/写入逐页读取和写入。
你要存储多少字节的数据(影响卡片技术)
您可能还想考虑要使用哪种 NFC 卡技术,可能是 NTAG 21x 系列卡之一的不错选择。
您要定位的最低 Android 版本是多少?
我不会使用 newIntent 方法,因为这对于写入数据非常不可靠,如果您的目标是足够高的 Android 版本,我会使用 enableReaderMode。
https://developer.android.com/reference/android/nfc/NfcAdapter.html#enableReaderMode(android.app.Activity,%20android.nfc.NfcAdapter.ReaderCallback,%20int,%20android.os.Bundle)
您需要考虑的一些答案会影响示例的一些细节。
更新:基于 cmets 即使您使用的是 Fragments,我仍然会将 NFC 处理机制放在 Activity 中。
这是因为操作系统仍在处理标签发现,如果您不在每个 Fragment 中“声明”NFC 硬件,那么特别是对于 NDEF 数据格式,操作系统可能会显示一个屏幕如果用户在错误的时间出示卡片,则会给您的应用程序带来糟糕的用户体验。
在我的多 Activity 应用程序中,我在每个 Activity 中“声明”了 NFC 硬件,即使其中很多都执行“发现标签时,什么也不做”,因为它们不是 NFC Activity。
因此,除非您想在每个 Fragment 中编写相同的代码,否则最好从您的一个 Activity 中调用 NFC 内容,然后在 onTagDiscovered 中执行类似(伪代码)的操作:-
更新:
if displaying the NFC user prompt Fragment.
get data to file.
write data to the card.
Notify user that it is done.
else
do nothing when other fragments are displayed.
或者你可以在应用打开的任何时候写卡片(最好还是在活动中而不是在任何片段中完成)
If card is presented no matter what fragment is being display
get data from the file
write data to the card
Notify user that it is done.
抱歉,我无法在 Kotlin 中做示例,但这里是 Java 示例的准系统,从我的应用程序中提取(未经测试,因此可能存在复制和粘贴错误)
public class MainActivity extends AppCompatActivity implements NfcAdapter.ReaderCallback{
private NfcAdapter mNfcAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
// All normal onCreate Stuff
// Listen to NFC setting changes
this.registerReceiver(mReceiver, filter);
}
// Listen for NFC being turned on while in the App
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED)) {
final int state = intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE,
NfcAdapter.STATE_OFF);
switch (state) {
case NfcAdapter.STATE_OFF:
// Tell the user to turn NFC on if App requires it
break;
case NfcAdapter.STATE_TURNING_OFF:
break;
case NfcAdapter.STATE_ON:
enableNfc();
break;
case NfcAdapter.STATE_TURNING_ON:
break;
}
}
}
};
@Override
protected void onResume() {
super.onResume();
enableNfc();
}
@Override
protected void onPause() {
super.onPause();
if(mNfcAdapter!= null)
mNfcAdapter.disableReaderMode(this);
}
private void enableNfc(){
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
if(mNfcAdapter!= null && mNfcAdapter.isEnabled()) {
// Work around some buggy hardware that checks for cards too fast
Bundle options = new Bundle();
options.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, 1000);
// Listen for all types of card when this App is in the foreground
// Turn platform sounds off as they misdirect users when writing to the card
// Turn of the platform decoding any NDEF data
mNfcAdapter.enableReaderMode(this,
this,
NfcAdapter.FLAG_READER_NFC_A |
NfcAdapter.FLAG_READER_NFC_B |
NfcAdapter.FLAG_READER_NFC_F |
NfcAdapter.FLAG_READER_NFC_V |
NfcAdapter.FLAG_READER_NFC_BARCODE |
NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK |
NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS,
options);
} else {
// Tell the user to turn NFC on if App requires it
}
}
public void onTagDiscovered(Tag tag) {
// This is run in a separate Thread to UI
StringBuilder Uid = new StringBuilder();
boolean successUid = getUID(tag, Uid);
if (!successUid){
// Not a successful read
return;
} else {
// Feedback to user about successful read
Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
v.vibrate(500);
runOnUiThread(new Runnable() {
@Override
public void run() {
// Update the UI / notify user
}
});
// Finish Task
try {
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone r = RingtoneManager.getRingtone(getApplicationContext(), notification);
r.play();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public boolean getUID(Tag tag, StringBuilder Uid){
NfcA mNfcA = NfcA.get(tag);
if (mNfcA != null) {
// The tag is NfcA capable
try {
mNfcA.connect();
// Do a Read operation at page 0 an 1
byte[] result = mNfcA.transceive(new byte[] {
(byte)0x3A, // FAST_READ
(byte)(0 & 0x0ff),
(byte)(1 & 0x0ff),
});
if (result == null) {
// either communication to the tag was lost or a NACK was received
// Log and return
return false;
} else if ((result.length == 1) && ((result[0] & 0x00A) != 0x00A)) {
// NACK response according to Digital Protocol/T2TOP
// Log and return
return false;
} else {
// success: response contains ACK or actual data
for (int i = 0; i < result.length; i++) {
// byte 4 is a check byte
if (i == 3) continue;
Uid.append(String.format("%02X ", result[i]));
}
// Close and return
try {
mNfcA.close();
} catch (IOException e) {
}
return true;
}
} catch (TagLostException e) {
// Log and return
return false;
} catch (IOException e){
// Log and return
return false;
} finally {
try {
mNfcA.close();
} catch (IOException e) {
}
}
} else {
// Log error
return false;
}
}
}