Android Tutorial NFC - Reading and Writing

Status
Not open for further replies.

Erel

Administrator
Staff member
Licensed User
NFC v2.00 adds support for low level access to the NFC features. This allows reading and writing from NFC tags.

The NFC library provides three features:
- Reading Ndef tags based intent filters: Reading NDEF data from NFC tags
- Sending data between two devices (Android Beam): https://www.b4x.com/android/forum/threads/60731/#content
- Low level access to the tag.

This tutorial explains how you can use the low level access to read and write Ndef tags. It is also possible to extend it to other types of tags. However you will need to implement the required protocol yourself.

upload_2016-3-9_16-12-25.png


When a tag is scanned, the system sends an intent. The first step is to call NFC.EnableForegroundDispatch in Activity_Resume. This will force the system to send the intent to our activity instead of sending it to a different app.
You should call NFC.DisableForegroundDispatch in Activity_Pause.

Activity_Resume will be called when an intent is sent to our activity. We need to check two things:
1. This intent is related to a tag discovery.
2. This is a new intent.

B4X:
Sub Activity_Resume
   'forces all nfc intents to be sent to this activity
   nfc.EnableForegroundDispatch
   Dim si As Intent = Activity.GetStartingIntent
   'check that the intent is a new intent
   If si.IsInitialized = False Or si = prevIntent Then Return
   prevIntent = si
   If si.Action.EndsWith("TECH_DISCOVERED") Or si.Action.EndsWith("NDEF_DISCOVERED") Or si.Action.EndsWith("TAG_DISCOVERED") Then
      'work with the intent
     End If
   End If
End Sub
Each NFC tag can support multiple types of technologies.
NFC.GetTechList will return the list of supported technologies.
You can see the full list of technologies here: http://developer.android.com/reference/android/nfc/tech/TagTechnology.html

Assuming that the tag supports a technology that is relevant to our app, we create a TagTechnology object with the technology name and then connect to the tag:
B4X:
If techs.IndexOf("android.nfc.tech.Ndef") > -1 Then
   TagTech.Initialize("TagTech", "android.nfc.tech.Ndef" , si)
   'Connect to the tag
   TagTech.Connect
Else
The technology class sets the actual type of TagTech.

The Connected event will be raised when the connection is established. Make sure to check the success parameter as it can fail if the user moved the device during the connection.

Once connected we can start calling the technology specific APIs. The NFC library doesn't expose these APIs. You should instead use JavaObject or TagTechnology.RunAsync to call these methods.
You can find the APIs here: http://developer.android.com/reference/android/nfc/tech/NfcA.html (for NfcA).

There are two types of methods: blocking (I/O) and non-blocking.
You should use TagTechnology.RunAsync to call any of the blocking methods. The RunAsync event will be raised when the operation completed (the call itself will be executed on a background thread).

Example of reading Ndef records (API: http://developer.android.com/reference/android/nfc/tech/Ndef.html):
B4X:
Private Sub ReadNdef
   TagTech.RunAsync("ReadNdef", "getNdefMessage", Null, 0)
End Sub

Private Sub ReadNdef_RunAsync (Flag As Int, Success As Boolean, Result As Object)
   Log($"Reading completed. Success=${Success}, Flag=${Flag}"$)
   ListView1.Clear
   If Success Then
     If Result = Null Then
       ToastMessageShow("No records found.", False)
     Else
       Dim message As JavaObject = Result
       Dim records() As Object = message.RunMethod("getRecords", Null)
       For Each r As NdefRecord In records
         Dim b() As Byte = r.GetPayload
         ListView1.AddSingleLine(BytesToString(b, 0, b.Length, "utf8"))
       Next
     End If
   End If
End Sub
The attached example shows how to read and write to Ndef tags. This is a popular and simple format.

Versions:

- This example is compatible with Android 4.1+ (API 16). The minimum version if you don't use NFC.CreateMimeRecord is Android 4.0 (API 14).
- NFC v2.0+: https://www.b4x.com/android/forum/threads/updates-to-internal-libraries.59340/#post-408085
- ViewsEx 1.11+: https://www.b4x.com/android/forum/threads/updates-to-internal-libraries.59340/#content
- B4A v5.80+ (you can use older versions by creating a new layout without the custom views, the minimum version is v5.00).
 

Attachments

Last edited:

Duncan williamson

Member
Licensed User
NFC v2.00 adds support for low level access to the NFC features. This allows reading and writing from NFC tags.

The NFC library provides three features:
- Reading Ndef tags based intent filters: Reading NDEF data from NFC tags
- Sending data between two devices (Android Beam): https://www.b4x.com/android/forum/threads/60731/#content
- Low level access to the tag.

This tutorial explains how you can use the low level access to read and write Ndef tags. It is also possible to extend it to other types of tags. However you will need to implement the required protocol yourself.

View attachment 42281

When a tag is scanned, the system sends an intent. The first step is to call NFC.EnableForegroundDispatch in Activity_Resume. This will force the system to send the intent to our activity instead of sending it to a different app.
You should call NFC.DisableForegroundDispatch in Activity_Pause.

Activity_Resume will be called when an intent is sent to our activity. We need to check two things:
1. This intent is related to a tag discovery.
2. This is a new intent.

B4X:
Sub Activity_Resume
   'forces all nfc intents to be sent to this activity
   nfc.EnableForegroundDispatch
   Dim si As Intent = Activity.GetStartingIntent
   'check that the intent is a new intent
   If si.IsInitialized = False Or si = prevIntent Then Return
   prevIntent = si
   If si.Action.EndsWith("TECH_DISCOVERED") Or si.Action.EndsWith("NDEF_DISCOVERED") Or si.Action.EndsWith("TAG_DISCOVERED") Then
      'work with the intent
     End If
   End If
End Sub
Each NFC tag can support multiple types of technologies.
NFC.GetTechList will return the list of supported technologies.
You can see the full list of technologies here: http://developer.android.com/reference/android/nfc/tech/TagTechnology.html

Assuming that the tag supports a technology that is relevant to our app, we create a TagTechnology object with the technology name and then connect to the tag:
B4X:
If techs.IndexOf("android.nfc.tech.Ndef") > -1 Then
   TagTech.Initialize("TagTech", "android.nfc.tech.Ndef" , si)
   'Connect to the tag
   TagTech.Connect
Else
The technology class sets the actual type of TagTech.

The Connected event will be raised when the connection is established. Make sure to check the success parameter as it can fail if the user moved the device during the connection.

Once connected we can start calling the technology specific APIs. The NFC library doesn't expose these APIs. You should instead use JavaObject or TagTechnology.RunAsync to call these methods.
You can find the APIs here: http://developer.android.com/reference/android/nfc/tech/NfcA.html (for NfcA).

There are two types of methods: blocking (I/O) and non-blocking.
You should use TagTechnology.RunAsync to call any of the blocking methods. The RunAsync event will be raised when the operation completed (the call itself will be executed on a background thread).

Example of reading Ndef records (API: http://developer.android.com/reference/android/nfc/tech/Ndef.html):
B4X:
Private Sub ReadNdef
   TagTech.RunAsync("ReadNdef", "getNdefMessage", Null, 0)
End Sub

Private Sub ReadNdef_RunAsync (Flag As Int, Success As Boolean, Result As Object)
   Log($"Reading completed. Success=${Success}, Flag=${Flag}"$)
   ListView1.Clear
   If Success Then
     If Result = Null Then
       ToastMessageShow("No records found.", False)
     Else
       Dim message As JavaObject = Result
       Dim records() As Object = message.RunMethod("getRecords", Null)
       For Each r As NdefRecord In records
         Dim b() As Byte = r.GetPayload
         ListView1.AddSingleLine(BytesToString(b, 0, b.Length, "utf8"))
       Next
     End If
   End If
End Sub
The attached example shows how to read and write to Ndef tags. This is a popular and simple format.

Versions:

- This example is compatible with Android 4.1+ (API 16). The minimum version if you don't use NFC.CreateMimeRecord is Android 4.0 (API 14).
- NFC v2.0+: https://www.b4x.com/android/forum/threads/updates-to-internal-libraries.59340/#post-408085
- ViewsEx 1.11+: https://www.b4x.com/android/forum/threads/updates-to-internal-libraries.59340/#content
- B4A v5.80+ (you can use older versions by creating a new layout without the custom views).
Hi Erel
I realised that the account I logged in from was my origional account which I had befor I renewed my licence.... So hopefully this account shows me as a licenced user.
My question is how do I read the tag UID using this new version of NFC

Regards

Duncan
 

Erel

Administrator
Staff member
Licensed User
You can use this code to get the id:
B4X:
Dim jo As JavaObject = TagTech
Dim tag As JavaObject = jo.RunMethod("getTag", Null)
Dim rawId() As Byte = tag.RunMethod("getId", Null)
Log(bc.HexFromBytes(rawId)) 'bc = ByteConverter
 

Duncan williamson

Member
Licensed User
You can use this code to get the id:
B4X:
Dim jo As JavaObject = TagTech
Dim tag As JavaObject = jo.RunMethod("getTag", Null)
Dim rawId() As Byte = tag.RunMethod("getId", Null)
Log(bc.HexFromBytes(rawId)) 'bc = ByteConverter
Thanks Erel , very much apreciated
 

GaNdAlF89

Active Member
Licensed User
Hi, I tried this example, adjusting code and layout for B4A v2.71. But when I try to read a tag, the row
B4X:
TagTech.Initialize("TagTech","android.nfc.tech.Ndef",si)
generate this
B4X:
** Activity (main) Resume **

main_activity_resume (B4A line: 61)
TagTech.Initialize("TagTech","android.nfc.tech.Ndef" ,si)
java.lang.NoSuchMethodError: No static method getExtraTags(Ljava/lang/Object;)Ljava/util/HashMap; in class Lanywheresoftware/b4a/AbsObjectWrapper; or its super classes (declaration of 'anywheresoftware.b4a.AbsObjectWrapper' appears in /data/app/b4a.example-1/base.apk)
   at anywheresoftware.b4a.objects.NFC$TagTechnologyWrapper.Initialize(NFC.java:273)
   at b4a.example.main._activity_resume(main.java:319)
   at java.lang.reflect.Method.invoke(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:372)
   at anywheresoftware.b4a.BA.raiseEvent2(BA.java:169)
   at anywheresoftware.b4a.BA.raiseEvent(BA.java:153)
   at b4a.example.main$ResumeMessage.run(main.java:221)
   at android.os.Handler.handleCallback(Handler.java:739)
   at android.os.Handler.dispatchMessage(Handler.java:95)
   at android.os.Looper.loop(Looper.java:155)
   at android.app.ActivityThread.main(ActivityThread.java:5696)
   at java.lang.reflect.Method.invoke(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:372)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
What is the problem?
 

GaNdAlF89

Active Member
Licensed User
because the lib is using

And i GUESS the AbsObjectWrapper has changed since B4A 2 to B4A 5.8
Thanks for reply. In the first post, I read
B4X:
"- B4A v5.80+ (you can use older versions by creating a new layout without the custom views)."
but I created a new layout....what version I have to use?
 

Duncan williamson

Member
Licensed User
I have come across a strange issue that i cant explain or get around... if i use the demo program supplied above i can write to the tag and read it with no issues.. if i use other tag reading apps i find that the first letter of record 0 is not read. eg if i write with the example "hello world!" then when i read it with other tag reading apps i get "ello world!"
if I write to the tag with other apps and read with the example i find it appends "en" to the start of the record so a tag writen with "hello" will read as "enhello".
any and all work arounds would be apreciated:)
 

GaNdAlF89

Active Member
Licensed User
This library requires B4A v5.0+. I've added this requirement to the first post.
Thanks.
Sorry but with the "you can use older versions by creating a new layout without the custom views" I understood that version also older than 5.0 would work...
I will send you a mail for new license.
 

Erel

Administrator
Staff member
Licensed User
I have come across a strange issue that i cant explain or get around... if i use the demo program supplied above i can write to the tag and read it with no issues.. if i use other tag reading apps i find that the first letter of record 0 is not read. eg if i write with the example "hello world!" then when i read it with other tag reading apps i get "ello world!"
if I write to the tag with other apps and read with the example i find it appends "en" to the start of the record so a tag writen with "hello" will read as "enhello".
any and all work arounds would be apreciated:)
There are all kinds of protocols for NDEF payloads: http://nfcpy.readthedocs.org/en/latest/topics/ndef.html
You can add the language code with:
B4X:
Dim s As String = Chr(2) & "en" & originalMessage
'now write s instead of the original messsage
When you read the message, use GetAsTextType instead of GetPayload.
 

Cableguy

Expert
Licensed User
Am I correct in assuming that with this lib we can emulate a NFC device? Like use the phone as a NFC tag, not a reader.
 
Status
Not open for further replies.
Top