android NFC 开发学习笔记(1)

来源:互联网 发布:泗阳网络问政12345 编辑:程序博客网 时间:2024/05/16 03:30

由于工作需求,最近在研究android nfc开发,借鉴了很对大神的文章在此记录自己的学习过程:


大家学习android开发建议首选android开发文档,该文档在你下载的sdk中,路径:/sdk/docs/index.html


目前NFC应用的大的框架上的理解:

我使用的API LEVEL是19,支持的API有三个:android.nfc,android.nfc.cardemulator,android.nfc.tech

NFC在手机上的应用大体分为两类:读卡器和卡

android.nfc.cardemulator接口是为NFC作为卡应用提供的接口,在较低版本的API上是没有的

android.nfc.tech,android.nfc接口是为NFC作为读卡器应用提供的接口


首先说作为卡,nfc有两种实现方式,一个是使用NFC芯片作为卡,另一个是使用SIM作为卡


Figure 1. NFC card emulation with a secure element.

至于从读卡器发送的指令到底是传递到NFC芯片还是SIM由NFC Controler控制,图中Secure Element是指SIM,Host-CPU指NFC芯片

android提供HostApduService用于NFC芯片,OffHostApduService用于SIM芯片,传递方向在res/xml文件中通过AID来控制


ps:Host-Based Card Emulator 简称为HCE


代码实现:

AndroidManifest.xml 中 配置service,因为作为卡实现的话,NFC功能是作为service存在的

        <service android:name="com.shhic.nfcapp.NFCService" android:exported="true"
            android:permission="android.permission.BIND_NFC_SERVICE">
            <intent-filter>
                <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/>
            </intent-filter>
            <meta-data android:name="android.nfc.cardemulation.host_apdu_service"
                android:resource="@xml/apduservice"/>
        </service>


res/xml/apduservice.xml 中配置service响应的AID

<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
           android:description="@string/servicedesc"
           android:requireDeviceUnlock="false">
    <aid-group android:description="@string/aiddescription"
                android:category="other">
        <aid-filter android:name="F0010203040506"/>
    </aid-group>
</host-apdu-service>


配置文件完成后编写service的处理方法:

NFCService需要继承HostApduService,如果需要与Activity通信,建议采用广播方式

也可以自己实现观察者模式,只是这样就需要持有Activity的引用,感觉不太好

NFCService.java

public class NFCService extends HostApduService {

    private Intent intent = new Intent("com.example.communication.RECEIVER");
    
    @Override
    public void onCreate()
    {
        //启动Acivity
        Intent i = new Intent();
        i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//需要启动的Activity不是当前Activity的时候需要用FLAG_ACTIVITY_NEW_TASK
        i.setAction("com.apdu.nfc");
        getApplication().startActivity(i);
        Toast.makeText(getApplicationContext(), "Service启动", Toast.LENGTH_LONG).show();
        
    }
    @Override
    public byte[] processCommandApdu(byte[] commandApdu, Bundle extras) {//当注册的AID被选中后,后续指令被分发到这个处理函数中
        byte[] sw = new byte[]{(byte)0x90,(byte)0x00};
        byte[] response = new byte[5];
        if (commandApdu[0]==(byte)0x00 &&commandApdu[1]==(byte)0xA4&& commandApdu[2]==(byte)0x04
                && commandApdu[4]==(byte)0x07&& commandApdu[5]==(byte)0xF0)
        {
            return sw;
        }
        else
        {
            //apdu处理逻辑
            switch(commandApdu[1])
            {
            case (byte)0xA8:
             
                break;
            case (byte)0xAE:
               
                break;
            default:
                return sw;
            }
        }
        

        intent.putExtra("command", commandApdu);
        intent.putExtra("response", response);
        sendBroadcast(intent);    //利用广播与Activity通信
        
        return response;   //SW值需要包含在response中
    }

    @Override
    public void onDeactivated(int reason) {
        if (reason==HostApduService.DEACTIVATION_DESELECTED)
        {
            Toast.makeText(getApplicationContext(), "已选择其它应用", Toast.LENGTH_LONG).show();
        }
        else
        {
            Toast.makeText(getApplicationContext(), "连接断开", Toast.LENGTH_LONG).show();
        }
    }
    
    @Override  
    public void onDestroy()
    {  
        Toast.makeText(getApplicationContext(), "Service关闭", Toast.LENGTH_LONG).show();
        super.onDestroy();  
    }

框架搭建好剩余的事情就很简单了,apdu的处理逻辑在processCommandApdu方法中实现即可


以上是Host-CPU方式的实现,SIM方式,API介绍中说该方式没有提供可供操作的API,也就是说Android不会监听SIM卡与读卡器之间的通信

所以NFCOffService 只需要实现onBind接口,这样绑定该Service的Activity可以对NFCOffService进行有限操作


public class NFCOffService extends OffHostApduService {
    
    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }

}


0 0
原创粉丝点击