iBeacon è una tecnologia Apple basata su Bluetooth 4.0 LE (Bluetooth Low Energy, ovvero con un basso consumo di energia), integrata in dispositivi di piccole dimensioni che contengono appunto una radio Bluetooth 4.
Grazie a questa tecnologia un dispositivo iOS può rilevare la sua presenza in una determinata regione, o capire la distanza a cui ci si trova dal "beacon" stesso.
In questo articolo vedremo come inviare una notifica ad uno smartphone che entra in una certa area tramite l'uso di iBeacon.
iBeacon = prossimità
Gli iBeacon sono largamente utilizzati all'interno di negozi, e permettono di inviare a un backend contenuti geolocalizzati (tramite i cosiddetti advertisement iBeacon) all'interno del punto vendita, per effettuare operazioni come check-in o pagamenti in prossimità. Anche un device iOS può essere utilizzato per generare advertisement iBeacon.
Esistono vari modelli di iBeacon, e ognuno fornisce il proprio SDK nativo per lo sviluppo.
Com'è fatto un advertisement iBeacon?
Ecco lo schema di ciò che un dispositivo iBeacon trasmette:
Campo | Dimensione (bytes) | Descrizione |
---|---|---|
UUID | 16 |
Lo sviluppatore può impostare questo campo per avere un UUID specifico da utilizzare nell'app |
Major | 2 |
Serve per identificare uno specifico set di iBeacon. Per esempio può definire una sottoregione in una regione definita tramite lo stesso UUID |
Minor | 2 |
Identifica un'ulteriore suddivisione della regione |
A partire da iOS 7, Apple ha esteso la libreria Core Location in modo da poter sfruttare questa tecnologia in maniera nativa, perciò nella maggior parte dei casi non è necessario utilizzare un SDK di terze parti.
Dal momento che questa tecnologia si basa sul Bluetooth Low Energy, essa richiede come hardware minimo un iPhone 4S, iPod Touch (5a generazione), iPad (3a Generazione) o iPad mini.
È possibile creare un'app che sfrutta la tecnologia iBeacon per monitorare una determinata area (o region): l'app riceverà una notifica dall'iBeacon quando quest'ultimo ed il dispositivo che esegue l'app si trovano in quell'area. Per esempio, se abbiamo installato diversi iBeacon all'interno di una galleria d'arte, possiamo essere avvisati quando entriamo in una determinata stanza.
Con iBeacon possiamo anche visualizzare la posizione dell'utente all'interno di uno spazio circoscritto, tramite la cosiddetta Proximity. In particolare, utilizzando la funzione di Ranging, possiamo ottenere la distanza di un dispositivo dal beacon. Il beacon in questo caso invierà una notifica contenente la proximity, il valore minor e il valore major.
Nel seguito vedremo come implementare quanto appena accennato.
Vediamo ora i passi necessari per creare un applicazione iOS che interagisce con gli iBeacon.
1. Creare il progetto su XCode
Creiamo un nuovo progetto XCode selezionando il template “Single View Application”.
2. Configurare le opzioni del nuovo progetto
Andiamo poi ad inserire il nome del progetto e il nome della nostra organizzazione.
3. Configurare i permessi di esecuzione in Background
Per poter eseguire il processo di Ranging e monitoraggio in background, e ricevere le notifiche, la nostra app deve essere registrata per usare il
Bluetooth LE, e deve avere i permessi di Location updates. Per fare questo, selezioniamo il progetto principale nel File Browser.
Selezioniamo poi la scheda Capabilities e cerchiamo la sezione Background Modes. Impostiamo lo switch su ON e poi abilitiamo i
flag Location updates e Uses Bluetooth LE.
4. Definire la regione da monitorare
Ora andremo ad agire sulla classe AppDelegate.
Come prima cosa dobbiamo importare le CoreLibreries, aggiungendo nell’interfaccia (AppDelegate.h) la riga seguente:
@import CoreLibraries;
Quindi, nel file AppDelegate.m, ridefiniamo il metodo seguente:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
In questo metodo, andiamo a definire l’UUID del nostro (o dei nostri) iBeacon. Va inoltre specificato un identificatore per la Region.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSUUID *beaconUUID = [[NSUUID alloc] initWithUUIDString:
@"B9407F30-F5F8-466E-AFF9-25556B57FE6D"];
NSString *beaconIdentifier = @"html.it";
CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:
beaconUUID identifier:beaconIdentifier];
return YES;
}
5. Abilitare la richiesta dei permessi all’utente
iOS8 richiede un permesso speciale per abilitare il monitoraggio della location.
Nel File Browser, sotto la voce Supporting Files, apriamo Info.plist. Selezioniamo quindi la prima riga Information Property List e clicchiamo sul piccolo pulsante con il segno + per aggiungere una nuova riga. Diamogli il nome (colonna di
sinistra) NSLocationAlwaysUsageDescription. Assicuriamoci che il tipo sia String e, nella colonna di destra, impostiamo come valore un a
frase che verrà presentata all’utente come descrizione della richiesta di permesso.
6. Configurare il CCLocationManager per il processo di monitor e ranging
Ora che abbiamo definito la regione, andiamo a creare un’istanza di CLLocationManager e specifichiamo l’intenzione di monitorarla.
Dovremo anche definire un Delegate per il location manager.
Definiamo quindi una nuova proprietà per l’AppDelegate che conterrà il nostro locationManager, e sempre nel file AppDelegate.h implementiamo il delegate CLLocationManagerDelegate.
#import
@import CoreLocation;
@interface AppDelegate : UIResponder
@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) CLLocationManager *locationManager;
@end
A questo punto, nell’implementazione dell’AppDelegate, andiamo a creare l’istanza del CLLocationManager e facciamo partire il
monitoraggio della Region. Andiamo così ad includere i metodi del delegate.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSUUID *beaconUUID = [[NSUUID alloc] initWithUUIDString:
@"B9407F30-F5F8-466E-AFF9-25556B57FE6D"];
NSString *regionIdentifier = @"html.it";
CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc]
initWithProximityUUID:beaconUUID identifier:regionIdentifier];
self.locationManager = [[CLLocationManager alloc] init];
//In iOS 8 va richiesto all'utente il permesso di utilizzare la location
if([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
[self.locationManager requestAlwaysAuthorization];
}
self.locationManager.delegate = self;
self.locationManager.pausesLocationUpdatesAutomatically = NO;
[self.locationManager startMonitoringForRegion:beaconRegion];
[self.locationManager startRangingBeaconsInRegion:beaconRegion];
[self.locationManager startUpdatingLocation];
return YES;
}
7. Aggiungere l’azione da compiere quando si entra in una Regione
La nostra app ora monitora il beacon, ma non fa ancora nulla di concreto. Andiamo a definire un nuovo metodo, sendLocalNotificationWithMessage: (NSString *) message
, che genererà la notifica e verrà eseguito quando si entra nella regione del Beacon. Il file in cui opereremo è ancora AppDelegate.m.
-(void)sendLocalNotificationWithMessage:(NSString*)message {
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = message;
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
}
-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:
(NSArray *)beacons inRegion:(CLBeaconRegion *)region {
NSString *message = @"";
if(beacons.count > 0) {
CLBeacon *nearestBeacon = beacons.firstObject;
switch(nearestBeacon.proximity) {
case CLProximityFar:
message = @"Ti trovi molto lontano dal beacon";
break;
case CLProximityNear:
message = @"Ti trovi vicino al beacon";
break;
case CLProximityImmediate:
message = @"Sei nell'immediata prossibita' beacon";
break;
case CLProximityUnknown:
return;
}
} else {
message = @"Nessun beacon nelle vicinanze";
}
NSLog(@"%@", message);
[self sendLocalNotificationWithMessage:message];
}
8. Visualizzare i Beacon nelle vicinanze
Per dare un minimo di esperienza utente al seguito di una notifica, bisogna estendere ancora un po' la nostra app.
Aggiungiamo quindi una tabella che verrà popolata con le informazioni di tutti i beacon nel range.
Apriamo il file Main.storyboard. Selezioniamo la view principale, e dalla libreria oggetti prendiamo una Table View e trasciniamola all'interno della vista principale, facendola adattare alla view.
Ora apriamo il nostro ViewController.h e andiamo a dichiarare la proprietà che referenzia la tabella.
@interface ViewController : UIViewController
@property IBOutlet UITableView *tableView;
@end
Riapriamo quindi lo storyboard. Cliccando con il tasto destro sulla tabella (o con la combinazione di tasti option+click), trasciniamo, dal menu contestuale che compare, il cerchio accanto alla voce dataSource fino al nostro View Controller, nella fascia di destra della vista storyboard.
Facciamo la stessa cosa con la voce delegate e Referencing Outlets, andando a selezionare la proprietà tableView.
Ora dobbiamo fare in modo che il View Controller implementi i protocolli richiesti dalla connessione appena fatta: UITableViewDataSource e UITableViewDelegate.
Aggiungiamole nel file ViewController.h e già che ci siamo aggiungiamo anche una property per l'array dei beacon trovati, da passare alla tabella.
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
@property IBOutlet UITableView *tableView;
@property (strong) NSArray *beacons;
@end
Ora facciamo in modo che quando i Beacon vengono rilevati nell'App Delegate, essi vengano utilizzati dal nostro View Controller ed aggiunti alla tabella.
Andiamo ad aggiungere al metodo locationManager:didRangeBeacons:inRegion nel file AppDelegate.m il riferimento al ViewController e alla sua proprietà beacons.
-(void) locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region
{
ViewController *viewController = (ViewController *)self.window.rootViewController;
viewController.beacons = beacons;
[viewController.tableView reloadData];
...
Ricordiamoci di importare il nostro ViewController qualora Xcode lo richieda.
Ora torniamo nel nostro View Controller ed implementiamo i metodi che servono alla Table View per visualizzare gli elementi:
- (NSInteger) tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
return self.beacons.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyIdentifier"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"MyIdentifier"];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
CLBeacon *beacon = (CLBeacon *)[self.beacons objectAtIndex:indexPath.row];
NSString *proximityLabel = @"";
switch (beacon.proximity) {
case CLProximityFar:
proximityLabel = @"Lontano";
break;
case CLProximityNear:
proximityLabel = @"Vicino";
break;
case CLProximityImmediate:
proximityLabel = @"Immediato";
break;
case CLProximityUnknown:
proximityLabel = @"Sconosciuto";
break;
}
cell.textLabel.text = proximityLabel;
NSString *detailLabel = [NSString stringWithFormat: @"Major: %d, Minor: %d, RSSI: %d, UUID: %@", beacon.major.intValue, beacon.minor.intValue, (int)beacon.rssi, beacon.proximityUUID.UUIDString];
cell.detailTextLabel.text = detailLabel;
return cell;
}
9. Assicurarsi che le notifiche vengano mostrate
Se l'applicazione non dovesse chiedere l'autorizzazione per inviare le notifiche dei beacon, è sufficiente aggiungere queste linee di codice alla fine del metodo application:application didFinishLaunchingWithOptions: della classe AppDelegate.m.
if ([UIApplication instancesRespondToSelector:@selector(registerUserNotificationSettings:)]) {
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeSound categories:nil]];
}
Fatto ciò, basterà eseguire nuovamente l'app per riuscire a visualizzare le notifiche.
10. Risultato finale
Le immagini seguenti mostrano il risultato finale.