android - 使用 Android Studio 在标签上写入 NFC 数据
问题描述
我正在创建一个应用程序,在该应用程序中,我必须将来自文件的一系列值写入 NFC 卡,我一直在阅读,但我不知道从哪里真正开始,我有一些疑问。
首先,我知道理想的做法是创建一个处理 NFC 的类,尽管我认为这是可选的并且可以在同一个类中完成。问题是我看到的教程仅使用活动并使用 onNewIntent 方法。
在一个片段中我不能调用这个方法,所以这是我失败的第一步,我不知道这个方法是否必要,因为据我所知,这是启动应用程序,即使它像关闭一样关闭读者,如果我错了,请纠正我。如果您能指导我应该做什么,我将不胜感激,因为在阅读了这么多之后,我有点发疯了。
解决方案
我要开始的第一个地方是考虑如何存储数据。
数据是为您的应用程序定制的,还是您想与其他应用程序共享?
应用程序会只写入一次数据还是会更新它(想要将数据附加到存储在卡上的现有数据中?
更新:根据您对数据类型的评论,您可能最好使用更高级别的 NDEF 格式来使用自定义 mime 类型存储您的数据。这是假设您选择的卡类型支持这一点。请注意,我给出的示例是使用低级命令读取/写入逐页读取和写入。
您要存储多少字节的数据(影响卡片技术)
您可能还想考虑要使用哪种 NFC 卡技术,可能是 NTAG 21x 系列卡之一的不错选择。
您要定位的最低 Android 版本是多少?
我不会使用 newIntent 方法,因为这对于写入数据非常不可靠,enableReaderMode
如果您的目标是足够高的 Android 版本,我会使用。
您需要考虑的一些答案会影响示例的一些细节。
更新:基于评论即使您使用的是 Fragments,我仍然会将 NFC 处理机制放在 Activity 中。
这样做的原因是因为操作系统仍在处理标签发现,如果您不在每个片段中“声明”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;
}
}
}
推荐阅读
- mysql - 如何从两个sql查询结果中获取结果
- python - 注册在 jupyter notebook 单元中定义的健身房环境
- linux - 使用 systemd 组织 Kafka 和 Zookeeper 的合作
- html - jquery获取没有摘要的详细信息
- react-native - Coordiantes 的 React Native mapbox 3D 构建亮点
- django - 在同一台服务器上运行两个 Django 站点。带有 Ubuntu 18.04 的 Linode
- android - 我在android studio中删除了我的数据库,现在我无法检索它。我应该怎么办?
- node.js - VSCode launch.json 在子文件夹中调试节点项目
- javascript - 如何停止其中包含 addEventListener 的 forEach:Javascript
- docker - exim-relay docker 容器的自定义 /metrics 端点