2. SDK + Permisos + Feature
<uses-permission android:name="android.permission.NFC" />
<uses-sdk android:minSdkVersion="10"/>
a l'sdk 9 l'interacció amb nfc era molt limitada
<uses-feature android:name="android.hardware.nfc" android:required="true" />
només si l'nfc és implescindible per a la nostra app
Google Play filtra apps basant-se en aquest valor
@rocboronat
3. Hola NDEF!
●
NDEF és un standard definit per NFC Forum
● Android suporta més tecnologies a part d'NDEF
● Però no ho fa molt bé
●
Si ens basem en NDEF, estalviarem molt de temps
@rocboronat
4. Hola NDEF!
●
Cada NdefMessage pot tenir molts NdefRecord
●
Android reacciona al primer NdefRecord
●
El primer NdefRecord hauria de contenir:
● 3-bit TNF (Type Name Format)
●
TNF_ABSOLUTE_URI, TNF_MIME_MEDIA, TNF_WELL_KNOWN...
● Tipus
● RTD_URI, RTD_TEXT, RTD_SMART_POSTER...
● ID
●
Un identificador únic per aquest NdefRecord
● Payload
● Les dades en sí. Com un NdefMessage pot tenir molts NdefRecords,
no podem assumir que el Payload té el total de les dades
●
Android ens proporciona un mecanisme per a escriure NdefRecords i NdefMessages
@rocboronat
5. Dispatching
●
Quan s'ha llegit l'NFC, el sistema llença un Intent d'un dels tres tipus:
●
ACTION_NDEF_DISCOVERED
●
Són tags amb missatges NDEF comprensibles. Són bons.
●
ACTION_TECH_DISCOVERED
●
Són tags que es basen en el tipus de tag. Evita'ls
●
ACTION_TAG_DISCOVERED
●
Són tags que Android ni reconeix. Compatibilitat futura?
@rocboronat
7. Dispatching
●
Si un Intent el pot capturar més d'una aplicació...
●
El sistema li preguntarà a l'usuari quina aplicació vol obrir...
●
I com haurà de fer click a la pantalla, apartarà el mobil del tag!
●
Estaria bé evitar-ho. Jo utilitzo una URI personalitzada:
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:host="crema.cat" android:scheme="roc" />
</intent-filter>
@rocboronat
8. Dispatching
Com llegim el tag des de la nostra app?
tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
ndefTag = Ndef.get(tag);
Aquesta serà la única referència que tindrem al nostre tag. Si aquest Intent es
perd, mai més podrem accedir al tag, de manera que més val que ens ho
guardem en una variable.
@rocboronat
9. Hello AAR!
●
AAR són les sigles d'Android Application Records
●
Van aparèixer amb Android 4.0 – API14
●
AAR assegura que l'app que s'iniciarà a l'escanejar el tag és la teva
●
Si l'usuari no té la teva app instal·lada: Google Play
● El preu a pagar és que no s'utilitzen Intent Filters.
● De manera que no pots rebre informació continguda en el tag...
●
Les estacions de Bicing podrien tenir un tag NFC amb AAR.
@rocboronat
10. Howto AAR by Google
NdefMessage msg = new NdefMessage(
new NdefRecord[] {
...,
NdefRecord.createApplicationRecord("com.example.android.beam")}
@rocboronat
11. Howto AAR by me
public static NdefMessage createAAR() {
try {
NdefRecord aar = null;
try{
Class c = Class.forName("android.nfc.NdefRecord");
c.getMethods();
Method m = c.getMethod ("createApplicationRecord", String.class);
aar = (NdefRecord) m.invoke(aar, "net.rocboronat.android.nfc.car");
} catch (Exception e) {
return null;
}
NdefMessage msg = new NdefMessage(new NdefRecord[] {
new NdefRecord(
aar.getTnf(),
aar.getType(),
RandomUtil.randomNumeric().getBytes(Charset.forName("US-ASCII")),
aar.getPayload())
});
return msg;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
@rocboronat
12. Howto AAR by me
private static boolean writeNdefAar(){
boolean result = false;
Ndef ndefTag = null;
try {
NdefMessage aar = AndroidApplicationRecordsUtil.createAAR();
ndefTag = Ndef.get(NfcActivity.tag);
Log.i("NfcNdefAar","Message: "+(aar.toByteArray().length));
Log.i("NfcNdefAar","NFC max: "+ndefTag.getMaxSize());
if (aar.toByteArray().length>ndefTag.getMaxSize()){
Log.i("NfcNdefAar", "message is too big for this NFC");
}
if (!ndefTag.isConnected()){
ndefTag.connect();
}
ndefTag.writeNdefMessage(aar);
result = true;
} catch (IOException e) {
Log.e("TagWriter", "IOException while writing...", e);
} catch (FormatException e) {
Log.e("TagWriter", "FormatException while writing...", e);
} catch (NullPointerException e) {
Log.e("TagWriter", "NullPointerException while writing...", e);
} finally {
try {
if (ndefTag!=null){
ndefTag.close();
}
} catch (Exception e) {
Log.e("TagWriter", "Exception while closing...", e);
}
}
return result;
}
@rocboronat
13. Creating NdefMessage
private static final String CUSTOM_URI = "roc://crema.cat/";
public static NdefMessage createCustom() {
NdefRecord uri = NdefRecord.createUri(CUSTOM_URI.concat(RandomUtil.randomNumeric()));
NdefMessage msg = new NdefMessage(new NdefRecord[] { new NdefRecord(
uri.getTnf(), uri.getType(), RandomUtil.randomNumeric()
.getBytes(Charset.forName("US-ASCII")),
uri.getPayload()) });
return msg;
}
@rocboronat
14. Foreground Dispatch System
●
Quan es troba un NFC, Android el tracta. Aquest fet limita.
●
Si activem el FDS, ens fem responsables de tractar els NFC des de la nostra app.
●
NFCar utilitza aquest sistema per a formatar tags.
@rocboronat
15. Foreground Dispatch System
private static String[][] techListsArray = null;
private static IntentFilter[] intentFiltersArray = null;
private static IntentFilter intentFilter = null;
private static PendingIntent pendingIntent = null;
private static void init(Activity a){
pendingIntent = PendingIntent.getActivity(a, 0,
new Intent(a, a.getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
intentFilter = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
try {
intentFilter.addDataType("*/*"); // Handles all MIME based dispatches.
} catch (MalformedMimeTypeException e) {
throw new RuntimeException("fail", e);
}
intentFiltersArray = new IntentFilter[] { intentFilter, };
techListsArray = new String[][] {
new String[] { NfcA.class.getName(), NfcB.class.getName() },
new String[] { NfcV.class.getName() },
new String[] { NfcF.class.getName() },
new String[] { MifareClassic.class.getName() },
new String[] { MifareUltralight.class.getName() },
new String[] { Ndef.class.getName() },
new String[] { NdefFormatable.class.getName() },
new String[] { IsoDep.class.getName() } };
}
@rocboronat
16. Foreground Dispatch System
public static void enable(Activity a){
if (NfcUtil.nfcAvailable(a)){
try{
init(a);
NfcUtil.enableForeground(a, pendingIntent, intentFiltersArray, techListsArray);
}catch (IllegalStateException e) {
// TODO: handle exception
}
}
}
public static void disable(Activity a){
if (NfcUtil.nfcAvailable(a)){
NfcUtil.disableForeground(a);
}
}
@rocboronat
18. Arquitectura proposada
●
L'Activity que reb l'Intent del tag NFC no ha de tenir vista
●
L'Activity que reb l'Intent del tag NFC fa coses amb el tag NFC
●
L'Activity que reb l'Intent del tag NFC pot llençar Intents
<activity
android:name=".NfcActivity"
android:theme="@android:style/Theme.NoDisplay" >
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:host="crema.cat" android:scheme="roc" />
</intent-filter>
</activity>
@rocboronat
19. All your base
http://developer.android.com/guide/topics/connectivity/nfc/index.html
article oficial de Google
http://rocboronat.net/index.php/en/blog/72-coses-que-he-apres-sobre-lnfc-a-android
experiències i batalletes d'en Roc
http://fewlaps.com
empresa catalana de desenvolupament mobil
fem ponències sobre NFC!
@rocboronat