I want to create a mini app just to read an NFC tag and later send to another device on Android. That part is done already and I can read the tag and I can print the string on a EditText. But I also want to send the text that I have read from that tag to another device with NFC. How can I do that?
//I have this code here when a tag is discovered...
#Override
protected void onNewIntent(Intent intent) {
if (intent.getAction().equals(NfcAdapter.ACTION_TAG_DISCOVERED)) {
String result = "";
result = ByteArrayToHexString(intent.getByteArrayExtra(NfcAdapter.EXTRA_ID));
myTag = result;
txtTag.setText(myTag);
}
}
How can I send the text string to another device via NFC?
What you want to do is simply not possible with Android right no (and probably won't be in future).
You currently read the anti-collision identifier (UID, PUPI, or whatever it is called for that specific tag platform that you read):
result = ByteArrayToHexString(intent.getByteArrayExtra(NfcAdapter.EXTRA_ID));
The anti-collision identifier is part of a very low protocol layer. While Android does support host-based card emulation (see Android HCE), the Android API has no means to control such low-level parameters as the UID. Typically, its also not possible to change that information on NFC tags.
Note that if your tag also contains some high-level data in NDEF format you could obtain that using:
Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
NdefMessage msg = null;
if ((rawMsgs != null) && (rawMsgs.length > 0)) {
msg = (NdefMessage)rawMsgs[0];
}
if (msg != null) {
// do something with the received message
}
Android does support storing these NDEF messages on (writable) NFC tags and it also supports sending NDEF messages to other NFC devices (see Beaming NDEF Messages to Other Devices).
E.g. to store an NDEF message on an NFC tag you could use:
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
Ndef ndef = Ndef.get(tag);
if (ndef != null) {
try {
ndef.connect();
ndef.writeNdefMessage(msg);
} finally {
ndef.close();
}
} else {
NdefFormatable ndefFormatable = NdefFormatable.get(tag);
if (ndefFormatable != null) {
try {
ndefFormatable.connect();
ndefFormatable.format(message);
} finally {
ndefFormatable.close();
}
}
}
Or in order to send the message to another NFC device through peer-to-peer mode (Android Beam), you could use:
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
nfcAdapter.setNdefPushMessage(msg, this);
Related
I am trying to use NFC to send a URL from an Android app to other phone,
both have enabled NFC and working fine.
when i tried to test the app nothing happen,
i have tried the following app from store and it work perfectly:
https://play.google.com/store/apps/details?id=com.maxsoft.ndeftagemulator
this is my code:
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (nfcAdapter == null) {
Toast.makeText(this, "NFC not supported on this device.", Toast.LENGTH_LONG).show();
finish();
return;
}
nfcAdapter.setNdefPushMessageCallback(event -> {
String url = "https://www.example.com";
NdefRecord ndefRecord = NdefRecord.createUri(url);
NdefMessage ndefMessage = new NdefMessage(ndefRecord);
return ndefMessage;
}, this);
nfcAdapter.setOnNdefPushCompleteCallback(event -> Toast.makeText(MainActivity.this, "URL sent via NFC.", Toast.LENGTH_LONG).show(), this);
i also added permission in Manifest
<uses-permission android:name="android.permission.NFC" />
i searched for answers here and checked the following with no success ( android API +29 )
Ho do I send a URL via NFC?
Sending URL from Android to Windows Phone via NFC gives Play Store link
Sending URL via NFC to be opened by browser
we are using symbol ls4278 bluetooth scanner to integrate in android application. It is connected as keyboard and types scanned barcode in any edittext field...
After scanner OnKeyUp event is called.
public override bool OnKeyUp(Keycode keyCode, KeyEvent e)
{
..
}
I was searching documentation and android sdk, but I can't found such one. But for LI4278 they have android sdk here : https://www.zebra.com/us/en/support-downloads/scanners/general-purpose-scanners/li4278.html
here is also documentation for sdk but LS4278 is not in supported device list.
Does anyone implemented LS4278 scanner in android devices?
The LS4278 product page is here: https://www.zebra.com/us/en/support-downloads/scanners/general-purpose-scanners/ls4278.html and lists support for the "Windows Scanner SDK" ONLY. The LS4278 was discontinued on September 24th 2012 so I am not surprised it does not have Android support. As you say, its successor, the LI4278 does have Android support. As the other answer states, if you want more control over how you receive data then I suggest trying SPP if the scanner supports it.
If it works as a bluetooth keyboard, then no support is needed. Just capture the key events, and react to the data when enter is pressed. Its just a mediocre experience and can mess with on screen keyboards and stop them from using an actual bluetooth keyboard. If the scanner supports SPP, you can pretty trivially parse the scan data out of it via bluetooth serial (I did this about 2 weeks ago).
BluetoothAdapter bta = BluetoothAdapter.getDefaultAdapter();
if(bta != null) {
Set<BluetoothDevice> devices = bta.getBondedDevices();
for (final BluetoothDevice device : devices) {
BluetoothClass btClass = device.getBluetoothClass();
if (btClass.getMajorDeviceClass() == 0x1f00) {
//Only look at devices which are considered uncategorized, so we don't screw up any bt headset, leyboard, mouse, etc
new DeviceThread(device).start();
}
}
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
if (state == BluetoothDevice.BOND_BONDED) {
new DeviceThread(device).start();
} else if (state == BluetoothDevice.BOND_NONE) {
DeviceThread thread = threadMap.get(device.getAddress());
if (thread != null) {
thread.interrupt();
}
}
}
}, filter);
}
private class DeviceThread extends Thread {
private BluetoothDevice device;
public DeviceThread(BluetoothDevice device) {
this.device = device;
threadMap.put(device.getAddress(), this);
}
#Override
public void run() {
try {
BluetoothSocket socket = device.createInsecureRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
socket.connect();
InputStream inputStream = socket.getInputStream();
while (!Thread.interrupted() && socket.isConnected()) {
inputStream.skip(5);
String data = "";
do {
int code = inputStream.read();
char character = (char) code;
data = data + character;
} while (inputStream.available() > 0);
data = data.substring(0, data.length() - 2);
if (scannerEventListener != null) {
scannerEventListener.onScan(data);
}
}
} catch (IOException ex) {
ex.printStackTrace();
}
Log.d("GABE", "Exiting thread");
}
}
This code will register for bluetooth devices being paired, then check and see if they're unknown device types (scanners don't have a device class). If so, it will start a thread to listen for that device. When its unbonded, it will interrupt that thread. On the thread it opens up a SPP connection to the device and waits for input. When it gets it, it parses the input and sends the result to a listener.
For this to work, the scanner needs to be in SPP mode. Some scanners support it, some don't, and how to set it into that mode varies (the one on my desk has a control barcode I need to scan to set the mode). Generally I would code for it to accept either type of input- hardware keyboard mode or SPP.
I am having an issue with NFC in a project I am currently making for school.
It is the first time I try to use NFC in an application and might therefore not have a proper understanding of how it works.
The issue is that we have been testing the application on a HTC One M8 for the past week, where our application had no problems reading the string on our chip.
However when I'm now trying with a family member's LG Nexus 5, the string does not get passed to the application.
Here is the code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_app);
//NFC Adapter
nfcAdapter = NfcAdapter.getDefaultAdapter(this);
}
#Override
protected void onResume() {
super.onResume();
enableForegroundDispatchSystem();
}
#Override
protected void onPause() {
super.onPause();
disableForegroundDispatchSystem();
}
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if (intent.hasExtra(NfcAdapter.EXTRA_TAG)) {
Toast.makeText(this, "NfcIntent!", Toast.LENGTH_SHORT).show();
Parcelable[] parcelables = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if (parcelables != null && parcelables.length > 0) {
// this part gets executed on the HTC Once m8
readTextFromMessage((NdefMessage) parcelables[0]);
} else {
// this part gets executed on the LG Nexus 5
Toast.makeText(this, "No NDEF messages found!", Toast.LENGTH_SHORT).show();
}
}
}
private void readTextFromMessage(NdefMessage ndefMessage) {
NdefRecord[] ndefRecords = ndefMessage.getRecords();
if (ndefRecords != null && ndefRecords.length>0) {
NdefRecord ndefRecord = ndefRecords[0];
String tagContent = getTextFromNdefRecord(ndefRecord);
if (tagContent.toString().equals("Kasse")) {
//scanBtn.setVisibility(View.VISIBLE);
} else {
//addItem(tagContent);
//cartArrayDisplay.addView(nameList.get(cartAmount));
//priceArrayDisplay.addView(priceList.get(cartAmount));
//cartAmount++;
}
} else {
Toast.makeText(this, "No NDEF records found!", Toast.LENGTH_SHORT).show();
}
}
private void enableForegroundDispatchSystem() {
Intent intent = new Intent(this, AppActivity.class).addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
IntentFilter[] intentFilters = new IntentFilter[]{};
nfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFilters, null);
}
private void disableForegroundDispatchSystem() {
nfcAdapter.disableForegroundDispatch(this);
}
public String getTextFromNdefRecord(NdefRecord ndefRecord) {
String tagContent = null;
try {
byte[] payload = ndefRecord.getPayload();
String textEncoding = ((payload[0] & 128) == 0) ? "UTF-8" : "UTF-16";
int languageSize = payload[0] & 0063;
tagContent = new String(payload, languageSize + 1,
payload.length - languageSize - 1, textEncoding);
} catch (UnsupportedEncodingException e) {
Log.e("getTextFromNdefRecord", e.getMessage(), e);
}
return tagContent;
}
When run the app on the HTC One m8 it would always run this part:
if (parcelables != null && parcelables.length > 0) {
readTextFromMessage((NdefMessage) parcelables[0]);
However, when run the app on the LG Nexus 5 it runs this part:
} else {
Toast.makeText(this, "No NDEF messages found!", Toast.LENGTH_SHORT).show();
I have been told that it is most likely due to the tags we're using not being compatible with all devices. However, I thought it could also be something programmatically, since I am not experienced working with Android and NFC.
The tags are student IDs. A tag reader app identified one of them as
Tag Type: Mifare Classic 1k
NUID[4]: dbc3f12d
ATQA: 0004
SAK: 08
Target technology: android.nfc.tech.NfcA
The problem you are experiencing is a result of the NFC chipset in your device not being compatible with MIFARE Classic. Typically, only devices with an NFC chipset from NXP are capable of reading MIFARE Classic (NXP is the owner of the MIFARE technology).
MIFARE Classic uses the anti-collision and activation mechanism defined in ISO/IEC 14443 Type A (and also ISO/IEC 18092). Therefore, that part matches the way other contactless smartcards and NFC tags work. As a result, all (most!) Android NFC devices will detect such cards/tags. However, the communication protocol and framing deviates from that defined for other NFC tags and contactless smartcards. This non-standard protocol is not available on other chipsets than those by NXP and therefore, no data can be read from MIFARE Classic cards on devices with non-NXP NFC controllers.
The HTC One m8 contains NXP's PN544 NFC controller and can therefore discover your tag and read data from it. The LG Nexus 5 contains Broadcom's BCM20793 NFC controller and can therefore discover your tag but is unable to read data from it.
On top of what Michael said, you can check whether your device supports Mifare Classic with
PackageManager.hasSystemFeature("com.nxp.mifare");
I have an android application with a webview in it.
When the webview is getting to url with certain text, e.g. ticket, then I would like to send the url to another NFC device through NFC.
I was able to send the url to the type 4 NFC tag, but I am not able to find out how to send it to other NFC device so that it will launch the browser with the url.
I was just using the following to create the NDEF
NdefRecord uriRecord = NdefRecord.createUri(url);
NdefMessage message = new NdefMessage(new NdefRecord[] {
uriRecord
});
and then use this to write
ndef.writeNdefMessage(message);
I am writing the app in ICS (on galaxy nexus) and trying to send to the galaxy s2 with 2.3.6.
Any help and pointer will be appreciated.
When sending an NDEF message to another phone, you don't use a tag read/write API such as Ndef. Instead, your NDEF message is delivered via NFC peer-to-peer. One way to do that is to use setNdefPushMessageCallback in your Activity's onCreate():
NfcAdapter nfc = NfcAdapter.getDefaultAdapter(this);
nfc.setNdefPushMessageCallback(new NfcAdapter.CreateNdefMessageCallback()
{
/*
* (non-Javadoc)
* #see android.nfc.NfcAdapter.CreateNdefMessageCallback#createNdefMessage(android.nfc.NfcEvent)
*/
#Override
public NdefMessage createNdefMessage(NfcEvent event)
{
NdefRecord uriRecord = NdefRecord.createUri(Uri.encode("http://www.google.com/"));
return new NdefMessage(new NdefRecord[] { uriRecord });
}
}, this, this);
The callback will be called when another NFC device comes near and a peer-to-peer connection is established. The callback then creates the NDEF message to be sent (in your case: the URL displayed in the webview).
I would like to know the answer for the following questions:
Identify device types (Type A , B or Felica)
Ways to open communication between the external POS
Code samples and how to test them?
Tag type identification example:
Intent intent = getIntent();
if (intent.hasExtra(NfcAdapter.EXTRA_TAG)) {
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG));
if(NfcA.get(tag) != null)
Toast.makeText(this, "Type A tag found!", Toast.LENGTH_LONG).show();
else if(NfcB.get(tag) != null)
Toast.makeText(this, "Type B tag found!", Toast.LENGTH_LONG).show();
else if(NfcF.get(tag) != null)
Toast.makeText(this, "FeliCa tag found!", Toast.LENGTH_LONG).show();
else if(NfcV.get(tag) != null)
Toast.makeText(this, "ISO15693 tag found!", Toast.LENGTH_LONG).show();
else if(Ndef.get(tag) != null)
Toast.makeText(this, "Android Beam message received!", Toast.LENGTH_LONG).show();
else
Toast.makeText(this, "Unknown tag type!", Toast.LENGTH_LONG).show(); // hypothetical...
}
There is no API defined in Android to communicate with an external reader. You could consider implementing peer-to-peer communication in the reader, using LLCP and SNEP (see NFC Forum for the specs).