iBeacon

Entendendo melhor a tecnologia, sua utilização e seu potencial

Postado por Gabriel Oliva em 18/03/2016

Gabriel Oliva é um entusiasta mobile e desenvolvedor iOS. Acredita que o engajamento da comunidade faz total diferença para o crescimento pessoal e profissional e por isso participa de projetos como o equinociOS.

Introdução

Muito se fala em internet das coisas hoje em dia, que nada mais é um conceito utilizado para referenciar a conexão de objetos de uso cotidiano à internet. Eletrodoméstidos, móveis e até vestuário estão se conectando na internet para fazer requisições ou apenas enviar informações. Magia negra? Que nada! Qualquer microchip pode dar poderes computacionais para itens que utilizamos no nosso dia a dia :P

E o que pode dar poderes computacionais para contextualizar uma localização? Que tipo de magia negra irei utilizar para fazer com que algum computador saiba que eu estou no setor masculino de uma loja de departamentos? O beacon está aí para resolver seu problema!

Bacon? Adoro!

Calma! Bacon pode resolver seus problemas? Muito provavelmente! Mas até cientistas e engenheiros conseguirem implementar um micro processador nessa maravilha, a computação contextual vai precisar da ajuda do seu primo distante, o Beacon.

Traduzido do inglês, beacon significa farol. “Uai, o que tem farol a ver com o beacon???”, questionaria o mineiro interno em você!

Pois bem, os faróis foram concebidos para avisar aos navegadores que eles estavam se aproximando da terra. Ou seja, era uma informação que estava sendo enviada em broadcast.

O beacon funciona da mesma forma mas, ao invés de enviar luz, ele transmite algumas informações por Bluetooth Low Energy. Ele é produzido por diversas empresas e por utilizar a versão 4.0 do Bluetooth, tem uma autonomia muito grande. Empresas como estimote e kontakt.io são alguma das referências que temos em produção de beacons de qualidade, porém você consegue encontrar ótimos produtos na amazon e também alguns genéricos em mercados chineses (e caso essa seja sua opção, comece a rezar para não ser tributado).

Utilização no mundo real

A utilização de beacons no mundo real vem se tornando cada vez maior e grandes empresas vem fazendo testes para ver o resultado na prática. Porém a maior parte dessa utilização é feita por lojas buscando entregar publicidade geolocalizada.

Funciona da seguinte forma: o usuário, com o smartphone no bolso, entra na loja e passa por algum departamento específico, como a sessão masculina. Dentro dessa sessão há um beacon fazendo broadcast de informações. O smartphone do usuário irá receber essas informações e internamente fazer uma requisição que irá enviar como parâmetro a informação recebida pelo beacon. O retorno dessa requisição pode ser diverso, como notificação de promoções, informação sobre produto, vouchers, etc.

Apesar de ser utilizado principalmente em ações de marketing geolocalizado, o beacon pode resolver diversos outros problemas. Até pouco tempo atrás existia uma lista atualizada de casos reais de empresas que utilizavam a tecnologia junto com seu ramo de atuação: Cinema, aeroportos, museu, farmácia e até colégios eram algumas dessas áreas.

Onde o “i” entrou no beacon?

No final de 2013 a Apple lança para o público o iBeacon, que nada mais é que a sua versão proprietária do beacon implementada do jeito dela. Apesar dos pesares, funciona tanto no iOS quanto no Android.

O Google também tem sua implementação do beacon, chamada Eddystone, e até possui algumas diferenças com relação ao iBeacon. Porém isso é o lado verde da força que não iremos entrar em detalhe.

Características do iBeacon

O iBeacon faz o broadcast de três informações: major, minor e UUID. Sendo:

Parâmetro Valor
UUID 16 bytes
Major 2 bytes
Minor 2 bytes

O UUID pode ser único por aplicação. Já o major e minor devem ser subdivisões de uma determinada região. Se fizermos a divisão de uma loja, poderemos ter por exemplo a seguinte tabela:

Ou seja, as filiais da loja são divididas pelo major e o departamento é dividido pelo minor. Não existe uma regra de subdivisão, mas lembre-se de fazer algo bem organizado!

Talk is cheap. Show me the code!

Existem diversos tipos de iBeacons de diversas empresas e, consequentemente, diversos SDKs que encapsulam a implementação nativa para oferecer featurings melhoradas ou o mais do mesmo.

Para esse exemplo não utilizaremos nenhum SDK de terceiro e nenhum iBeacon. Vamos dividir a implementação em duas partes: primeiro criaremos um app que ira atuar como um iBeacon, porque eu sei que você talvez não tenha um em casa. Viu como sou bonzinho? Depois iremos criar de fato o nosso app que irá lidar com as informações do nosso AppBeacon.

O framework que nos oferece ferramentas para trabalhar com iBeacon é o Core Location, então se você já possui algum conhecimento básico sobre ela, vai tirar isso de letra!

Um pequeno adendo: irei escrever esse artigo partindo do princípio que você já tenha um pouco de experiência com desenvolvimento iOS.

AppBeacon

O AppBeacon será um aplicativo básico que terá apenas uma funcionalidade: simular um iBeacon. Ele vai possuir 3 UIButtons que servirá como um switch de Minor. A intenção é simular o iBeacon da loja de San Francisco que está na tabela acima. Mas caso sua memória seja curta, aqui vai um refresco:

Departamento Major Minor
Clothing 1 10
Housewares 1 20
Automotive 1 30

Vamos criar um projeto Single View Application, em Objective-c para iPhone. O aplicativo terá uma interface bem simplória, porém que irá nos atender perfeitamente. Além dos 3 UIButtons, iremos acidionar algumas labels para representar o major e minor.

Cada botão possui uma tag diferente para identificarmos qual foi pressionado, então não se esqueça de taggear.

Botão Tag
Clothing 1
Housewares 2
Automotive 3

Para setar a tag basta selecionar o botão, ir em Attributes Inspector e voilà:

Após criar a interface, um ultimo ajuste antes de partir pro código: importe o CoreLocation.framework e o CoreBluetooth.framework para o seu projeto.

Pronto, agora já podemos importar os framewoks no ViewController.m:

#import <CoreLocation/CoreLocation.h>
#import <CoreBluetooth/CoreBluetooth.h>

A classe terá a seguinte interface:

@interface ViewController ()
{
    NSUUID *uuid;
}

enum ibeacon {
    majorSanFrancisco = 1,
    minorClothing = 10,
    minorHouseware = 20,
    minorAutomotive = 30
};

@property CLBeaconRegion *beaconRegion;
@property CBPeripheralManager *peripheralManager;

@property (strong, nonatomic) IBOutlet UILabel *majorLabel;
@property (strong, nonatomic) IBOutlet UILabel *minorLabel;

@end

Vamos entender o que a interface da nossa classe contém:

  • O uuid é um objeto de classe para armazenarmos o uuid;
  • O enum é apenas para padronizar nossas informações;
  • O beaconRegion é o objeto responsável por monitorar a região, que é composta por uuid, major, minor e identifier. Como esse app não irá monitorar nada, mas sim enviar dados, ele irá servir como base de informação para o nosos próximo componente;
  • O peripheralManager é o responsável por gerenciar o nosso bluetooth e é através dele que iremos fazer a propagação;
  • E, por fim, as labels são apenas IBOutlet para informar na nossa interface qual major e minor está sendo propagado.

O viewDidLoad do AppBeacon servirá apenas para iniciar nossas variáveis uuid e identifier e também setar o texto da majorLabel, que nunca será alterado pois estamos fazendo o exemplo com a cidade de San Francisco somente.

O UUID pode ser gerado através de um simples uuidgen no terminal, e foi o que eu fiz!

- (void)viewDidLoad {
    [super viewDidLoad];
    
    uuid = [[NSUUID alloc]initWithUUIDString:@"EBCBB7AD-0D9D-4C9F-82AF-096040BC5B3C"];
    identifier = @"com.equinocios";
    
    self.majorLabel.text = [NSString stringWithFormat:@"%d", majorSanFrancisco];
}

Por fim, temos o método que é invocado toda vez que algum botão for selecionado. O método - (IBAction)departmentDidTapped:(UIButton *)sender deve ser linkado com todos os três botões, então não se esqueça de fazer isso!

Vamos ao código:

- (IBAction)departmentDidTapped:(UIButton *)sender {
    int minor;
    
    switch (sender.tag) {
        // Clothing
        case 1:
            minor = minorClothing;
            self.minorLabel.text = [NSString stringWithFormat:@"%d", minor];
            break;
            
        // Houseware
        case 2:
            minor = minorHouseware;
            self.minorLabel.text = [NSString stringWithFormat:@"%d", minor];
            break;
            
        // Automotive
        case 3:
            minor = minorAutomotive;
            self.minorLabel.text = [NSString stringWithFormat:@"%d", minor];
            break;
            
        default:
            break;
    }
    
    self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid major:majorSanFrancisco minor:minor identifier:identifier];
    
    self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:nil queue:nil options:nil];
    [self.peripheralManager startAdvertising:[self.beaconRegion peripheralDataWithMeasuredPower:nil]];
}

O método já começa fazendo um switch de qual botão foi pressionado através da tag que foi inserida anteriormente. Dentro do switch é gravado qual o valor do minor e também é alterado na label qual é o atual minor selecionado.

Agora que já temos todos os parâmetros necessários para instanciar nossa região, o beaconRegion é inicializado e, logo em seguida, o peripheralManager começa a propagar os dados!

Simples, não?! Mas lembre-se! Como não há nenhum tipo de tratamento para checar se o bluetooth está ligado, certifique-se de fazer isso :P

App LojaXPTO

A segunda parte desse artigo é construir o app da Loja XPTO, que coincidentemente possui departamentos de vestuário, utensílios de casa e área automotiva! Em algum momento que o nosso app chegar perto de algum desses departamentos, uma promoção referente ao local será enviada!

O modelo do app da Loja XPTO é o mesmo do anterior, então mãos à obra! O projeto será um Single View Application, em Objective-C, para iPhone. Não utilizaremos nenhuma interface nesse projeto pois iremos utilizar UIAlertController para exemplificar.

Importe o CoreLocation.framework para o projeto e o adicione no ViewController.m. A interface da classe vai ficar assim:

#import <CoreLocation/CoreLocation.h>

@interface ViewController () <CLLocationManagerDelegate>
{
    CLBeacon *lastBeacon;
}

enum ibeacon {
    majorSanFrancisco = 1,
    minorClothing = 10,
    minorHouseware = 20,
    minorAutomotive = 30
};

@property (strong, nonatomic) CLBeaconRegion *beaconRegion;
@property (strong, nonatomic) CLLocationManager *locationManager;

@end

Dessa vez temos alguns itens diferentes! Vamos por partes:

  • A variável de classe lastBeacon irá servir como um placeholder do último beacon encontrado, para não haver loops de notificação;
  • Nossa classe agora tem que se conformar com o protocolo CLLocationManagerDelegate. Esse protocolo define os métodos responsáveis por lidar com atualização de localização, dentre outras coisas;
  • O CLLocationManager é o objeto que lida com o gerenciamento da localização. Usaremos ele para monitorar a região.

O viewDidLoad da classe nada mais faz que inicializar o monitoramento pela região especificada. A implementação fica assim:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.locationManager = [[CLLocationManager alloc] init];
    self.locationManager.delegate = self;
    
    NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:@"EBCBB7AD-0D9D-4C9F-82AF-096040BC5B3C"];
    NSString *identifier = [NSString stringWithFormat:@"com.equinocios"];
    
    self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid
                                                           identifier:identifier];
    
    [self.locationManager startMonitoringForRegion:self.beaconRegion];
}

Primeiro o locationManager é instanciado e dizemos à ele que o delegate é a própria classe.

Criamos o uuid com o mesmo id que utilizamos no nosso AppBeacon, pois é ele que iremos monitorar. O mesmo acontece com o identifier.

O beaconRegion é inicializado apenas com o uuid, major e identificador, porque não podemos restringir a busca pelo minor, que são os diferentes tipos de departamento.

Por fim, é solicitado ao locationManager começar a monitorar pela região. Assim que entrarmos na range do nosso AppBeacon, uma funcionalidade será executada. Que funcionalidade é essa? Vamos implementá-la agora!

Os métodos abaixo são do CLLocationManagerDelegate. Eles são acionados quando o aparelho entrar ou deixar a região. Quando entrarmos na região, devemos dizer ao locationManager para começar a procurar por beacons. E ao sair, pedimos para ele parar de procurar.

- (void)locationManager:(CLLocationManager*)manager didEnterRegion:(CLRegion*)region {
    [self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
}

-(void)locationManager:(CLLocationManager*)manager didExitRegion:(CLRegion*)region {
    [self.locationManager stopRangingBeaconsInRegion:self.beaconRegion];
}

Já o método -locationManager: didRangeBeacons é chamado sempre que algum beacon for encontrado. A implementação dele segue assim:

-(void)locationManager:(CLLocationManager*)manager didRangeBeacons:(NSArray*)beacons inRegion:(CLBeaconRegion*)region {
    
    if ([beacons firstObject] != lastBeacon) {
        lastBeacon = [beacons firstObject];
        [self showPromoForBeacon:[beacons firstObject]];
    }
    
}

Primeiramente há uma checagem para identificar se o beacon encontrado não é igual ao último encontrado. Isso é feito para evitar notificações duplicadas. Caso positivo, o beacon atual se torna o lastBeacon e o método para mostrar uma promoção é chamado, passando o beacon encontrado.

Vamos implementar esse método?

-(void) showPromoForBeacon:(CLBeacon *)beacon {
    
    NSString *message;
    NSString *title;
    UIAlertController *alert;
    UIAlertAction *ok;
    
    switch ([beacon.minor intValue]) {
        case minorClothing:
            title = [NSString stringWithFormat:@"Promoção de blusas!"];
            message = [NSString stringWithFormat:@"Na compra acima de R$ 100,00, ganhe R$10 de desconto!"];
            break;
            
        case minorHouseware:
            title = [NSString stringWithFormat:@"Voucher de Desconto!"];
            message = [NSString stringWithFormat:@"Kit de cozinha com 20%% de desconto com o código EQUINOCIOS"];
            break;
            
        case minorAutomotive:
            title = [NSString stringWithFormat:@"Promoção de Pneus"];
            message = [NSString stringWithFormat:@"Especialmente pra você que acabou de entrar no departamento!"];
            break;
            
        default:
            break;
    }
    
    alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
    ok = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil];
    
    [alert addAction:ok];
    
    [self presentViewController:alert animated:YES completion:nil];
    
}

Esse método também é bem simples. De acordo com o minor que eu encontrar no beacon, um switch é feito para trazer mensagens customizadas de acordo com o departamento que a pessoa se encontra. Por fim, um alerta é montado e apresentado para o usuário! :)

Em um aparelho abra o AppBeacon e em outro abra a LojaXPTO, faça o teste e verá os diferentes tipos de alerta dependendo do minor que é alterado.

O que fazer de agora em diante?

Esse artigo mostrou os conceitos básicos de utilização e implementação do iBeacon. Existem diversas formas de implementar, com diversos SDKs e uma quantidade absurda de beacons diferentes. Agora é com você!

Fontes de informação