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).
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
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);
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've got a problem using wifi direct. I managed to connect 2 devices and send data from the client to the group owner, because the group owner ip is the one that everybody knows. I managed also to find out the IP of the client and pass it to the group owner but I can't send data from the group owner to the client, even if it should be simmetric. I'm using Intent and startService() to send data and AsynkTask for receive. Using only 2 devices I noticed that the client IP is always the same (192.168.49.10), so I give it to the intent manually.
Here's the method where I'm trying to create the sender for the owner and the receiver for the client:
#Override
public void onConnectionInfoAvailable(final WifiP2pInfo info) {
// InetAddress from WifiP2pInfo struct.
InetAddress groupOwnerAddress = info.groupOwnerAddress;
connected = true;
ownerIP = groupOwnerAddress.getHostAddress();
// After the group negotiation, we can determine the group owner.
if (info.groupFormed && info.isGroupOwner) {
Toast.makeText(MainActivity.this, "I'm the owner!!", Toast.LENGTH_SHORT).show();
owner = true;
// Do whatever tasks are specific to the group owner.
// One common case is creating a server thread and accepting
// incoming connections.
Intent serviceIntent = new Intent(MainActivity.this, OwnerSender.class);
serviceIntent.setAction(OwnerSender.ACTION_SEND);
serviceIntent.putExtra(OwnerSender.EXTRAS_CLIENT_ADDRESS,"192.168.49.10");
serviceIntent.putExtra(OwnerSender.EXTRAS_CLIENT_PORT, 8988);
startService(serviceIntent);
//new OwnerReceiver(this).execute(); // owner riceve dai client sulla porta 8988
} else if (info.groupFormed) {
// The other device acts as the client. In this case,
// you'll want to create a client thread that connects to the group
// owner.
/*Intent serviceIntent = new Intent(MainActivity.this, ClientSender.class);
serviceIntent.setAction(ClientSender.ACTION_SEND);
serviceIntent.putExtra(ClientSender.EXTRAS_GROUP_OWNER_ADDRESS,ownerIP);
serviceIntent.putExtra(ClientSender.EXTRAS_GROUP_OWNER_PORT, 8988);
startService(serviceIntent);*/
new ClientReceiver(this).execute(); // i client ricevono dall'owner sula porta 8989
Toast.makeText(MainActivity.this, "I'm a client...", Toast.LENGTH_SHORT).show();
Toast.makeText(MainActivity.this, "Server IP: " + groupOwnerAddress.getHostAddress(), Toast.LENGTH_SHORT).show();
}
}
This method starts when the connection is established and the owner should start the service to send the data, but the service never starts. How I already said, the same service starts if it's used on the client side and the data is transferred correctly from the client to the owner.
Like Laszlo Magyar said, you need to sent an empty message to server first so that server can use client socket to get the incoming ip address.
My solution is to send an string to server from client so server CAN know the client's ip address, and the rest of process is the same.
As the title suggests, I am developing an app, which can connect and pair with another Android phone. I can successfully scan, connect, pair and transmit String data over bluetooth. I tested by sending String data and received it in another android smartphone and showed it in the toast.
The actual scenario
This application will be installed in both android phones. Once another android phone scans and connect to the phone over bluetooth, then I want to launch this app. I know we can accomplish this using BroadcastReceiver. But how can I implement this in terms of Bluetooth connection. Any code snippet or idea or suggestions are welcomed..
After you get the BT msg,Hope you followed this link ,Here after "// Send the obtained bytes to the UI activity"
Send a broadcast to start your app.
Loop with the list of apps installed and know which app to be launched and use the below to launch a app.
public String getPreInstalledPocPkgName(){
String pkgName = null;
try {
List<PackageInfo> pkgInfoList = mContext.getPackageManager().getInstalledPackages(0);
for(PackageInfo pkgInfo:pkgInfoList){
pkgName = pkgInfo.packageName;
if(pkgName==null || pkgName.equals("")){
continue;
}
for(String name:pttPkgList){
if(pkgName.equals(name)){
Log.d(TAG, "------------ app with package name ["+pkgName+"] already installed----------");
return pkgName;
}
}
}
} catch (Exception e) {
Log.e(TAG, "-------Error! while fetching previously installed app------", e);
clearConfigFromSharedPath();
}
Log.d(TAG, "------------No previously installed app----------");
return null;
}
}
String pttAppPkgName = getPreInstalledPocPkgName();
Or
pttAppPkgName = your app package.
PackageManager pm = getPackageManager();
Intent intent = pm.getLaunchIntentForPackage(pttAppPkgName);
startActivity(intent);