您的位置:首页 > 移动开发 > Android开发

android NFC开发

2016-07-04 16:43 330 查看
原文地址



先说说NFC开发总结,看了几天NFC开发资料,搜集了不少关于这方面的资料、demo、以及他人的总结。以下有部分是摘录总结的。因为要是现在总结也是那些,最后附送代码。关于demo我也有,有需要在评论去发邮箱给我。


一、NFC的配置总结

第一:屏幕没有锁住 。 第二:NFC功能已经在设置中打开

当系统检测到一个NFC标签的时候,他会自动去寻找最合适的activity去处理这个intent.

NFC发出的这个Intent将会有三种action:

ACTION_NDEF_DISCOVERED:当系统检测到tag中含有NDEF格式的数据时,且系统中有activity声明可以接受包含NDEF数据的Intent的时候,系统会优先发出这个action的intent。

ACTION_TECH_DISCOVERED:当没有任何一个activity声明自己可以响应ACTION_NDEF_DISCOVERED时,系统会尝试发出TECH的intent.即便你的tag中所包含的数据是NDEF的,但是如果这个数据的MIMEtype或URI不能和任何一个activity所声明的想吻合,系统也一样会尝试发出tech格式的intent,而不是NDEF.

ACTION_TAG_DISCOVERED:当系统发现前两个intent在系统中无人会接受的时候,就只好发这个默认的TAG类型的


二、NFC相关androidManifest文件设置

首先是权限:

<uses-permissionandroid:name="Android.permission.NFC"/>

然后是sdk级别限制:我个人建议API11开始比较合适:

<uses-sdkandroid:minSdkVersion="11"/>

如果是API8,在代码中,nfc功能设置的代码会出错,要抛出

例如:

NfcAdapter mAdapter = NfcAdapter.getDefaultAdapter(this);

mAdapter.isEnabled()

接着是特殊功能限制:

<uses-featureandroid:name="android.hardware.nfc"android:required="true"/>这个生命可以让你的应用在googleplay上被声明使用者必须拥有nfc功能。


三、NFC标签过滤,也在androidManifest文件设置

在activity的intent过滤xml声明中,你可以同时声明过滤这三种action.但是由之前所说,你应该知道系统在发送intent的时候是有优先级的,所以你最好清楚自己最想处理哪个。


1:过滤ACTION_TAG_DISCOVERED:

[html] view
plain copy

<intent-filter>

<action android:name="android.nfc.action.TAG_DISCOVERED"/>

<category android:name="android.intent.category.DEFAULT"/>

</intent-filter>

这个最简单,也是最后一个被尝试接受intent的选项。


2:过滤ACTION_NDEF_DISCOVERED:

[html] view
plain copy

<intent-filter>

<action android:name="android.nfc.action.NDEF_DISCOVERED"/>

<category android:name="android.intent.category.DEFAULT"/>

<data android:mimeType="text/plain" />

</intent-filter>

其中最重要的应该算是data的mimeType类型了,这个定义的越准确,intent指向你这个activity的成功率就越高,否则系统可能不会发出你想要的NDEF intent了。下面在讲如何使用NDEF写入NFC标签的时候会多举几个类型的例子。


3:过滤ACTION_TECH_DISCOVERED:

你首先需要在你的<project-path>/res/xml下面创建一个过滤规则文件。名字任取,比如可以叫做nfc_tech_filter.xml。这个里面定义的是nfc实现的各种标准,每一个nfc卡都会符合多个不同的标准,个人理解为这些标准有些相互之间也是兼容的。你可以在检测到nfc标签后使用getTechList()方法来查看你所检测的tag到底支持哪些nfc标准。

一个nfc_tech_filter.xml中可以定义多个<tech-list>结构组。

[html] view
plain copy

<span style="font-size:18px;"><resources xmlns:xliff="urn:oasis:names:tc:xliff:documen</span>t:1.2">

<tech-list>

<tech>

android.nfc.tech.IsoDep</tech>

<tech>android.nfc.tech.NfcA</tech>

<tech>android.nfc.tech.NfcB</tech>

<tech>android.nfc.tech.NfcF</tech>

</tech-list>

<tech-list>

<tech>android.nfc.tech.NfcV</tech>

<tech>android.nfc.tech.Ndef</tech>

<tech>android.nfc.tech.NdefFormatable</tech>

<tech>android.nfc.tech.MifareClassic</tech>

<tech>android.nfc.tech.MifareUltralight</tech>

</tech-list>

</resources>

在androidManifest文件中声明xml过滤的举例如下:

[html] view
plain copy

<activity>

<intent-filter>

<action android:name="android.nfc.action.TECH_DISCOVERED"/>

</intent-filter>

<meta-data android:name="android.nfc.action.TECH_DISCOVERED"

android:resource="@xml/nfc_tech_filter" />

</activity>


四、看具体代码:


1、主要代码实现如下:

[java] view
plain copy

package org.reno.Beam;

import java.io.ByteArrayOutputStream;

import java.nio.charset.Charset;

import java.text.DateFormat;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.List;

import java.util.Locale;

import org.nfc.read.ParsedNdefRecord;

import android.app.Activity;

import android.app.AlertDialog;

import android.app.PendingIntent;

import android.content.DialogInterface;

import android.content.Intent;

import android.nfc.NdefMessage;

import android.nfc.NdefRecord;

import android.nfc.NfcAdapter;

import android.nfc.Tag;

import android.nfc.tech.MifareClassic;

import android.nfc.tech.MifareUltralight;

import android.os.Bundle;

import android.os.Parcelable;

import android.provider.Settings;

import android.widget.TextView;

public class MainActivity extends Activity {

private static final DateFormat TIME_FORMAT = SimpleDateFormat

.getDateTimeInstance();

private NfcAdapter mAdapter;

private PendingIntent mPendingIntent;

private NdefMessage mNdefPushMessage;

private TextView promt;

private AlertDialog mDialog;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

promt = (TextView) findViewById(R.id.promt);

resolveIntent(getIntent());

mDialog = new AlertDialog.Builder(this).setNeutralButton("Ok", null)

.create();

// 获取默认的NFC控制器

mAdapter = NfcAdapter.getDefaultAdapter(this);

//拦截系统级的NFC扫描,例如扫描蓝牙

mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,

getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);

mNdefPushMessage = new NdefMessage(new NdefRecord[] { newTextRecord("",

Locale.ENGLISH, true) });

}

@Override

protected void onResume() {

super.onResume();

if (mAdapter == null) {

if (!mAdapter.isEnabled()) {

showWirelessSettingsDialog();

}

showMessage(R.string.error, R.string.no_nfc);

promt.setText("设备不支持NFC!");

return;

}

if (!mAdapter.isEnabled()) {

promt.setText("请在系统设置中先启用NFC功能!");

return;

}

if (mAdapter != null) {

//隐式启动

mAdapter.enableForegroundDispatch(this, mPendingIntent, null, null);

mAdapter.enableForegroundNdefPush(this, mNdefPushMessage);

}

}

@Override

protected void onPause() {

super.onPause();

if (mAdapter != null) {

//隐式启动

mAdapter.disableForegroundDispatch(this);

mAdapter.disableForegroundNdefPush(this);

}

}

//16进制字符串转换为String

private String hexString = "0123456789ABCDEF";

public String decode(String bytes) {

if (bytes.length() != 30) {

return null;

}

ByteArrayOutputStream baos = new ByteArrayOutputStream(

bytes.length() / 2);

// 将每2位16进制整数组装成一个字节

for (int i = 0; i < bytes.length(); i += 2)

baos.write((hexString.indexOf(bytes.charAt(i)) << 4 | hexString

.indexOf(bytes.charAt(i + 1))));

return new String(baos.toByteArray());

}

// 字符序列转换为16进制字符串

private static String bytesToHexString(byte[] src, boolean isPrefix) {

StringBuilder stringBuilder = new StringBuilder();

if (isPrefix == true) {

stringBuilder.append("0x");

}

if (src == null || src.length <= 0) {

return null;

}

char[] buffer = new char[2];

for (int i = 0; i < src.length; i++) {

buffer[0] = Character.toUpperCase(Character.forDigit(

(src[i] >>> 4) & 0x0F, 16));

buffer[1] = Character.toUpperCase(Character.forDigit(src[i] & 0x0F,

16));

System.out.println(buffer);

stringBuilder.append(buffer);

}

return stringBuilder.toString();

}

private void showMessage(int title, int message) {

mDialog.setTitle(title);

mDialog.setMessage(getText(message));

mDialog.show();

}

private NdefRecord newTextRecord(String text, Locale locale,

boolean encodeInUtf8) {

byte[] langBytes = locale.getLanguage().getBytes(

Charset.forName("US-ASCII"));

Charset utfEncoding = encodeInUtf8 ? Charset.forName("UTF-8") : Charset

.forName("UTF-16");

byte[] textBytes = text.getBytes(utfEncoding);

int utfBit = encodeInUtf8 ? 0 : (1 << 7);

char status = (char) (utfBit + langBytes.length);

byte[] data = new byte[1 + langBytes.length + textBytes.length];

data[0] = (byte) status;

System.arraycopy(langBytes, 0, data, 1, langBytes.length);

System.arraycopy(textBytes, 0, data, 1 + langBytes.length,

textBytes.length);

return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT,

new byte[0], data);

}

private void showWirelessSettingsDialog() {

AlertDialog.Builder builder = new AlertDialog.Builder(this);

builder.setMessage(R.string.nfc_disabled);

builder.setPositiveButton(android.R.string.ok,

new DialogInterface.OnClickListener() {

public void onClick(DialogInterface dialogInterface, int i) {

Intent intent = new Intent(

Settings.ACTION_WIRELESS_SETTINGS);

startActivity(intent);

}

});

builder.setNegativeButton(android.R.string.cancel,

new DialogInterface.OnClickListener() {

public void onClick(DialogInterface dialogInterface, int i) {

finish();

}

});

builder.create().show();

return;

}

//初步判断是什么类型NFC卡

private void resolveIntent(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[] rawMsgs = intent

.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);

NdefMessage[] msgs;

if (rawMsgs != null) {

msgs = new NdefMessage[rawMsgs.length];

for (int i = 0; i < rawMsgs.length; i++) {

msgs[i] = (NdefMessage) rawMsgs[i];

}

} else {

// Unknown tag type

byte[] empty = new byte[0];

byte[] id = intent.getByteArrayExtra(NfcAdapter.EXTRA_ID);

Parcelable tag = intent

.getParcelableExtra(NfcAdapter.EXTRA_TAG);

byte[] payload = dumpTagData(tag).getBytes();

NdefRecord record = new NdefRecord(NdefRecord.TNF_UNKNOWN,

empty, id, payload);

NdefMessage msg = new NdefMessage(new NdefRecord[] { record });

msgs = new NdefMessage[] { msg };

}

// Setup the views

buildTagViews(msgs);

}

}

//一般公家卡,扫描的信息

private String dumpTagData(Parcelable p) {

StringBuilder sb = new StringBuilder();

Tag tag = (Tag) p;

byte[] id = tag.getId();

sb.append("Tag ID (hex): ").append(getHex(id)).append("\n");

sb.append("Tag ID (dec): ").append(getDec(id)).append("\n");

sb.append("ID (reversed): ").append(getReversed(id)).append("\n");

String prefix = "android.nfc.tech.";

sb.append("Technologies: ");

for (String tech : tag.getTechList()) {

sb.append(tech.substring(prefix.length()));

sb.append(", ");

}

sb.delete(sb.length() - 2, sb.length());

for (String tech : tag.getTechList()) {

if (tech.equals(MifareClassic.class.getName())) {

sb.append('\n');

MifareClassic mifareTag = MifareClassic.get(tag);

String type = "Unknown";

switch (mifareTag.getType()) {

case MifareClassic.TYPE_CLASSIC:

type = "Classic";

break;

case MifareClassic.TYPE_PLUS:

type = "Plus";

break;

case MifareClassic.TYPE_PRO:

type = "Pro";

break;

}

sb.append("Mifare Classic type: ");

sb.append(type);

sb.append('\n');

sb.append("Mifare size: ");

sb.append(mifareTag.getSize() + " bytes");

sb.append('\n');

sb.append("Mifare sectors: ");

sb.append(mifareTag.getSectorCount());

sb.append('\n');

sb.append("Mifare blocks: ");

sb.append(mifareTag.getBlockCount());

}

if (tech.equals(MifareUltralight.class.getName())) {

sb.append('\n');

MifareUltralight mifareUlTag = MifareUltralight.get(tag);

String type = "Unknown";

switch (mifareUlTag.getType()) {

case MifareUltralight.TYPE_ULTRALIGHT:

type = "Ultralight";

break;

case MifareUltralight.TYPE_ULTRALIGHT_C:

type = "Ultralight C";

break;

}

sb.append("Mifare Ultralight type: ");

sb.append(type);

}

}

return sb.toString();

}

private String getHex(byte[] bytes) {

StringBuilder sb = new StringBuilder();

for (int i = bytes.length - 1; i >= 0; --i) {

int b = bytes[i] & 0xff;

if (b < 0x10)

sb.append('0');

sb.append(Integer.toHexString(b));

if (i > 0) {

sb.append(" ");

}

}

return sb.toString();

}

private long getDec(byte[] bytes) {

long result = 0;

long factor = 1;

for (int i = 0; i < bytes.length; ++i) {

long value = bytes[i] & 0xffl;

result += value * factor;

factor *= 256l;

}

return result;

}

private long getReversed(byte[] bytes) {

long result = 0;

long factor = 1;

for (int i = bytes.length - 1; i >= 0; --i) {

long value = bytes[i] & 0xffl;

result += value * factor;

factor *= 256l;

}

return result;

}

//显示NFC扫描的数据

private void buildTagViews(NdefMessage[] msgs) {

if (msgs == null || msgs.length == 0) {

return;

}

// Parse the first message in the list

// Build views for all of the sub records

Date now = new Date();

List<ParsedNdefRecord> records = NdefMessageParser.parse(msgs[0]);

final int size = records.size();

for (int i = 0; i < size; i++) {

TextView timeView = new TextView(this);

timeView.setText(TIME_FORMAT.format(now));

ParsedNdefRecord record = records.get(i);

promt.append(record.getViewText());

}

}

//获取系统隐式启动的

@Override

public void onNewIntent(Intent intent) {

setIntent(intent);

resolveIntent(intent);

}

}


2、androidManifest配置

[html] view
plain copy

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="org.reno.Beam"

android:versionCode="1"

android:versionName="1.0" >

<uses-sdk

android:minSdkVersion="11"

android:targetSdkVersion="16" />

<!-- 权限 -->

<uses-permission android:name="android.permission.NFC" />

<!-- 是否支持谷歌什么硬件一般可以忽略 -->

<uses-feature android:name="android.hardware.nfc" />

<application

android:allowBackup="true"

android:icon="@drawable/ic_launcher"

android:label="@string/app_name"

android:theme="@style/AppTheme" >

<activity

android:name="org.reno.Beam.MainActivity"

android:alwaysRetainTaskState="true"

android:label="@string/app_name"

android:launchMode="singleInstance"

android:screenOrientation="nosensor" >

<intent-filter>

<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />

</intent-filter>

<intent-filter>

<action android:name="android.nfc.action.TECH_DISCOVERED" />

<!-- 添加这一条默认设置,能拦截当前页面所有扫描NFC的配置 -->

<category android:name="android.intent.category.DEFAULT" />

</intent-filter>

<!--

这个过滤条件我就没有使用了

<meta-data

android:name="android.nfc.action.TECH_DISCOVERED"

android:resource="@xml/nfc_tech_filter" />

-->

</activity>

</application>

</manifest>

本文的下载地址demo:http://download.csdn.net/detail/qq_16064871/9324211
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: