上一篇文章已经给大家普及了一些基础知识。这次讲解一下Android系统下的nfc编程。本文依旧采用问答式的形式给大家讲解。
学习Android系统下的nfc编程,很自然的学习方法就是到官网下载NFC的Demo代码下来研究研究。看到AndroidMainfest.xml文件
<activity android:name="TagViewer"
android:theme="@android:style/Theme.NoTitleBar"
>
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
红色部分这个和nfc有关系,那它究竟是什么呢?
答:NDEF_DISCOVERED、TECH_DISCOVERED、TAG_DISCOVERED是三种类型的action,优先级依次递减。如果在AndroidMainfest.xml文件中定义了
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="*/*" />
</intent-filter>
<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" />
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED" />
<data android:mimeType="*/*" />
</intent-filter>
则系统会先匹配NDEF_DISCOVERED、TECH_DISCOVERED、TAG_DISCOVERED,有匹配,系统发出清脆的声音,表示匹配成功。系统发出沉闷的声音,表示匹配失败。如果都匹配,系统不发出任何声音。这样的过程叫做Tag 分发,也叫NFC三重过滤机制。
NFC Demo中的com.example.android.nfc.record包下的TextRecord.java
public static TextRecord parse(NdefRecord record) {
Preconditions.checkArgument(record.getTnf() == NdefRecord.TNF_WELL_KNOWN);
Preconditions.checkArgument(Arrays.equals(record.getType(), NdefRecord.RTD_TEXT));
try {
byte[] payload = record.getPayload();
/*
* payload[0] contains the "Status Byte Encodings" field, per the
* NFC Forum "Text Record Type Definition" section 3.2.1.
*
* bit7 is the Text Encoding Field.
*
* if (Bit_7 == 0): The text is encoded in UTF-8 if (Bit_7 == 1):
* The text is encoded in UTF16
*
* Bit_6 is reserved for future use and must be set to zero.
*
* Bits 5 to 0 are the length of the IANA language code.
*/
String textEncoding = ((payload[0] & 0200) == 0) ? "UTF-8" : "UTF-16";
int languageCodeLength = payload[0] & 0077;
String languageCode = new String(payload, 1, languageCodeLength, "US-ASCII");
String text =
new String(payload, languageCodeLength + 1,
payload.length - languageCodeLength - 1, textEncoding);
return new TextRecord(languageCode, text);
} catch (UnsupportedEncodingException e) {
// should never happen unless we get a malformed tag.
throw new IllegalArgumentException(e);
}
}
红色部分代码为什么这么写?
答:这是nfc论坛的文本规范,具体标准的内容可以到http://members.nfc-forum.org/specs/spec_dashboard 链接下载你想要的规范文件。此代码的含义是从返回NdefRecord对象中获取字符编码格式和语言类型和文本内容。文件有规范,uri也有它的规范,具体参见uri的规范文件。
很可惜,系统提供的NFC Demo没有提供一个nfc标签很重要的知识点,nfc标签前台发布系统。在此我贴出来部分代码。
publc String[][] TECHLISTS = new String[][] {
{ IsoDep.class.getName() },
{ NfcV.class.getName() }, { NfcF.class.getName() }, };
public IntentFilers FILTERS = new IntentFilter[] { new IntentFilter(
NfcAdapter.ACTION_TECH_DISCOVERED, "*/*") };
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.nfcard);
。
。
。
//前台调度系统 第一步
nfcAdapter = NfcAdapter.getDefaultAdapter(this);
pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,
getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
}
protected void onPause() {
super.onPause();
//前台调度系统 第三步
if (nfcAdapter != null)
nfcAdapter.disableForegroundDispatch(this);
}
@Override
protected void onResume() {
super.onResume();
//前台调度系统 第二步
if (nfcAdapter != null)
nfcAdapter.enableForegroundDispatch(this, pendingIntent,
FILTERS, TECHLISTS);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
final Parcelable p = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
if (p!=null){
Tag tag = (Tag)p;
for (int i=0; i<tag.getTechList().length; i++) {
Log.d("NFCTAG", tag.getTechList()[i] );
}
}
}
这些红色的代码添加的就是nfc标签的前台发布系统。
nfc的前台调度系统有什么作用,在程序中不使用行不行?
答:前台调度系统允许activity 截取intent并声明自己比其他处理相同的intent的activity优先级更高。
nfc标签前台调度系统分两种情况:
第一种情况:activity没有启动的时候,拿手机去扫描tag,那么系统中所有的intent filter都将一起参与过滤。
第二种情况:actiity启动后,拿手机去扫描tag时,那么将直接使用在foreground dispatch中代码写入的过滤标准。如果这个标准没有命中任何intent,那么系统将使用所activity声明的intent filter xml来过滤。网上下载的支付源码NFCard和z自己写的XXXXDemo两个程序都在配置文件里面有Intent的过滤,也都使用前台调度,如果前台调度中的TechList参数中并没有要刷的nfc卡的数据格式过滤,则会调用自己写的规则过滤文件,如果两个应用中的规则文件都有适配nfc卡的数据格式组,则会弹出activity列表。如果NFCard代码中增加了ISODep这种数据格式的前台调度系统过滤,则直接用这个应用读写nfc卡。否则即使NFCard的activity已经启动,接触nfc卡时,还是会弹出activity给用户选择。
总之前台调度系统就是为了再加一层过滤,避免弹出activity列表给用户选择。
NfcAdaper: nfc适配器,Android系统默认只有一个nfc适配器,所以用nfcAdapter = NfcAdapter.getDefaultAdapter(this);
Tag: 描述nfc标签的类,Tag tag =(Tag) intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
深圳通的tag.getTechList()返回的是ISODep和NfcA,说明深圳通支持这个芯片支持这两种格式。如果前台调度系统都没有这两种格式会怎么样,要是intent调度系统也没有对其进行过滤,会怎样?
答:没有前台调度系统也照样能够读写nfc的tag。intent调度系统中没有过滤这两种格式,也可以读写tag。带nfc模块的手机或者平板接触nfc模块时,如果系统中存在好几种nfc的应用,那么会弹出过滤nfc模块的activity,如果你的activity中没有过滤,则连读写nfc的机会都没有。如果使用了前台调度系统或者进行了过滤,则优先级会较高,此时即使你处在当前没有进行任何过滤的但具备nfc读写功能的界面,也会因为优先级不够,而被其他优先级更高的界面抢占。
好了,了解了上述的知识,你就可以很容易地看懂nfc的代码,进而编写自己的nfc应用了。