I have created Two App for NFC. 1. NFC Sender 2. NFC Receiver. NFC Sender sends simple text data to NFC Receiver App. But I am in a big problem here.
I am unable to read simple text from NFC. The text format I am sending using NFC is NdefRecord.
1. NFC Sender Activity code :
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 Receiver Manifest :
<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 Receiver Activity Code :
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();
}
}
Please Help me to solve this puzzle.
The tag technology I am receiving in the Receiver app is below :
[android.nfc.tech.IsoDep, android.nfc.tech.NfcA]
Android Beam was deprecated in Android 10
Therefore the Pixel phone does not have the capability to send or receive NDEF messages sent from other old Android phones via this method you are trying to use.
Update: The IsoDep Tag you are seeing is most likely being generated by the secure element part of the NFC hardware in the device as part of the NFC wallet type functionality that can hold your contactless bank card details. You would read this as though you were reading a contactless bank cards with, using the right AID's and higher level protocols and standards (But if you have not loaded a credit/debit card in to Google Wallet, it won't respond to any of the standard AID's for credit/debit cards)
The only thing you could really read from at the IsoDep level is a randomly generated UID.
Android does allow you to do Host Card Emulation (HCE) which allows you to set the response to selected AID queries. There is an AID for NDef data, thus using HCE you could replicate the Android Beam type funtionality, but this is complicated.
The recommended way to send data between 2 devices is via Bluetooth or Wifi Direct