AndroidNFC

AndroidNFC

Posted by candy1126xx on July 13, 2017

NFC应用架构

当开启NFC功能,监测到附近有标签时,标签调度系统会执行: 1、解析NFC标签并搞清楚标签中标识数据负载的MIME类型或URI; 2、把MIME类型或URI以及数据负载封装到一个Intent中。 3、基于Intent来启动Activity。

开发人员需要指定自己开发的Activity所匹配的MIME类型或URI,这样标签调度系统就会调起这个Activity,并调用onNewIntent(),把Intent传过来。

声明权限

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

指定Activity所匹配的MIME类型或URI

<activity android:name=".Activity.Main.NFCActivity">  
    <intent-filter>  
        <action android:name="android.nfc.action.TAG_DISCOVERED" />  
        <category android:name="android.intent.category.DEFAULT" />  
        <data android:mimeType="*/*" />  
    </intent-filter>  
</activity>

处理Intent

检查NFC是否打开
public NfcAdapter NfcCheck(Activity activity) {  
    NfcAdapter mNfcAdapter = NfcAdapter.getDefaultAdapter(activity);  
    if (mNfcAdapter == null) {  
        return null;  
    } else {  
        if (!mNfcAdapter.isEnabled()) {  
            Intent setNfc = new Intent(Settings.ACTION_NFC_SETTINGS);  
            activity.startActivity(setNfc);  
        }  
    }  
    return mNfcAdapter;  
}  
读取数据
public String readNFCFromTag(Intent intent) throws UnsupportedEncodingException {  
    Parcelable[] rawArray = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);  
    if (rawArray != null) {  
        NdefMessage mNdefMsg = (NdefMessage) rawArray[0];  
        NdefRecord mNdefRecord = mNdefMsg.getRecords()[0];  
        if (mNdefRecord != null) {  
            String readResult = new String(mNdefRecord.getPayload(), "UTF-8");  
            return readResult;  
        }  
    }  
    return "";  
}  
写数据
public void writeNFCToTag(String data, Intent intent) throws IOException, FormatException {  
    Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);  
    Ndef ndef = Ndef.get(tag);  
    ndef.connect();  
    NdefRecord ndefRecord = NdefRecord.createTextRecord(null, data);  
    NdefRecord[] records = {ndefRecord};  
    NdefMessage ndefMessage = new NdefMessage(records);  
    ndef.writeNdefMessage(ndefMessage);  
}  
读取ID
public String readNFCId(Intent intent) throws UnsupportedEncodingException {  
    Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);  
    String id = ByteArrayToHexString(tag.getId());  
    return id;
}  

要在生命周期中开启/关闭调度系统

@Override  
protected void onResume() {  
    super.onResume();  
    //开启前台调度系统  
    mNfcAdapter.enableForegroundDispatch(this);  
}
@Override  
protected void onPause() {  
    super.onPause();  
    //关闭前台调度系统  
    mNfcAdapter.disableForegroundDispatch(this);  
}

NDEF

NDEF由各种数据记录组成,而各个记录由报头(Header)和有效载荷(Payload)组成,其中NDEF记录的数据类型和大小由记录载荷的报头注明,这里的报头包含3部分,分别为Length、Type和Identifier.。 NDEF数据被封装在一个消息(NdefMessage)中,该消息中包含了一条或多条记录(NdefRecord)。 当Android设备扫描到包含NDEF格式数据的NFC标签时,它会解析该消息,并尝试搞清楚数据的MIME类型或URI标识。首先系统会读取消息(NdefMessage)中的第一条NdefRecord,来判断如何解释整个NDEF消息(一个NDEF消息能够有多条NDEF记录)。 在格式良好的NDEF消息中,第一条NdefRecord包含以下字段信息: 1、3-bit TNF(类型名称格式)  指示如何解释可变长度类型字段。 2、可变长度类型  说明记录的类型,如果使用TNF_WELL_KNOWN,那么则使用这个字段来指定记录的类型定义(RTD)。 3、可变长度ID    唯一标识该记录。这个字段不经常使用,但是,如果需要唯一的标识一个标记,那么就可以为该字段创建一个ID。 4、可变长度负载  你想读/写的实际的数据负载。一个NDEF消息能够包含多个NDEF记录,因此不要以为在NDEF消息的第一条NDEF记录中包含了所有的负载。 标签调度系统使用TNF和类型字段来尝试把MIME类型或URI映射到NDEF消息中。如果成功,它会把信息跟实际的负载一起封装到ACTION_NEDF_DISCOVERED类型的Intent中。但是,会有标签调度系统不能根据第一条NDEF记录来判断数据类型的情况,这样就会有NDEF数据不能被映射到MIME类型或URI,或者是NFC标签没有包含NDEF开始数据的情况发生。在这种情况下,就会用一个标签技术信息相关的Tag对象和封装在ACTION_TECH_DISCOVERED类型Intent对象内部的负载来代替。

三种模式

1、读卡器模式:作为非接触读卡器使用,比如从海报或者展览信息电子标签上读取相关信息。 2、点对点模式:此模式和红外线差不多,可用于数据交换,只是传输距离较短,传输创建速度较快,传输速度也快些,功耗低。 3、卡模式:这个模式其实就是相当于一张采用RFID技术的IC卡,可以替代大量的IC卡(包括信用卡)使用的场合,如商场刷卡、公交卡、门禁管制,车票,门票等等。

应用

手机读取实体卡信息

手机给实体卡充值

1、手机读取实体卡信息; 2、把实体卡信息和充值信息发送给服务器; 3、服务器返回充值成功的信息; 4、手机向实体卡写入信息。

把手机当作实体卡

需要APP开发者与公交公司达成协议。 1、POS机读取手机; 2、POS机向APP服务器发送扣款请求; 3、APP服务器向公交公司服务器执行扣款; 4、APP服务器向POS机返回扣款成功; 5、APP服务器向手机返回扣款成功。