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