Androidハードウェア通信のNFC通信

1. はじめに

1.1 NFC は、Wi-Fi や Bluetooth に次ぐ新しい近距離無線伝送技術です。この種の制限は比較的大きく、データ伝送を実現するにはデバイスに NFC ハードウェアが搭載されている必要があり、伝送距離は非常に短く、4cm以内のみ送信でき、実際のシーンは触れたときにのみ送信される可能性があります。

1.2 NFCの長所と短所

メリット:通信速度が速い、接続が便利、タッチするだけで通信可能、セキュリティが高い

短所: 伝送距離が非常に短い、伝送データ量が少ない、すべてに普及しているわけではない、一部の携帯電話はサポートしていない

1.3 NFC、Bluetooth、赤外線コントラスト

比較項目 NFC ブルートゥース 赤外線
ネットワークタイプ ピアツーピア ポイントツーマルチポイント ピアツーピア
有効距離 <=0.1m <=10m、最新の Bluetooth 4.0 有効距離は最大 100m 通常1m以内、サーマルテクノロジー接続、不安定
転送速度 最大424kbps 最大24Mbps 低速 115.2kbp5、高速 4Mbps
接続時間 <0.1秒 6秒 0.5秒
安全性 セキュリティ、ハードウェア実装 セキュリティ、ソフトウェア実装 安全性、IRFM 使用時を除く
通信モード アクティブ-アクティブ/パッシブ アクティブ-アクティブ アクティブ-アクティブ
料金 低い 真ん中 低い

1.4 NFC通信モード

カードリーダーモード(リーダー/ライターモード)、エミュレーションカードモード(Card Emulation Mode)、ピアツーピアモード(P2Pモード)。

カードリーダーモード

NFC チップ内のデータは、単純に「スワイプ タグ」として理解できます。本質的には、NFC をサポートする携帯電話やその他の電子機器を介して、NFC チップを搭載したラベル、ステッカー、名刺などのメディアから情報を読み書きすることです。通常、NFC タグは外部電源を必要としません。NFC 対応の周辺機器が NFC にデータを読み書きするとき、ある種の磁場が送信され、この磁場が NFC タグに自動的に電力を供給します。

エミュレーションカードモード

NFC をサポートする携帯電話またはその他の電子デバイス内のデータは、単純に「携帯電話をスワイプする」と理解できます。本質的には、NFC 対応の携帯電話やその他の電子デバイスを、デビット カード、バス カード、アクセス コントロール カードなどの IC カードとして使用することです。基本原理は、対応するICカード内の情報証明書をデータパケットにカプセル化し、NFC対応周辺機器に格納することです。

ご利用の際にはNFC高周波デバイス(カードリーダーに相当)も必要となります。携帯電話をNFC無線デバイスに近づけると、携帯電話はNFC無線デバイスから送信された信号を受信し、一連の複雑な認証を通過した後、ICカードの対応する情報がNFC無線デバイスに送信されます。 IC カードのデータは、NFC 無線周波数デバイスに送信され、コンピュータは無線周波数デバイスに接続され、対応する処理 (電子転送、ドアの開閉など) を実行します。

ピアツーピアモード

このモードは Bluetooth や赤外線に似ており、異なる NFC デバイス間のデータ交換に使用されますが、このモードには「スワイプ」の感覚がありません。有効距離は一般に 4 cm を超えることはできませんが、伝送確立速度は赤外線や Bluetooth テクノロジーよりもはるかに速く、双方が Android 4.2 を使用している場合、NFC は Bluetooth を直接使用して伝送します。この技術は Android ビームと呼ばれます。そのため、Android ビームを使用してデータを転送する 2 台のデバイスは 4cm 以内に制限されなくなりました。

ピアツーピア モードの一般的な用途は、2 台の NFC 対応携帯電話またはタブレット間のピアツーピア データ送信 (写真の交換やデバイスの連絡先の同期など) です。したがって、NFC を介して、デジタル カメラ、コンピュータ、携帯電話などの複数のデバイスを迅速に接続し、データやサービスを交換できます。

2、NFC通信ステップ

2.1 AndroidManifest.xml は動的リクエストなしで NFC 権限を追加します

<!--NFC 相关权限-->
<!--描述所需硬件特性-->
<uses-feature
	android:name="android.hardware.nfc"
	android:required="true" />
<uses-permission android:name="android.permission.NFC" />

2.2 NFC タグフィルタリングの追加 (2 つの方法)

方法 1: AndroidManifest.xml の Activity タグに XML 設定を追加する

res ディレクトリに新しい xml フォルダーを作成し、新しい nfc_tech_filter.xml ファイルを作成します。

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <!-- 可以处理所有Android支持的NFC类型 -->
    <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>

アクティビティタグは XML を構成します

<activity
	android:name=".MainActivity"
	android:exported="true">
	<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>

 方法 2: NFC の初期化時にタグを動的に構成する

/**
 * 初始化nfc设置
 */
public static void NfcInit(Activity activity) {
	Intent intent = new Intent(activity, activity.getClass());
	intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
	mPendingIntent = PendingIntent.getActivity(activity, 0, intent, 0);
	//做一个IntentFilter过滤你想要的action 这里过滤的是ndef
	IntentFilter filter = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
	//如果你对action的定义有更高的要求,比如data的要求,你可以使用如下的代码来定义intentFilter
	//        IntentFilter filter2 = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
	//        try {
	//            filter.addDataType("*/*");
	//        } catch (IntentFilter.MalformedMimeTypeException e) {
	//            e.printStackTrace();
	//        }
	//        mIntentFilter = new IntentFilter[]{filter, filter2};
	//        mTechList = null;
	  try {
			filter.addDataType("*/*");
	  } catch (IntentFilter.MalformedMimeTypeException e) {
			e.printStackTrace();
	  }
	mTechList = new String[][]{
   
   {MifareClassic.class.getName()},
		{NfcA.class.getName()}};
	//生成intentFilter
	mIntentFilter = new IntentFilter[]{filter};
}

2.3 NFCアダプターの作成

NFC のすべての操作は NfcAdapter を通じて完了します。NfcAdapter を作成した後、同時に待機中の PendingIntent を作成します。これは主に NFC を起動してページを開くために使用されます。

private NfcAdapter mNfcAdapter;
private PendingIntent mPendingIntent;
@Override
protected void onStart() {
	super.onStart();
	mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
	mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass())
			.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);

}

2.4 onResume でフォアグラウンド スケジューリングをオンにして NFC を初期化する

//在onResume中开启前台调度
@Override
protected void onResume() {
	super.onResume();
	//设定intentfilter和tech-list。如果两个都为null就代表优先接收任何形式的TAG action。也就是说系统会主动发TAG intent。
	if (mNfcAdapter != null) {
		mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, null, null); //启动        }
	}
}

2.5 onNewIntent で NFC デバイスによって渡されたインテントを処理する


//在onNewIntent中处理由NFC设备传递过来的intent
@Override
protected void onNewIntent(Intent intent) {
	super.onNewIntent(intent);
	processIntent(intent);
}

2.6 カード ID (通常はデバイスのシリアル番号、16 進形式 09:D1:E6:6B) を含む読み取りデータを処理します。

NFC カードのラベルの情報は入手できない場合がありますが、NFC カードを一意に識別するシリアル番号は入手できる必要があります。

//这块的processIntent() 就是处理卡中数据的方法
public void processIntent(Intent intent) {
	try {
		tvContent.setText("");
		// 检测卡的id
		String id = readNFCId(intent);
		// NfcUtils中获取卡中数据的方法
		String result = readNFCFromTag(intent);
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.append("卡ID十六进制:" + id).append("\r\n");
		stringBuilder.append("卡ID十进制:" + hexToDec(id)).append("\r\n");
		stringBuilder.append("信息:").append("\r\n");
		stringBuilder.append(result).append("\r\n");


		tvContent.setText(stringBuilder);
		
		// 往卡中写数据
		//String data = "this.is.write";
		//writeNFCToTag(data, intent);
	} catch (Exception e) {
		e.printStackTrace();
	}
}

/**
 * 读取nfcID
 */
public String readNFCId(Intent intent) throws UnsupportedEncodingException {
	Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
	String id = ByteArrayToHexString(tag.getId());
	return id;
}


/**
 * 读取NFC的数据
 */
public String readNFCFromTag(Intent intent) throws UnsupportedEncodingException {
	Parcelable[] rawArray = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
	StringBuilder stringBuilder = new StringBuilder();
	if (rawArray != null) {
		for (int i = 0; i < rawArray.length; i++) {
			NdefMessage mNdefMsg = (NdefMessage) rawArray[i];

			for (int j = 0; j < mNdefMsg.getRecords().length; i++) {
				NdefRecord mNdefRecord = mNdefMsg.getRecords()[j];

				if (mNdefRecord != null) {
					String readResult = new String(mNdefRecord.getPayload(), "UTF-8");
					stringBuilder.append(readResult).append("\r\n");
				}
			}
		}
	}
	return stringBuilder.toString();
}


/**
 * 十六进制转10进制
 * @param s
 * @return
 */
public static int hexToDec(String s) {
	String s1 = s.toUpperCase(); // 全转大写
	char[] chars = s1.toCharArray(); // 转成 char 数组
	Stack<Character> stack = new Stack<>();
	for (int i = 0; i < chars.length; i++) {
		stack.push(chars[i]); // 放入栈中,倒序遍历
	}
	int sum = 0;  // 定义总和
	int size = stack.size(); // 要先赋值给 size ,不然 stack.pop() 之后 size 会变
	for (int i = 0; i < size; i++) {
		Character pop = stack.pop();
		if (String.valueOf(pop).matches("[A-F]")) {  // 如果是 A-F
			sum += (Math.pow(16, i) * ((pop - 55))); // A的ASCII码为 65,取偏移量
		} else { // 如果是纯数字
			sum += Math.pow(16, i) * Integer.parseInt(String.valueOf(pop));
		}
	}
	return sum;
}


/**
 * 将字节数组转换为字符串
 */
private 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;
}

2.7 NFC へのデータの書き込み

/**
 * 往nfc写入数据
 */
public static void writeNFCToTag(String data, Intent intent){
	try {
		Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
		Ndef ndef = Ndef.get(tag);
		ndef.connect();
		NdefRecord ndefRecord = null;
		if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
			ndefRecord = NdefRecord.createTextRecord(null, data);
		}
		NdefRecord[] records = {ndefRecord};
		NdefMessage ndefMessage = new NdefMessage(records);
		ndef.writeNdefMessage(ndefMessage);
	}catch (Exception e){

	}
}
// 往卡中写数据
String data = "this.is.write";
writeNFCToTag(data, intent);

 2.8 NfcAdapter スケジュールのキャンセル

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

2.9 NfcAdapter の破棄

@Override
protected void onDestroy() {
	super.onDestroy();
	mNfcAdapter = null;
}

2.10 概要

NFC は、アクセス コントロール カード、支払いカード、地下鉄カードなどのカード スワイプ データ送信シナリオに適しており、高速かつ便利です。

おすすめ

転載: blog.csdn.net/qq_29848853/article/details/130278294