天天看點

安卓開發,NFC讀取NFC标簽ID,包含Dome和個人見解。

安卓開發,NFC讀取NFC标簽ID,包含Dome和個人見解。

首先放上谷歌開發文檔對NFC的介紹,剛了解NFC開發的可以去看一下NFC文檔。

第一步想要實作的肯定是通過NFC标簽調用起我們的Dome,這也是我們日常用其他NFC的基礎操作。

通過學習文檔,我們得知NFC的調用是通過過濾器來實作的在安裝軟體時就會記錄下軟體所能過濾的NFC類型。

一共有三種過濾器:

一、ACTION_NDEF_DISCOVERED

二、ACTION_TECH_DISCOVERED

三、ACTION_TAG_DISCOVERED

主要差別可以研究文檔,大體上就是設定上的差别,優先級的差别(優先級順序為一二三),和讀寫部分代碼的差别。

這次我使用的第二種ACTION_TECH_DISCOVERED來實作的Dome。下面教大家配置ACTION_TECH_DISCOVERED。

首先在清單檔案中配置權限

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

然後在想要調起跳轉的頁面的Activity的清單配置中加入過濾器

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.NfcTest">
        <activity android:name=".MainActivity"
            android:launchMode="singleTop">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </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" />
        </activity>
    </application>
           

這裡有一個地方需要強調,就是android:launchMode=“singleTop”,雖然後面在建立NFC基類的時候會通過addFlags加上,但不知道為什麼不起作用,是以還是直接在清單裡加上比較友善,不然軟體就會在掃描到一次标簽就打開一個新頁面放入棧中。

随後就是針對android:resource="@xml/nfc_tech_filter"的配置,在res下建立xml檔案夾,有就不用,然後在檔案夾裡建立File,名稱為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.MifareUltralight</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.MifareClassic</tech>
    </tech-list>
</resources>
           

這部分比較簡單,每個tech-list就是一種類型的過濾,這個包含了tech所能支援的所有類型。基本上正常的标簽靠近,都能調起Dome,我自己試了四種都可以。

接下來就是主要的工作代碼了,由于是讀取Dome是以比較簡單,目标是讀取到标簽上的ID就算成功。

首先建立BaseNfcActivity.java

package com.example.nfctest;

import android.app.PendingIntent;
import android.content.Intent;
import android.nfc.NdefMessage;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.os.Parcelable;
import android.provider.Settings;
import android.util.Log;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

public class BaseNfcActivity extends AppCompatActivity {

    private NfcAdapter mNfcAdapter;
    private PendingIntent mPendingIntent;
    @Override
    protected void onStart() {
        super.onStart();
        mNfcAdapter= NfcAdapter.getDefaultAdapter(this);//裝置的NfcAdapter對象
        if(mNfcAdapter==null){//判斷裝置是否支援NFC功能
            Toast.makeText(this,"裝置不支援NFC功能!",Toast.LENGTH_SHORT);
            finish();
            return;
        }
        if (!mNfcAdapter.isEnabled()){//判斷裝置NFC功能是否打開
            Toast.makeText(this,"請到系統設定中打開NFC功能!",Toast.LENGTH_SHORT);
            finish();
            return;
        }
        mPendingIntent= PendingIntent.getActivity(this,0,new Intent(this,getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),0);//建立PendingIntent對象,當檢測到一個Tag标簽就會執行此Intent
        Log.d("myNFC","NFC is start");
    }

    //頁面擷取焦點
    @Override
    protected void onResume() {
        super.onResume();
        if (mNfcAdapter!=null){
            mNfcAdapter.enableForegroundDispatch(this,mPendingIntent,null,null);//打開前台釋出系統,使頁面優于其它nfc處理.當檢測到一個Tag标簽就會執行mPendingItent
            Log.d("myNFC","onResume");
        }
    }

    //頁面失去焦點
    @Override
    protected void onPause() {
        super.onPause();
        if(mNfcAdapter!=null){
            mNfcAdapter.disableForegroundDispatch(this);//關閉前台釋出系統
        }
    }
    
	//也是工具不過我沒用上。
    public static String flipHexStr(String s) {
        StringBuilder result = new StringBuilder();
        for (int i = 0; i <= s.length() - 2; i = i + 2) {
            result.append(new StringBuilder(s.substring(i, i + 2)).reverse());
        }
        return result.reverse().toString();
    }
    
	//工具,十六進制轉十進制用的
    String ByteArrayToHexString(byte[] inarray) {
        int i, j, in;
        String[] hex = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A",
                "B", "C", "D", "E", "F" };
        String out = "";

        for (j = 0; j < inarray.length; ++j) {
            in = (int) inarray[j] & 0xff;
            i = (in >> 4) & 0x0f;
            out += hex[i];
            i = in & 0x0f;
            out += hex[i];
        }
        return out;
    }
}

           

然後就是MainActivity.java,讓它繼承剛剛寫的BaseNfcActivity。

package com.example.nfctest;

import android.content.Intent;
import android.nfc.NdefMessage;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
import android.widget.TextView;

public class MainActivity extends BaseNfcActivity {
    TextView content;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        content = findViewById(R.id.content);
    }


    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        if(NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())){
            Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
//            Long cardId = Long.parseLong(flipHexStr(ByteArrayToHexString(tag.getId())), 16);
//            Long cardId = Long.parseLong(ByteArrayToHexString(tag.getId()), 16);
            String cardId = ByteArrayToHexString(tag.getId());
            content.setText(cardId.toString());
        }
        Log.d("myNFC",intent.toString());
    }
}
           

可以看到比較短,如果之前已經看了寫NFC文章的,應該知道NFC被掃描到之後不關是從桌面還是其他地方或者此應用,都會執行onNewIntent方法,而且傳過來的intent中包含了标簽中的資料。通過Tag擷取再從Tag中擷取ID。

layout代碼雖然簡單,但也放一下,友善大家!

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/content"
        />

</androidx.constraintlayout.widget.ConstraintLayout>
           

完成上述步驟,運作起來,即可驗證手邊的标簽ID了,ID都是出廠賦予好的,不需要自己寫。好了我該去研究如何寫入了。一起加油吧。

不做過多的解釋,因為大部分網上都有,隻是上傳一個簡單完整的技術驗證。,如果不是開發網上這種現成的工具很多,主要是考慮到包括我自己,需要開發,把這部分技術融入到項目中去!

展示一下吧,ID不是進去就擷取到的,而是要調起軟體後把标簽拿開再放上去才能擷取到,畢竟不是一開始就打開,從桌面打開隻會執行onStart和onResume,之後在軟體界面每次貼都會馬上擷取到。

安卓開發,NFC讀取NFC标簽ID,包含Dome和個人見解。

(免費)Demo位址:https://download.csdn.net/download/weixin_45920642/19886770