上一篇笔记主要是研究了NFC芯片作为卡片的应用场景以及实现
上文没有提到的就是,如果你需要使用NFC,需要在Manifest中申请NFC权限:
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" android:required="true" />
现在来说说NFC芯片作为读卡器的应用场景以及实现
android.nfc.tech,android.nfc接口是为NFC作为读卡器应用提供的接口
接口定义了三种Action Tags:ACTION_NDEF_DISCOVERED
,ACTION_TECH_DISCOVERED,
ACTION_TAG_DISCOVERED。
当你在Manifest文件中将Activity的action-filter设置为这三个Tag中的一种或几种时,NFC响应事件会按照如图流程处理
我的理解是ACTION_NDEF_DISCOVERED
是用于两台NFC手机之间传输文件的
ACTION_TECH_DISCOVERED,
ACTION_TAG_DISCOVERED才是用于NFC与卡进行通讯的
所以开发第一步是在Manifest中配置你的Action:
<activity
android:name="com.shhic.nfcapp.POSActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="com.nfc.pos" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.TECH_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</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" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
TECH_DISCOVERED还需要配置meta-data,meta-data的作用相当于补充说明或者一些配置信息
nfc_tech_filter.xml
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<tech-list>
<tech>android.nfc.tech.IsoDep</tech>
</tech-list>
<tech-list>
<tech>android.nfc.tech.NfcA</tech>
</tech-list>
<tech-list>
<tech>android.nfc.tech.NfcB</tech>
</tech-list>
<tech-list>
<tech>android.nfc.tech.NfcF</tech>
</tech-list>
<tech-list>
<tech>android.nfc.tech.NfcV</tech>
</tech-list>
<tech-list>
<tech>android.nfc.tech.Ndef</tech>
</tech-list>
<tech-list>
<tech>android.nfc.tech.NdefFormatable</tech>
</tech-list>
<tech-list>
<tech>android.nfc.tech.MifareClassic</tech>
</tech-list>
<tech-list>
<tech>android.nfc.tech.MifareUltralight</tech>
</tech-list>
</resources>
当然API中说明你可以将多个tech写在一个tech-list中,我做了尝试,这样做会引出一个问题,在程序未启动的情况下当手机刷卡时不会自动打开程序
如果想要自动打开需要按照上面这种写法,tech的个数可以根据你想要支持的卡类型进行调整
配置完成后,可以开始编写自己的Activity的java代码了
在onCreate方法中,需要获取NfcAdapter的引用,从名字可以看出这是一个适配器
NfcAdapter nfcAdapter;
PendingIntent pendingIntent;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.pos_main);
dc = (Button)findViewById(R.id.button4DC);
ecc = (Button)findViewById(R.id.button4ECC);
qpboc = (Button)findViewById(R.id.button4QPBOC);
logWindow=(TextView)findViewById(R.id.communication4Financy);
nfcAdapter=NfcAdapter.getDefaultAdapter(this);
pendingIntent = PendingIntent.getActivity(
this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
onNewIntent(getIntent());
}
这里使用PendingIntent,该Intent与普通的Intent不同的是它是有一个延迟启动的功能,它启动时会回调onNewIntent函数,这样能够实现NFC与Activity的交互
pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);的含义是将Intent传递给this Activity
在onPause与onResume中需要添加代码
public void onPause() {
super.onPause();
nfcAdapter.disableForegroundDispatch(this);
}
public void onResume() {
super.onResume();
nfcAdapter.enableForegroundDispatch(this, pendingIntent, FILTERS, TECHLISTS);
}
enableForegroundDispatch的作用是,当NFC事件发生时如果当前Activity不是注册了NFC action-filter的Activity,手机会显示注册了NFC事件的Activity供用户选择
如果当前Activity注册了NFC action 则将事件优先交由当前Activity处理。
onNewIntent实现:
@Override
public void onNewIntent(Intent intent) {
Parcelable p = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
if (p==null)
{
return;
}
Tag nfcTag = (Tag)p;
final IsoDep isodep = IsoDep.get(nfcTag);
// final NfcA isodep = NfcA.get(nfcTag);
final byte[] cmd = { (byte) 0x00, // CLA Class
(byte) 0xB4, // INS Instruction
(byte) 0x04, // P1 Parameter 1
(byte) 0x00, // P2 Parameter 2
(byte) 0x00, // Le
};
try {
isodep.connect();
byte[] reaponse=null;
logWindow.append("00B4040000"+'\n');
try {
reaponse = isodep.getHistoricalBytes();
logWindow.append(Util.bytes2HexString(reaponse)+'\n');
reaponse =isodep.transceive(cmd);
logWindow.append(Util.bytes2HexString(reaponse)+'\n');
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}finally{
try {
isodep.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
首先需要获取Tag,Tag是操作NFC的基础
Parcelable p = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
if (p==null)
{
return;
}
Tag nfcTag = (Tag)p;
再将tag转换成特定的通讯协议
final IsoDep isodep = IsoDep.get(nfcTag);
连接读卡器:
isodep.connect();
获取历史字节:
reaponse = isodep.getHistoricalBytes();
响应指令:
reaponse =isodep.transceive(cmd);
最后断开连接:(断开动作应该在Activity关闭或者pause的时候发生)
finally{
try {
isodep.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
onNewIntent里面可以实现业务逻辑的处理以及UI