Em 2013, a Apple Inc. introduziu uma tecnologia chamada iBeacon que é executado sobre o protocolo Bluetooth 4.0, também conhecido como Bluetooth Low Energy ou BLE. Embora os dispositivos habilitados para Bluetooth possam se identificar, o processo geralmente é de 1 para 1 com o emparelhamento de um host com um dispositivo, como o emparelhamento de um smartphone com um fone de ouvido Bluetooth. O iBeacon é simplesmente um serviço de transmissão que envia algumas informações pré-configuradas e pode ser executado em paralelo com outros serviços Bluetooth. Para discussão, os quatro parâmetros de interesse ao criar aplicativos de beacon a partir de soluções como Estimote ou de Gimbal são a cadeia de caracteres UUID, um número maior de 16 bits, um número menor de 16 bits e um valor de intensidade de sinal.
No iOS7, a Apple Inc. fornece funcionalidades de biblioteca para trabalhar com iBeacons e, embora existam 3rd bibliotecas de terceiros para outras plataformas, o blog aqui se concentrará no iOS. Combinando as tecnologias do Couchbase Mobile, Ed Arenberg e a equipe do Equipe EPage está desenvolvendo um serviço que faz uso intenso do iBeacon e utiliza o Couchbase Lite para armazenamento local enquanto sincroniza dados entre vários dispositivos usando o Couchbase Sync Gateway.
Vamos agora explorar os três principais componentes desse serviço iBeacon e como implementar esses recursos principais usando as tecnologias do Couchbase Mobile. Observe que todo o código foi escrito em Swift 1.2.
Salvando dados localmente no dispositivo para o Couchbase Lite
O serviço primeiro coletará informações de beacons próximos e registrará as informações do dispositivo no banco de dados. Para sua exploração, a Apple tem uma boa quantidade de documentação sobre como localizar e alcançar iBeacons próximos. Para integrar o Couchbase Lite ao seu aplicativo móvel, você pode consultar o Portal do desenvolvedor do Couchbase Mobile para obter um código de exemplo de referência.
Implementação do ORM
Faremos com que o aplicativo mantenha objetos em classes nativas e implementaremos um ORM para mapear de e para a representação do Couchbase. Quando o aplicativo localizar um grupo de iBeacons, seus objetos de classe serão gerados. A classe inclui código para salvar o objeto no Couchbase e para carregá-lo do Couchbase. Aqui está a classe para manter um iBeacon:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
class Beacon : EntityDocument { var proximityID = “XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" var major : Int? = 0 var minor : Int? = 0 override func save() { let dict = NSMutableDictionary() dict["type"] = "gbeacon" dict["proximityID"] = proximityID dict["major"] = major ?? 0 dict["minor"] = minor ?? 0 super.save(dict) } override func load(document: CBLDocument) { super.load(document) proximityID = document.properties["proximityID"] as! String major = document.properties["major"] as? Int minor = document.properties["minor"] as? Int } } //EntityDocument is a base class for various objects: class EntityDocument { var document : CBLDocument? init () {} func save(dict: NSDictionary) { if document == nil { document = Database.sharedDatabase.createDocument(dict, object:self) } else { var error: NSError? var properties = NSMutableDictionary(dictionary: document!.properties) properties.addEntriesFromDictionary(dict as [NSObject : AnyObject]) if document!.putProperties(properties as [NSObject : AnyObject], error: &error) == nil { NSLog("%@", error!) } } } func load(document: CBLDocument) { self.document = document } func delete() { var error : NSError? if let doc = document { if !doc.deleteDocument(&error) { // Handle Error } } } } //Now can create Beacon object from a discovered 'foundBeacon'(CLBeacon iOS object) and save it simply with: let beacon = Beacon() beacon.proximityID = foundBeacon.proximityUUID beacon.major = foundBeacon.major beacon.minor = foundBeacon.minor beacon.save() } |
Sincronização de dados de beacon
Quando você estiver conectado a uma rede, o Couchbase Mobile sincronizará os dados usando Gateway de sincronização do Couchbase. Isso é tratado automaticamente quando configuramos nossas replicações push e pull, o que facilita muito manter o sistema coordenado. Podemos adicionar um método de observador para ouvir o estado das operações push e pull. No entanto, cada dispositivo precisa ouvir as alterações no banco de dados para as quais ele precisa agir, portanto, podemos adicionar um observador para uma notificação de alteração do banco de dados. Quando o banco de dados é alterado, atualizamos nossos objetos nativos locais. Para gerenciar a interação com o Couchbase, crie um objeto Database que instancie um singleton. Os principais conceitos estão delineados no código abaixo:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
private let _DatabaseSharedInstance = Database() class Database { var manager: CBLManager = CBLManager.sharedInstance() var db: CBLDatabase var my_push: CBLReplication var my_pull: CBLReplication class var sharedDatabase: Database { return _DatabaseSharedInstance } init() { var replication_url = NSURL(string: REPLICATION_URL) var error :NSError? db = manager.databaseNamed(DATABASE_NAME, error: &error) let push = db.createPushReplication(replication_url) let pull = db.createPullReplication(replication_url) push?.continuous = true pull?.continuous = true my_push = push my_pull = pull push.start() pull.start() NSNotificationCenter.defaultCenter().addObserver(self, selector: "replicationChanged:", name: kCBLReplicationChangeNotification, object: push) NSNotificationCenter.defaultCenter().addObserver(self, selector: "replicationChanged:", name: kCBLReplicationChangeNotification, object: pull) NSNotificationCenter.defaultCenter().addObserver(self, selector: "databaseChanged:", name: kCBLDatabaseChangeNotification, object: db) } @objc func databaseChanged(notification: NSNotification) { if let changes = notification.userInfo!["changes"] as? [CBLDatabaseChange] { for change in changes { NSLog("%@ changed", change.documentID) updateObject(change.documentID) } } } @objc func replicationChanged(notification: NSNotification) { let active = my_pull.status == CBLReplicationStatus.Active || my_push.status == CBLReplicationStatus.Active NSLog("%@ in replication changed: %@", notification.object!.description, active) // Now show a progress indicator: if active { var progress = 0.0 let total = my_push.changesCount + my_pull.changesCount let completed = my_push.completedChangesCount + my_pull.completedChangesCount if total > 0 { progress = Double(completed) / Double(total); NSLog("progress: %f", progress) } } } } |
Essas são as peças principais que permitem que o aplicativo móvel execute atividades locais, como o monitoramento de beacons próximos, salvando seu estado local e configurando serviços de sincronização para coordenar a consistência das informações entre as instâncias do aplicativo. A partir disso, você pode desenvolver mais funcionalidades e criar serviços sofisticados que possam sincronizar o estado em uma rede de aplicativos. No próximo blog, exploraremos o uso de beacon e Couchbase Mobile para oferecer aplicativos com reconhecimento de localização que funcionam sem conexão de rede.