NFC开发入门篇

NFC开发入门篇

之前做过一些关于NFC的项目,比如手机羊城通卡芯片的充值,粤通卡的充值(与微信的羊城通充值功能类似),NFC功能是需要硬件的支持的,不过现在越来越多手机支持NFC功能了,所以这里简单的介绍它的开发流程吧。

一、NFC简介

NFC(Near Field Communication)近距离无线通信技术。工作模式分为两种:卡模式(Card emulation)、点对点模式(P2P mode)。这里主要是介绍卡模式的的开发,卡模式的开发又分为机卡通道和非机卡通道两种,机卡通道就是手机卡里面集成了相关的芯片,一卡多用,卡离开手机之后无法工作,比如手机卡里面又附带羊城通的芯片的功能,这样既可以打电话又可以刷公交和地铁。非机卡通道就是卡和手机是分开使用的,就是平常使用单独一张公交卡一样。

二、开发流程

1、非机卡通道模式

(1)在AndroidManifest.xml中声明权限

<uses-permission android:name=”android.permission.NFC” />
<uses-feature android:name=”android.hardware.nfc” android:required=”true” />

(2)在AndroidManifest.xml 中的activity中声明可以处理的NFC Tag。 
当手机开启了NFC,并且检测到一个TAG后,TAG分发系统会自动创建一个封装了NFC TAG信息的intent。如果多于一个应用程序能够处理这个intent的话,那么手机就会弹出一个框,让用户选择处理该TAG的Activity。 TAG分发系统定义了3中intent。按优先级从高到低排列为: 
NDEF_DISCOVERED, TECH_DISCOVERED,TAG_DISCOVERED 
当Android设备检测到有NFC Tag靠近时,会根据Action申明的顺序给对应的Activity 发送含NFC消息的 Intent。在某个Activity中添加以下的代码: 
这里写图片描述

(3)编写xml文件。 
在res目录下新建xml,编写上面红色框的xml文件:nfc_tech_filter,声明要处理的NFC Tag。 
这里写图片描述

(4)测试 
打开Android手机的NFC,运行程序,并把羊城通靠近手机背部,这样就可以看到可以处理NFC卡的应用。 
这里写图片描述

(5)设置Activity 
在onCreate()方法里添加以下代码。

nfcAdapter = NfcAdapter.getDefaultAdapter(this);
pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
//区分系统版本
sysVersion = Integer.parseInt(VERSION.SDK);
if(sysVersion<19){
    onNewIntent(getIntent());
}

onPause里面解除

@Override
    protected void onPause() {
        super.onPause();
        if (nfcAdapter != null){
            nfcAdapter.disableForegroundDispatch(this);
            disableReaderMode();
        }
    }

重写OnnewIntent方法,在低于4.4系统时会用到这方法。

@Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        //获取数据
        final Parcelable p = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        Log.d("NFCTAG", intent.getAction());
        board.setText((p != null) ? CardReader.load(p) : null);
        if(p==null){
            board.setText("the intent=="+intent);
        }else{
            //board.setText("the intent !=null");
        }
    }

重写onResume方法

public static String[][] TECHLISTS;
public static IntentFilter[] FILTERS;
static {
   try {
TECHLISTS = new String[][] { { IsoDep.class.getName() },{ NfcV.class.getName() }, { NfcF.class.getName() }, };
FILTERS = new IntentFilter[] { new IntentFilter(
                    NfcAdapter.ACTION_TECH_DISCOVERED, "*/*") };
        } catch (Exception e) {
        }
    }
//4.4以上系统,在这个页面,多次发现标签,onresume只执行一次,4.4以下的会执行多次,但是onNewIntent()和enableReaderMode()都能够执行多次
@Override
    protected void onResume() {
        super.onResume();
        if (nfcAdapter != null){
            nfcAdapter.enableForegroundDispatch(this, pendingIntent,
                    CardReader.FILTERS, CardReader.TECHLISTS);
            enableReaderMode();
        }
        Log.e("NFC----", IsoDep.class.getName());
    }

(6)与卡片的交互方法的实现至此非机卡通道方式的代码设置结束。

2、机卡通道模式

(1)选择API 
使用的API是Open mobile api,这是基于android平台的用于APP与SIM卡建立通信连接的规范。添加的方法和添加其它版本API一样。 
(2) 添加权限

<uses-permission android:name="org.simalliance.openmobileapi.SMARTCARD"/>
<uses-library android:name="org.simalliance.openmobileapi" 
             android:required="true" />

(3)在Activity类实现以下代码

SEService mSeService = new SEService(this, this);

实现回调的方法:

@Override
    public void serviceConnected(SEService service) {
//      DebugLog.i(LOG_TAG, "service connected");
//      可以读取卡的数据了
        NFCResponeController.getCardInfo(mSeService);
    }

    @Override
    protected void onDestroy() {
        if (mSeService != null && mSeService.isConnected()) {
            mSeService.shutdown();
        }
        super.onDestroy();
    }

/**
     * 传输API访问卡,执行command命令
     * @param aid AID标识字节
     * @param command 执行命令字节 至少4个字节
     * @param mseService SE服务
     * @return resulteStr 卡返回字节
     */
    public static byte[] queryCardCommand(byte[] aid,byte[] command,SEService mseService)
    {
        try {
              Reader[] readers = mseService.getReaders();
              if (readers.length < 1)
                 return null;
              Session session = readers[0].openSession();
              Channel channel = session.openLogicalChannel(aid);
              byte[] respApdu = channel.transmit(command);
              channel.close();
//            DebugLog.d(DebugLog_TAG,"读卡接口结果:"+NFCUtil.bytesToHexString(respApdu));
              return respApdu;
           }catch(java.lang.IllegalArgumentException e)
            {
//               DebugLog.e(DebugLog_TAG, "ERROR<<<<<<<<发送命令至少4个字节");
                 return null;
            }
            catch (Exception e) {
//                DebugLog.e(DebugLog_TAG, "Error occured:", e);
                  return null;
            } 
    }

3、参考内容

参考的博客

三、总结

刚开始接触的时候会不知道怎么入手,但这些基本的操作是需要掌握的,用多几次之后,就可以算入门了。

猜你喜欢

转载自blog.csdn.net/zhangbijun1230/article/details/82589171