通过 NFC 发送 NdefRecord 但接收 android.nfc.tech.IsoDep
Sending NdefRecord via NFC but Receiving android.nfc.tech.IsoDep
我已经为 NFC 创建了两个应用程序。 1. NFC 发送器 2. NFC 接收器。 NFC Sender 向 NFC Receiver App 发送简单的文本数据。但是我这里有一个大问题。
我无法从 NFC 读取简单的文本。我使用 NFC 发送的文本格式是 NdefRecord。
1. NFC 发送器 Activity 代码:
public class MainActivity extends AppCompatActivity {
private Button btnPay;
private LinearLayout llRootView;
private NfcAdapter mNfcAdapter;
private EditText edtAmount;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnPay = findViewById(R.id.btnPay);
llRootView = findViewById(R.id.rootView);
edtAmount = findViewById(R.id.etAmount);
btnPay.setOnClickListener(view -> {
hideKeyboard(MainActivity.this);
if (TextUtils.isEmpty(edtAmount.getText().toString().trim())) {
Snackbar.make(llRootView, "Please enter valid value.", Snackbar.LENGTH_SHORT).show();
return;
}
startNFC();
});
}
private void startNFC() {
//Check if NFC is available on device
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (mNfcAdapter != null) {
//This will be called if the message is sent successfully
mNfcAdapter.setOnNdefPushCompleteCallback(event -> runOnUiThread(() ->
Toast.makeText(MainActivity.this, "Message sent.", Toast.LENGTH_SHORT)
.show()), this);
//This will refer back to createNdefMessage for what it will send
mNfcAdapter.setNdefPushMessageCallback(event -> new NdefMessage(createRecords()), this);
Snackbar.make(llRootView, "Please attach receiver device to back of your device.", Snackbar.LENGTH_INDEFINITE).show();
} else {
Toast.makeText(this, "NFC not available on this device",
Toast.LENGTH_SHORT).show();
}
}
private NdefRecord[] createRecords() {
//Api is high enough that we can use createMime, which is preferred.
NdefRecord record = NdefRecord.createMime("text/plain", edtAmount.getText().toString().trim().getBytes(StandardCharsets.UTF_8));
return new NdefRecord[]{
record
, NdefRecord.createApplicationRecord("com.example.nfcreceiver")
};
}
public static void hideKeyboard(Activity activity) {
InputMethodManager imm = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
//Find the currently focused view, so we can grab the correct window token from it.
View view = activity.getCurrentFocus();
//If no view currently has focus, create a new one, just so we can grab a window token from it
if (view == null) {
view = new View(activity);
}
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
}
2。 NFC 接收器清单:
<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" />
<action android:name="android.nfc.action.TAG_DISCOVERED" />
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
3。 NFC 接收器 Activity 代码:
public class MainActivity extends AppCompatActivity {
NfcAdapter mAdapter;
PendingIntent mPendingIntent;
TextView tvReceived, tvTagTech;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvReceived = findViewById(R.id.tvReceived);
tvTagTech = findViewById(R.id.tvTagList);
Initialization();
}
@Override
protected void onResume() {
super.onResume();
if (!WebConstant.isOnline()) {
Snackbar.make(tvReceived, R.string.str_no_internet_connection, Snackbar.LENGTH_LONG).show();
}
resolveIntent(getIntent());
if (mAdapter != null) {
if (!mAdapter.isEnabled()) {
Toast.makeText(this, "NFC Not Enabled", Toast.LENGTH_LONG).show();
}
mAdapter.enableForegroundDispatch(this, mPendingIntent, null, null);
}
}
@Override
protected void onPause() {
super.onPause();
if (mAdapter != null) {
mAdapter.disableForegroundDispatch(this);
}
}
private void Initialization() {
mAdapter = NfcAdapter.getDefaultAdapter(this);
if (mAdapter == null) {
Toast.makeText(this, "NFC Not found", Toast.LENGTH_LONG).show();
// finish();
return;
}
mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,
getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
}
@Override
protected void onNewIntent(final Intent intent) {
super.onNewIntent(intent);
new Handler().postDelayed(() -> {
setIntent(intent);
}, 0);
}
private void resolveIntent(Intent intent) {
String action = intent.getAction();
Log.d("ActionType", action);
if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)
|| NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)
|| NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
getTagInfo(intent);
}
}
private void getTagInfo(Intent intent) {
sendToFirebase(intent);
}
private void sendToFirebase(Intent intent) {
String title, message;
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
NdefMessage[] messages = getNdefMessages(intent);
if (messages != null && messages.length > 0) {
title = "Success";
message = "Received NDEF Messages";
showAlert(title, message);
try {
String msg = new String(messages[0].getRecords()[0].getPayload(), StandardCharsets.UTF_8);
message = String.format("You received %sQAR", msg);
tvReceived.setText(message);
} catch (Exception e) {
e.printStackTrace();
title = "Error";
message = e.getLocalizedMessage();
showAlert(title, message);
}
} else {
title = "Failure";
message = "Received empty NDEF Messages";
showAlert(title, message);
}
} else {
title = "Failure";
message = "Received non NDEF Messages";
showAlert(title, message);
}
Map<String, Object> body = new HashMap<>();
body.put("Title", title);
body.put("Message", message);
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
if (tag != null) {
body.put("TagList", Arrays.toString(tag.getTechList()));
} else {
body.put("TagList", "");
}
RestClient.getInstance().push("NFCDetails", body, mResponse -> {
});
}
private NdefMessage[] getNdefMessages(Intent intent) {
Parcelable[] rawMessages = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if (rawMessages != null) {
NdefMessage[] messages = new NdefMessage[rawMessages.length];
for (int i = 0; i < messages.length; i++) {
messages[i] = (NdefMessage) rawMessages[i];
}
return messages;
} else {
return null;
}
}
public void showAlert(String title, String message) {
AlertDialog dialog = new AlertDialog.Builder(this)
.create();
dialog.setTitle(title);
dialog.setMessage(message);
dialog.setButton(DialogInterface.BUTTON_POSITIVE, "OK", (dialog1, which) -> dialog1.dismiss());
dialog.show();
}
}
请帮我解决这个难题。
我在 Receiver 应用程序中接收到的标签技术如下:
[android.nfc.tech.IsoDep, android.nfc.tech.NfcA]
Android 光束是 deprecated in Android 10
因此 Pixel phone 无法通过您尝试使用的此方法发送或接收从其他旧 Android phone 发送的 NDEF 消息。
更新:
您看到的 IsoDep 标签很可能是由设备中 NFC 硬件的安全元件部分生成的,作为 NFC 钱包类型功能的一部分,可以保存您的非接触式银行卡详细信息。你会像阅读非接触式银行卡一样阅读这篇文章,使用正确的 AID 和更高级别的协议和标准(但如果你没有将 credit/debit 卡加载到 Google 钱包,它会赢不响应 credit/debit 卡片的任何标准 AID)
您在 IsoDep 级别真正可以读取的唯一内容是随机生成的 UID。
Android 允许您进行主机卡仿真 (HCE),它允许您设置对选定 AID 查询的响应。 NDef 数据有一个 AID,因此使用 HCE 您可以复制 Android 光束类型功能,但这很复杂。
在 2 台设备之间发送数据的推荐方式是通过蓝牙或 Wifi Direct
我已经为 NFC 创建了两个应用程序。 1. NFC 发送器 2. NFC 接收器。 NFC Sender 向 NFC Receiver App 发送简单的文本数据。但是我这里有一个大问题。
我无法从 NFC 读取简单的文本。我使用 NFC 发送的文本格式是 NdefRecord。
1. NFC 发送器 Activity 代码:
public class MainActivity extends AppCompatActivity {
private Button btnPay;
private LinearLayout llRootView;
private NfcAdapter mNfcAdapter;
private EditText edtAmount;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnPay = findViewById(R.id.btnPay);
llRootView = findViewById(R.id.rootView);
edtAmount = findViewById(R.id.etAmount);
btnPay.setOnClickListener(view -> {
hideKeyboard(MainActivity.this);
if (TextUtils.isEmpty(edtAmount.getText().toString().trim())) {
Snackbar.make(llRootView, "Please enter valid value.", Snackbar.LENGTH_SHORT).show();
return;
}
startNFC();
});
}
private void startNFC() {
//Check if NFC is available on device
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (mNfcAdapter != null) {
//This will be called if the message is sent successfully
mNfcAdapter.setOnNdefPushCompleteCallback(event -> runOnUiThread(() ->
Toast.makeText(MainActivity.this, "Message sent.", Toast.LENGTH_SHORT)
.show()), this);
//This will refer back to createNdefMessage for what it will send
mNfcAdapter.setNdefPushMessageCallback(event -> new NdefMessage(createRecords()), this);
Snackbar.make(llRootView, "Please attach receiver device to back of your device.", Snackbar.LENGTH_INDEFINITE).show();
} else {
Toast.makeText(this, "NFC not available on this device",
Toast.LENGTH_SHORT).show();
}
}
private NdefRecord[] createRecords() {
//Api is high enough that we can use createMime, which is preferred.
NdefRecord record = NdefRecord.createMime("text/plain", edtAmount.getText().toString().trim().getBytes(StandardCharsets.UTF_8));
return new NdefRecord[]{
record
, NdefRecord.createApplicationRecord("com.example.nfcreceiver")
};
}
public static void hideKeyboard(Activity activity) {
InputMethodManager imm = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
//Find the currently focused view, so we can grab the correct window token from it.
View view = activity.getCurrentFocus();
//If no view currently has focus, create a new one, just so we can grab a window token from it
if (view == null) {
view = new View(activity);
}
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
}
2。 NFC 接收器清单:
<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" />
<action android:name="android.nfc.action.TAG_DISCOVERED" />
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
3。 NFC 接收器 Activity 代码:
public class MainActivity extends AppCompatActivity {
NfcAdapter mAdapter;
PendingIntent mPendingIntent;
TextView tvReceived, tvTagTech;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvReceived = findViewById(R.id.tvReceived);
tvTagTech = findViewById(R.id.tvTagList);
Initialization();
}
@Override
protected void onResume() {
super.onResume();
if (!WebConstant.isOnline()) {
Snackbar.make(tvReceived, R.string.str_no_internet_connection, Snackbar.LENGTH_LONG).show();
}
resolveIntent(getIntent());
if (mAdapter != null) {
if (!mAdapter.isEnabled()) {
Toast.makeText(this, "NFC Not Enabled", Toast.LENGTH_LONG).show();
}
mAdapter.enableForegroundDispatch(this, mPendingIntent, null, null);
}
}
@Override
protected void onPause() {
super.onPause();
if (mAdapter != null) {
mAdapter.disableForegroundDispatch(this);
}
}
private void Initialization() {
mAdapter = NfcAdapter.getDefaultAdapter(this);
if (mAdapter == null) {
Toast.makeText(this, "NFC Not found", Toast.LENGTH_LONG).show();
// finish();
return;
}
mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,
getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
}
@Override
protected void onNewIntent(final Intent intent) {
super.onNewIntent(intent);
new Handler().postDelayed(() -> {
setIntent(intent);
}, 0);
}
private void resolveIntent(Intent intent) {
String action = intent.getAction();
Log.d("ActionType", action);
if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)
|| NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)
|| NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
getTagInfo(intent);
}
}
private void getTagInfo(Intent intent) {
sendToFirebase(intent);
}
private void sendToFirebase(Intent intent) {
String title, message;
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
NdefMessage[] messages = getNdefMessages(intent);
if (messages != null && messages.length > 0) {
title = "Success";
message = "Received NDEF Messages";
showAlert(title, message);
try {
String msg = new String(messages[0].getRecords()[0].getPayload(), StandardCharsets.UTF_8);
message = String.format("You received %sQAR", msg);
tvReceived.setText(message);
} catch (Exception e) {
e.printStackTrace();
title = "Error";
message = e.getLocalizedMessage();
showAlert(title, message);
}
} else {
title = "Failure";
message = "Received empty NDEF Messages";
showAlert(title, message);
}
} else {
title = "Failure";
message = "Received non NDEF Messages";
showAlert(title, message);
}
Map<String, Object> body = new HashMap<>();
body.put("Title", title);
body.put("Message", message);
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
if (tag != null) {
body.put("TagList", Arrays.toString(tag.getTechList()));
} else {
body.put("TagList", "");
}
RestClient.getInstance().push("NFCDetails", body, mResponse -> {
});
}
private NdefMessage[] getNdefMessages(Intent intent) {
Parcelable[] rawMessages = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if (rawMessages != null) {
NdefMessage[] messages = new NdefMessage[rawMessages.length];
for (int i = 0; i < messages.length; i++) {
messages[i] = (NdefMessage) rawMessages[i];
}
return messages;
} else {
return null;
}
}
public void showAlert(String title, String message) {
AlertDialog dialog = new AlertDialog.Builder(this)
.create();
dialog.setTitle(title);
dialog.setMessage(message);
dialog.setButton(DialogInterface.BUTTON_POSITIVE, "OK", (dialog1, which) -> dialog1.dismiss());
dialog.show();
}
}
请帮我解决这个难题。
我在 Receiver 应用程序中接收到的标签技术如下:
[android.nfc.tech.IsoDep, android.nfc.tech.NfcA]
Android 光束是 deprecated in Android 10
因此 Pixel phone 无法通过您尝试使用的此方法发送或接收从其他旧 Android phone 发送的 NDEF 消息。
更新: 您看到的 IsoDep 标签很可能是由设备中 NFC 硬件的安全元件部分生成的,作为 NFC 钱包类型功能的一部分,可以保存您的非接触式银行卡详细信息。你会像阅读非接触式银行卡一样阅读这篇文章,使用正确的 AID 和更高级别的协议和标准(但如果你没有将 credit/debit 卡加载到 Google 钱包,它会赢不响应 credit/debit 卡片的任何标准 AID)
您在 IsoDep 级别真正可以读取的唯一内容是随机生成的 UID。
Android 允许您进行主机卡仿真 (HCE),它允许您设置对选定 AID 查询的响应。 NDef 数据有一个 AID,因此使用 HCE 您可以复制 Android 光束类型功能,但这很复杂。
在 2 台设备之间发送数据的推荐方式是通过蓝牙或 Wifi Direct