En 2013 Apple Inc. introdujo una tecnología llamada iBeacon que se ejecuta sobre el protocolo Bluetooth 4.0, también conocido como Bluetooth de baja energía o BLE. Aunque los dispositivos con Bluetooth pueden identificarse a sí mismos, el proceso suele ser 1 a 1, con un anfitrión que se empareja con un dispositivo, como un teléfono inteligente que se empareja con unos auriculares Bluetooth. El iBeacon es simplemente un servicio de difusión que envía unas pocas piezas preconfiguradas de información y puede funcionar en paralelo con otros servicios Bluetooth. Para el debate, los cuatro parámetros de interés a la hora de crear aplicaciones beacon a partir de soluciones como Estimote o de Gimbal son la cadena UUID, un número mayor de 16 bits, un número menor de 16 bits y un valor de intensidad de señal.
En iOS7, Apple Inc. proporciona funcionalidades de biblioteca para trabajar con iBeacons y aunque hay 3rd para otras plataformas, el blog se centrará en iOS. Combinando las tecnologías de Couchbase Mobile, Ed Arenberg y el Equipo EPage está desarrollando un servicio que hace un uso intensivo de iBeacon y utiliza Couchbase Lite para el almacenamiento local, a la vez que sincroniza los datos entre varios dispositivos mediante Couchbase Sync Gateway.
Exploremos ahora los 3 componentes clave de este servicio iBeacon y cómo implementar estas características básicas utilizando las tecnologías de Couchbase Mobile. Ten en cuenta que todo el código está escrito en Swift 1.2.
Guardar datos localmente en el dispositivo en Couchbase Lite
El servicio recopilará primero información de las balizas cercanas y registrará la información del dispositivo en la base de datos. Para su exploración, Apple dispone de una buena cantidad de documentación sobre cómo localizar y alcanzar iBeacons cercanos. Para integrar Couchbase Lite en tu aplicación móvil, puedes consultar la página Portal para desarrolladores de Couchbase Mobile para ver el código de ejemplo de referencia.
Implantación de ORM
Haremos que la app guarde objetos en clases nativas e implementaremos un ORM para mapear hacia y desde la representación de Couchbase. Cuando la app localice un grupo de iBeacons, se generarán sus objetos de clase. La clase incluye código para guardar el objeto en Couchbase y para cargarlo desde Couchbase. Aquí está la clase para guardar un 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() } |
Sincronización de datos de balizas
Cuando esté conectado a una red, Couchbase Mobile sincronizará los datos utilizando Pasarela de sincronización Couchbase. Esto se maneja automáticamente una vez que configuramos nuestras réplicas push y pull, lo que hace muy fácil mantener el sistema coordinado. Podemos añadir un método observador para escuchar el estado de las operaciones push y pull. Sin embargo, cada dispositivo necesita escuchar los cambios en la base de datos para los que necesita tomar medidas, por lo que podemos añadir un observador para una notificación de cambio de base de datos. Cuando la base de datos cambia, actualizamos nuestros objetos nativos locales. Para gestionar la interacción con Couchbase, crea un objeto Database que instancie un singleton. Los conceptos principales están delineados en el siguiente código:
|
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) } } } } |
Estas son las piezas principales que permiten a la aplicación móvil ejecutar actividades locales, como la monitorización de balizas cercanas, guardar su estado local y configurar servicios de sincronización para coordinar la coherencia de la información entre las instancias de la aplicación. A partir de ahí, se pueden desarrollar más funcionalidades y crear servicios sofisticados capaces de sincronizar el estado de una red de aplicaciones. En el próximo blog exploraremos el uso de beacon y Couchbase Móvil para ofrecer aplicaciones de localización que funcionan sin conexión a la red.