From 9c11fb9a45b0f1ff2a86eb139078e5361216434b Mon Sep 17 00:00:00 2001 From: zuoxiao <470321431@qq.com> Date: 星期三, 29 十一月 2023 14:59:10 +0800 Subject: [PATCH] 读取模拟卡修改后注释(未完成) --- app/src/main/java/com/dayu/recharge/tools/NFCWriteHelper.java | 1 app/src/main/java/com/dayu/recharge/tools/CustomIsoDepReader.java | 35 ++++++++ app/src/main/java/com/dayu/recharge/activity/BaseNfcActivity.java | 43 ++++++++-- app/src/main/AndroidManifest.xml | 3 app/src/main/java/com/dayu/recharge/tools/LoyaltyCardReader.java | 156 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 227 insertions(+), 11 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a680c04..39721f4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -92,7 +92,8 @@ android:exported="true" android:launchMode="singleTop"> <intent-filter> - <action android:name="android.nfc.action.TAG_DISCOVERED" /> + <action android:name="android.nfc.action.ACTION_NDEF_DISCOVERED" /> + <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="text/plain" /> </intent-filter> </activity> diff --git a/app/src/main/java/com/dayu/recharge/activity/BaseNfcActivity.java b/app/src/main/java/com/dayu/recharge/activity/BaseNfcActivity.java index 66804f1..fa0d0f9 100644 --- a/app/src/main/java/com/dayu/recharge/activity/BaseNfcActivity.java +++ b/app/src/main/java/com/dayu/recharge/activity/BaseNfcActivity.java @@ -13,10 +13,12 @@ import android.nfc.NfcAdapter; import android.nfc.NfcEvent; import android.nfc.Tag; +import android.nfc.cardemulation.CardEmulation; import android.os.Handler; import android.os.Message; import com.dayu.recharge.card.UserCard; +import com.dayu.recharge.tools.LoyaltyCardReader; import com.dayu.recharge.tools.NfcReadHelper; import com.dayu.recharge.utils.LogUtil; import com.dayu.recharge.utils.TipUtil; @@ -34,7 +36,7 @@ * 鍦╫nNewIntent鏂规硶涓墽琛宨ntent浼犻�掕繃鏉ョ殑Tag鏁版嵁 * 灏哊FC鏍囩鍗¢潬杩戞墜鏈哄悗閮紙NFC鏍囩鍗″彲缃戜笂鑷璐拱锛� */ -public class BaseNfcActivity extends BaseActivity { +public class BaseNfcActivity extends BaseActivity implements LoyaltyCardReader.AccountCallback { /** * 璇ュ崱宸插啓鍏ョ敤鎴蜂俊鎭� @@ -57,25 +59,29 @@ volatile UserCard userCard; Handler handler; + public LoyaltyCardReader mLoyaltyCardReader; /** * onCreat->onStart->onResume->onPause->onStop->onDestroy * 鍚姩Activity锛岀晫闈㈠彲瑙佹椂. */ + + public static int READER_FLAGS = + NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK; + @Override protected void onStart() { super.onStart(); //姝ゅadapter闇�瑕侀噸鏂拌幏鍙栵紝鍚﹀垯鏃犳硶鑾峰彇message mNfcAdapter = NfcAdapter.getDefaultAdapter(this); - -// mNfcAdapter.enableReaderMode(this, new NfcAdapter.ReaderCallback() { -// @Override -// public void onTagDiscovered(Tag tag) { -// LogUtil.e(tag.toString()); -// } -// }, NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK, null); + Intent intent = new Intent(this, getClass()); //涓�鏃︽埅鑾種FC娑堟伅锛屽氨浼氶�氳繃PendingIntent璋冪敤绐楀彛 - mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()), 0); + mPendingIntent = PendingIntent.getActivity(this, 0, intent, 0); + +// mLoyaltyCardReader = new LoyaltyCardReader(this); +// if (mNfcAdapter != null) { +// mNfcAdapter.enableReaderMode(this, mLoyaltyCardReader, READER_FLAGS, null); +// } } @@ -102,6 +108,15 @@ //鎭㈠榛樿鐘舵�� if (mNfcAdapter != null) mNfcAdapter.disableForegroundDispatch(this); +// mNfcAdapter.disableReaderMode(this); + + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (mNfcAdapter != null) + mNfcAdapter.disableReaderMode(this); } /** @@ -120,4 +135,14 @@ } return true; } + + + @Override + public void onAccountReceived(Tag tag) { + + Intent intent = new Intent(this, getClass()); + intent.putExtra(NfcAdapter.EXTRA_TAG, tag); + startActivity(intent); + + } } diff --git a/app/src/main/java/com/dayu/recharge/tools/CustomIsoDepReader.java b/app/src/main/java/com/dayu/recharge/tools/CustomIsoDepReader.java new file mode 100644 index 0000000..c9b140d --- /dev/null +++ b/app/src/main/java/com/dayu/recharge/tools/CustomIsoDepReader.java @@ -0,0 +1,35 @@ +package com.dayu.recharge.tools; + +import android.nfc.Tag; +import android.nfc.tech.TagTechnology; + +import java.io.IOException; + +/** + * Created by Android Studio. + * author: zuo + * Date: 2023-11-29 + * Time: 9:13 + * 澶囨敞锛� + */ +public class CustomIsoDepReader implements TagTechnology { + @Override + public Tag getTag() { + return null; + } + + @Override + public void connect() throws IOException { + + } + + @Override + public void close() throws IOException { + + } + + @Override + public boolean isConnected() { + return false; + } +} diff --git a/app/src/main/java/com/dayu/recharge/tools/LoyaltyCardReader.java b/app/src/main/java/com/dayu/recharge/tools/LoyaltyCardReader.java new file mode 100644 index 0000000..b80f6d7 --- /dev/null +++ b/app/src/main/java/com/dayu/recharge/tools/LoyaltyCardReader.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.dayu.recharge.tools; + +import android.annotation.TargetApi; +import android.nfc.NfcAdapter; +import android.nfc.Tag; +import android.nfc.tech.IsoDep; +import android.os.Build; +import android.util.Log; + + +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.util.Arrays; + +/** + * Callback class, invoked when an NFC card is scanned while the device is running in reader mode. + * <p> + * Reader mode can be invoked by calling NfcAdapter + */ +@TargetApi(Build.VERSION_CODES.KITKAT) +public class LoyaltyCardReader implements NfcAdapter.ReaderCallback { + private static final String TAG = "LoyaltyCardReader"; + // AID for our loyalty card service. + private static final String SAMPLE_LOYALTY_CARD_AID = "F0010203040507"; + // ISO-DEP command HEADER for selecting an AID. + // Format: [Class | Instruction | Parameter 1 | Parameter 2] + private static final String SELECT_APDU_HEADER = "00A40400"; + // "OK" status word sent in response to SELECT AID command (0x9000) + private static final byte[] SELECT_OK_SW = {(byte) 0x10, (byte) 0x00}; + + // Weak reference to prevent retain loop. mAccountCallback is responsible for exiting + // foreground mode before it becomes invalid (e.g. during onPause() or onStop()). + private WeakReference<AccountCallback> mAccountCallback; + + public interface AccountCallback { + public void onAccountReceived(Tag tag); + } + + public LoyaltyCardReader(AccountCallback accountCallback) { + mAccountCallback = new WeakReference<AccountCallback>(accountCallback); + } + + /** + * Callback when a new tag is discovered by the system. + * + * <p>Communication with the card should take place here. + * + * @param tag Discovered tag + */ + @Override + public void onTagDiscovered(Tag tag) { + Log.i(TAG, "New tag discovered"); + mAccountCallback.get().onAccountReceived(tag); + // Android's Host-based Card Emulation (HCE) feature implements the ISO-DEP (ISO 14443-4) + // protocol. + // + // In order to communicate with a device using HCE, the discovered tag should be processed + // using the IsoDep class. + IsoDep isoDep = IsoDep.get(tag); + if (isoDep != null) { + try { + // Connect to the remote NFC device + isoDep.connect(); + // Build SELECT AID command for our loyalty card service. + // This command tells the remote device which service we wish to communicate with. + Log.i(TAG, "Requesting remote AID: " + SAMPLE_LOYALTY_CARD_AID); +// mAccountCallback.get().onAccountReceived(); + byte[] command = BuildSelectApdu(SAMPLE_LOYALTY_CARD_AID); + + // Send command to remote device + Log.i(TAG, "Sending: " + ByteArrayToHexString(command)); +// mAccountCallback.get().onAccountReceived(); + byte[] result = isoDep.transceive(command); + // If AID is successfully selected, 0x9000 is returned as the status word (last 2 + // bytes of the result) by convention. Everything before the status word is + // optional payload, which is used here to hold the account number. + int resultLength = result.length; + byte[] statusWord = {result[resultLength - 2], result[resultLength - 1]}; + byte[] payload = Arrays.copyOf(result, resultLength - 2); + if (Arrays.equals(SELECT_OK_SW, statusWord)) { + // The remote NFC device will immediately respond with its stored account number + String accountNumber = new String(payload, "UTF-8"); + Log.i(TAG, "Received: " + accountNumber); + // Inform CardReaderFragment of received account number +// mAccountCallback.get().onAccountReceived(); + } + } catch (IOException e) { + Log.e(TAG, "Error communicating with card: " + e.toString()); + } + } + } + + /** + * Build APDU for SELECT AID command. This command indicates which service a reader is + * interested in communicating with. See ISO 7816-4. + * + * @param aid Application ID (AID) to select + * @return APDU for SELECT AID command + */ + public static byte[] BuildSelectApdu(String aid) { + // Format: [CLASS | INSTRUCTION | PARAMETER 1 | PARAMETER 2 | LENGTH | DATA] + return HexStringToByteArray(SELECT_APDU_HEADER + String.format("%02X", aid.length() / 2) + aid); + } + + /** + * Utility class to convert a byte array to a hexadecimal string. + * + * @param bytes Bytes to convert + * @return String, containing hexadecimal representation. + */ + public static String ByteArrayToHexString(byte[] bytes) { + final char[] hexArray = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + char[] hexChars = new char[bytes.length * 2]; + int v; + for (int j = 0; j < bytes.length; j++) { + v = bytes[j] & 0xFF; + hexChars[j * 2] = hexArray[v >>> 4]; + hexChars[j * 2 + 1] = hexArray[v & 0x0F]; + } + return new String(hexChars); + } + + /** + * Utility class to convert a hexadecimal string to a byte string. + * + * <p>Behavior with input strings containing non-hexadecimal characters is undefined. + * + * @param s String containing hexadecimal characters to convert + * @return Byte array generated from input + */ + public static byte[] HexStringToByteArray(String s) { + int len = s.length(); + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + + Character.digit(s.charAt(i + 1), 16)); + } + return data; + } + +} diff --git a/app/src/main/java/com/dayu/recharge/tools/NFCWriteHelper.java b/app/src/main/java/com/dayu/recharge/tools/NFCWriteHelper.java index ee9b31a..1dc2d29 100644 --- a/app/src/main/java/com/dayu/recharge/tools/NFCWriteHelper.java +++ b/app/src/main/java/com/dayu/recharge/tools/NFCWriteHelper.java @@ -34,7 +34,6 @@ public NFCWriteHelper(Intent intent) { this.tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); - } /** -- Gitblit v1.8.0