Android NFC开发之读取NDEF格式数据
在上一篇文章Android NFC开发之写入NDEF格式数据中我们介绍了如何往NFC标签中写入NDEF格式的数据
今天这篇文章介绍如何读取NFC标签中的NDEF格式数据
首先在AndroidManifest.xml文件中添加如下配置
<!-- SDK版本至少为14 -->
<uses-sdk android:minSdkVersion="14"/>
<!-- 添加NFC权限 -->
<uses-permission android:name="android.permission.NFC" />
<!-- 要求当前设备必须要有NFC芯片 -->
<uses-feature android:name="android.hardware.nfc" android:required="true" />
创建一个NFC处理的基类
public class BaseNfcActivity extends AppCompatActivity {
private NfcAdapter mNfcAdapter;
private PendingIntent mPendingIntent;
@Override
protected void onStart() {
super.onStart();
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
// 用于感应到NFC时启动该Activity
// 这里建议将处理NFC的子类的launchMode设置成singleTop模式,这样感应到标签时就会回调onNewIntent,而不会重复打开页面
mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()), 0);
}
/**
* 获得焦点,按钮可以点击
*/
@Override
public void onResume() {
super.onResume();
// 设置当该页面处于前台时,NFC标签会直接交给该页面处理
if (mNfcAdapter != null) {
mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, null, null);
}
}
/**
* 暂停Activity,界面获取焦点,按钮可以点击
*/
@Override
public void onPause() {
super.onPause();
// 当页面不可见时,NFC标签不交给当前页面处理
if (mNfcAdapter != null) {
mNfcAdapter.disableForegroundDispatch(this);
}
}
}
然后创建一个NFC读标的类ReadTagActivity,继承BaseNfcActivity
public class ReadTagActivity extends BaseNfcActivity {
private TextView mContent;
private String mTagText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_read_tag);
mContent = findViewById(R.id.content);
}
@Override
public void onNewIntent(Intent intent) {
//1.获取Tag对象
Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
//2.获取Ndef的实例
Ndef ndef = Ndef.get(detectedTag);
mTagText = "type:" + ndef.getType();
mTagText += "\nmaxsize:" + ndef.getMaxSize() + "bytes";
readNfcTag(intent);
mContent.setText(mTagText);
}
/**
* 读取NFC标签文本数据
*/
private void readNfcTag(Intent intent) {
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
Parcelable[] rawMsgs = intent.getParcelableArrayExtra(
NfcAdapter.EXTRA_NDEF_MESSAGES);
NdefMessage msgs[] = null;
int contentSize = 0;
if (rawMsgs != null) {
msgs = new NdefMessage[rawMsgs.length];
for (int i = 0; i < rawMsgs.length; i++) {
msgs[i] = (NdefMessage) rawMsgs[i];
contentSize += msgs[i].toByteArray().length;
}
}
try {
if (msgs != null) {
NdefRecord record = msgs[0].getRecords()[0];
String textRecord = parseTextRecord(record);
mTagText += "\ncontent:" + textRecord;
mTagText += "\ncontentSize:" + contentSize + " bytes";
}
} catch (Exception e) {
}
}
}
/**
* 解析NDEF文本数据,从第三个字节开始,后面的文本数据
* @param ndefRecord
* @return
*/
public static String parseTextRecord(NdefRecord ndefRecord) {
/**
* 判断数据是否为NDEF格式
*/
//判断TNF
if (ndefRecord.getTnf() != NdefRecord.TNF_WELL_KNOWN) {
return null;
}
//判断可变的长度的类型
if (!Arrays.equals(ndefRecord.getType(), NdefRecord.RTD_TEXT)) {
return null;
}
try {
//获得字节数组,然后进行分析
byte[] payload = ndefRecord.getPayload();
//下面开始NDEF文本数据第一个字节,状态字节
//判断文本是基于UTF-8还是UTF-16的,取第一个字节"位与"上16进制的80,16进制的80也就是最高位是1,
//其他位都是0,所以进行"位与"运算后就会保留最高位
String textEncoding = ((payload[0] & 0x80) == 0) ? "UTF-8" : "UTF-16";
//3f最高两位是0,第六位是1,所以进行"位与"运算后获得第六位
int languageCodeLength = payload[0] & 0x3f;
//下面开始NDEF文本数据第二个字节,语言编码
//获得语言编码
String languageCode = new String(payload, 1, languageCodeLength, "US-ASCII");
//下面开始NDEF文本数据后面的字节,解析出文本
String textRecord = new String(payload, languageCodeLength + 1,
payload.length - languageCodeLength - 1, textEncoding);
return textRecord;
} catch (Exception e) {
throw new IllegalArgumentException();
}
}
}
布局文件很简单,就一个TextView显示读取的结果
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
最后记得把MainActivity的启动模式设置成singleTop
<activity
android:name=".ReadTagActivity"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
测试
- 首先准备一台支持NFC功能的手机,打开我们写好的应用
- 准备一张NFC标签,靠近手机NFC读取区域(一般在背部)
- 读取成功后会在页面显示标签的相关信息,如下所示