博主最近因为项目中要实现nfc读写功能,所以才接触这一方面,理论概念啥的请大家自行查询资料或百度。下面内容为博主自己demo实现的功能,为大家做参考(部分代码来源于其他博主,至于谁是第一个整理的,我也不知道,所以就不写转载谁了)。以下全是干货,大家看看看~~~
功能需求:将卡贴在有nfc功能的设备上,读取、写入数据。
博主查资料说这种属于读卡器模式,数据存储在有nfc芯片的卡中。so,如果大家想知道其他模式,百度去吧~~~
1.Manifest中配置
//权限
//要求当前设备具有nfc功能
权限 声明 配置...
这个是处理nfc的activity。Android提供两个系统来帮助你正确的识别一个NFC tag是否是你的Activity想要处理的:1.Intent发布系统和2.前台Activity发布系统。上面配置的是1。
2.下面贴上一个工具类NfcUtils
public class NfcUtils {
//nfc
public static NfcAdapter mNfcAdapter;
public static IntentFilter[] mIntentFilter = null;
public static PendingIntent mPendingIntent = null;
public static String[][] mTechList = null;
public NfcUtils(Activity activity) {
mNfcAdapter = NfcCheck(activity);
NfcInit(activity);
}
/**
* 检查NFC是否打开
*/
public static NfcAdapter NfcCheck(Activity activity) {
NfcAdapter mNfcAdapter = NfcAdapter.getDefaultAdapter(activity);
if (mNfcAdapter == null) {
ToastUtils.showShort(activity, "设备不支持NFC功能!");
return null;
} else {
if (!mNfcAdapter.isEnabled()) {
IsToSet(activity);
} else {
ToastUtils.showShort(activity, "NFC功能已打开!");
}
}
return mNfcAdapter;
}
/**
* 初始化nfc设置
*/
public static void NfcInit(Activity activity) {
Intent intent = new Intent(activity, activity.getClass());
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
mPendingIntent = PendingIntent.getActivity(activity, 0, intent, 0);
//做一个IntentFilter过滤你想要的action 这里过滤的是ndef
IntentFilter filter = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
//如果你对action的定义有更高的要求,比如data的要求,你可以使用如下的代码来定义intentFilter
// IntentFilter filter2 = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
// try {
// filter.addDataType("*/*");
// } catch (IntentFilter.MalformedMimeTypeException e) {
// e.printStackTrace();
// }
// mIntentFilter = new IntentFilter[]{filter, filter2};
// mTechList = null;
try {
filter.addDataType("*/*");
} catch (IntentFilter.MalformedMimeTypeException e) {
e.printStackTrace();
}
mTechList = new String[][]{{MifareClassic.class.getName()},
{NfcA.class.getName()}};
//生成intentFilter
mIntentFilter = new IntentFilter[]{filter};
}
/**
* 读取NFC的数据
*/
public static String readNFCFromTag(Intent intent) throws UnsupportedEncodingException {
Parcelable[] rawArray = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if (rawArray != null) {
NdefMessage mNdefMsg = (NdefMessage) rawArray[0];
NdefRecord mNdefRecord = mNdefMsg.getRecords()[0];
if (mNdefRecord != null) {
return parseTextRecord(mNdefRecord);
}
}
return "";
}
/**
* 往nfc写入数据
*/
public static void writeNFCToTag(Context context,String data, Intent intent) throws IOException, FormatException {
NdefRecord ndefRecord = null;
ndefRecord=createTextRecord(data);
NdefRecord[] records = {ndefRecord};
NdefMessage ndefMessage = new NdefMessage(records);
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
Ndef ndef = Ndef.get(tag);
if(ndef==null){
NdefFormatable format = NdefFormatable.get(tag);
format.connect();
format.format(ndefMessage);
if(format.isConnected()){
format.close();
}
return;
}
ndef.connect();
if(!ndef.isWritable()){
LogUtils.e("当前设备不支持写入");
return;
}
//判断大小
// if(ndef.getMaxSize() < size)
ndef.writeNdefMessage(ndefMessage);
if(ndef.isConnected()){
ndef.close();
}
ToastUtils.showShort(context,"读写完毕");
}
/**
* 读取nfcID
*/
public static String readNFCId(Intent intent) throws UnsupportedEncodingException {
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
String id = ByteArrayToHexString(tag.getId());
return id;
}
/**
* 将字节数组转换为字符串
*/
private static String ByteArrayToHexString(byte[] inarray) {
int i, j, in;
String[] hex = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"};
String out = "";
for (j = 0; j < inarray.length; ++j) {
in = (int) inarray[j] & 0xff;
i = (in >> 4) & 0x0f;
out += hex[i];
i = in & 0x0f;
out += hex[i];
}
return out;
}
private static void IsToSet(final Activity activity) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setMessage("是否跳转到设置页面打开NFC功能");
// builder.setTitle("提示");
builder.setPositiveButton("确认", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
goToSet(activity);
dialog.dismiss();
}
});
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.create().show();
}
private static void goToSet(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BASE) {
// 进入设置系统应用权限界面
Intent intent = new Intent(Settings.ACTION_SETTINGS);
activity.startActivity(intent);
return;
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {// 运行系统在5.x环境使用
// 进入设置系统应用权限界面
Intent intent = new Intent(Settings.ACTION_SETTINGS);
activity.startActivity(intent);
return;
}
}
/**
* 创建NDEF文本数据
* @param text
* @return
*/
public static NdefRecord createTextRecord(String text) {
byte[] langBytes = Locale.CHINA.getLanguage().getBytes(Charset.forName("US-ASCII"));
Charset utfEncoding = Charset.forName("UTF-8");
//将文本转换为UTF-8格式
byte[] textBytes = text.getBytes(utfEncoding);
//设置状态字节编码最高位数为0
int utfBit = 0;
//定义状态字节
char status = (char) (utfBit + langBytes.length);
byte[] data = new byte[1 + langBytes.length + textBytes.length];
//设置第一个状态字节,先将状态码转换成字节
data[0] = (byte) status;
//设置语言编码,使用数组拷贝方法,从0开始拷贝到data中,拷贝到data的1到langBytes.length的位置
System.arraycopy(langBytes, 0, data, 1, langBytes.length);
//设置文本字节,使用数组拷贝方法,从0开始拷贝到data中,拷贝到data的1 + langBytes.length
//到textBytes.length的位置
System.arraycopy(textBytes, 0, data, 1 + langBytes.length, textBytes.length);
//通过字节传入NdefRecord对象
//NdefRecord.RTD_TEXT:传入类型 读写
NdefRecord ndefRecord = new NdefRecord(NdefRecord.TNF_WELL_KNOWN,
NdefRecord.RTD_TEXT, new byte[0], data);
return ndefRecord;
}
/**
* 解析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";
LogUtils.e("parseTextRecord() textEncoding="+textEncoding);
//3f最高两位是0,第六位是1,所以进行"位与"运算后获得第六位
int languageCodeLength = payload[0] & 0x3f;
//下面开始NDEF文本数据第二个字节,语言编码
//获得语言编码
String languageCode = new String(payload, 1, languageCodeLength, "US-ASCII");
LogUtils.e("parseTextRecord() languageCode="+languageCode);
//下面开始NDEF文本数据后面的字节,解析出文本
String textRecord = new String(payload, languageCodeLength + 1,
payload.length - languageCodeLength - 1, textEncoding);
LogUtils.e("parseTextRecord() text="+textRecord);
return textRecord;
} catch (Exception e) {
throw new IllegalArgumentException();
}
}
}
3.Activity中的设置
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
NfcUtils nfcUtils = new NfcUtils(this);
}
@Override
protected void onResume() {
super.onResume();
//设定intentfilter和tech-list。如果两个都为null就代表优先接收任何形式的TAG action。也就是说系统会主动发TAG intent。
if (NfcUtils.mNfcAdapter != null) {
NfcUtils.mNfcAdapter.enableForegroundDispatch(this, NfcUtils.mPendingIntent, NfcUtils.mIntentFilter, NfcUtils.mTechList);
}
}
@Override
protected void onPause() {
super.onPause();
if (NfcUtils.mNfcAdapter != null) {
NfcUtils.mNfcAdapter.disableForegroundDispatch(this);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
NfcUtils.mNfcAdapter = null;
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
readWrite(intent);
}
// 这块的readWrite() 就是处理卡中数据的方法
public void readWrite(Intent intent) {
try {
// 检测卡的id
String id = NfcUtils.readNFCId(intent);
// NfcUtils中获取卡中数据的方法
String result = NfcUtils.readNFCFromTag(intent);
// 往卡中写数据
String data = "1这是写入的数据2";
NfcUtils.writeNFCToTag(this,data,intent);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (FormatException e) {
e.printStackTrace();
}
}
好了,就是这样。如果你想了解更多,那就好好查资料去吧。以上是博主从别的博主那参考过来,然后整理实践出来的demo,仅供大家参考,如有不对,欢迎指正。更多原理性知识,暂时没时间整理,如有时间,继续更上。