Utilización e implementación de Beacons en Android
Problema (Dificultad Alta)
El problema a resolver consiste en implementar en Android funcionalidades utilizando Beacons. Es importante revisar las herramientas a utilizar dado que esta guía está orientada a utilizarse con una librería concreta, además se requieren conocimientos mínimamente básicos de Android.
Los Beacons son unos dispositivos de alcance mediano que permite enviar información a través de bluetooth, la gran mayoría utilizando el conocido como Bluetooth LE (bluetooth de baja energía). Con estos dispositivos podemos conocer la posición (en un rango) de un usuario con un smartphone u otro dispositivo, que disponga de una aplicación para procesar la información recibida de dichos Beacons. También nos permiten enviar otros datos almacenados en estos dispositivos.
¿Para qué podemos usarlos? Por ejemplo, queremos que un usuario de nuestra cadena de restaurantes de comida rápida, que se encuentra en uno de nuestros establecimientos, pueda consultar información determinada de ese establecimiento. Para asegurarnos de que el usuario se encuentra en dicho local, en la aplicación de nuestra cadena de restaurantes se activaría el bluetooth y detectaría el Beacon correspondiente.
¿Por que no usamos el GPS en vez de los beacons? Normalmente sería más sencillo por GPS, pero en espacios interiores dónde queremos más precisión o donde simplemente no haya cobertura GPS, los Beacons sí que pueden comunicarse.
Herramientas
Para esta implementación se ha utilizado:
- Hardware:
- Beacons: Modelo iBKS 105 de Accent Systems: https://accent-systems.com/product/ibks-105/
- Smartphone:
- Software:
- Android versión 5.0, es importante que la versión de Android sea superior o igual a la 4.4 dado que versiones anteriores no dan soporte al Bluetooth LE.
- http://altbeacon.github.io/android-beacon-library/download.html librería o API para el uso de beacons en Android, concretamente se ha utilizado la versión 2.7 de esta API.
- Android Studio version 2.0 para el desarrollo de la aplicación.
Solución
Configuración de la aplicación Android
En primer lugar lo que vamos a modificar es el archivo Manifest de Android, añadiendo el siguiente permiso a la aplicación.
<uses-permission android:name="android.permission.BLUETOOTH"/>
Después pasamos a modificar el Gradle o archivo de compilación de Android, de tal manera que debemos aseguramos de tener jcenter definido
allprojects {
repositories {
jcenter()
}
}
En el Gradle además tenemos que añadir la API que hemos descargado de la web:
dependencies { ... compile 'org.altbeacon:android-beacon-library:2.7' ... }
Configuración del beacon iBKS
En el siguiente enlace tenéis toda la información disponible para la configuración del beacon: https://accent-systems.com/support/knowledge/ibks-config-tool-user-manual/
Simplemente tendremos que descargarnos una aplicación móvil y extraer la pila del beacon cuando queramos hacer modificaciones en su configuración, a través de la aplicación, como por ejemplo cambiar su id.
Os dejo directamente el enlace dado que la aplicación difiere en cada versión.
Implementación del Activity
Para utilizar los Beacons vamos a crear una actividad especial para ello, perteneciente a la API ya mencionada. Tendremos que estender la interfaz BeaconConsumer. Además necesitaremos un objeto que gestiona la información de los beacons, el cual inicializaremos como se muestra en el siguiente fragmento de código.
public class DialogActivity extends AppCompatActivity implements BeaconConsumer{ public BeaconManager beaconManager;beaconManager = BeaconManager.getInstanceForApplication(this); beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25")); beaconManager.bind(this) ... }
Donde la instancia es el Activity actual, el BeaconParser identifica el modelo o tipo de dispositivo beacon y el método bind sirve para guardar los cambios. Copiamos tal cual la cadena del setBeaconLayout, para este modelo de beacon, es el que funciona correctamente.
Una vez hecho esto será necesario definir las funciones de la interfaz:
@Override public void onBeaconServiceConnect(){ ... }
Dentro de este método a su vez rellenaremos más datos de la variable beaconManager definida en el Activity, se trata de una variable Region que nos permita identificar unívocamente el beacon que queremos que nos detecte.
final Region region = new Region("myBeacons", Identifier.parse("id"), null, null);
En esta línea de código tenemos como primer argumento el nombre de la región y el segundo argumento es el identificador del beacon que queremos detectar.
Entrada y salida en la región Beacon
Para ello definiremos un Monitor el cual se compone de varias funciones obligatorias a definir:
beaconManager.setMonitorNotifier(new MonitorNotifier() { @Override public void didEnterRegion(Region region) { //Hemos entrado en la región beacon } @Override public void didExitRegion(Region region) { //Hemos salido de la región beacon } @Override public void didDetermineStateForRegion(int i, Region region) { } }Una vez definido el monitor podemos inicializarlo para comenzar a detectar que hemos entrado en un determinado espacio (cercano al Beacon):beaconManager.startMonitoringBeaconsInRegion(region)
Detección del rango Beacon
El notificador de rango nos permite obtener información del Beacon periódicamente, es decir, tendrá definida una frecuencia de emisión, por lo que una vez hayamos entrado en la región del Beacon nos enviará información con dicha frecuencia.
Para ello definiremos el notificador de rango el cual tiene un método obligatorio a definir:
beaconManager.setRangeNotifier(new RangeNotifier() { @Override public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) { for (org.altbeacon.beacon.Beacon oneBeacon : beacons){ beaconDistance = oneBeacon.getDistance(); } } });
En el código anterior podemos ver la utilidad del notificador de rango, en este caso concreto estamos obteniendo la distancia a la que se encuentra un solo Beacon con respecto a la posición de nuestro dispositivo móvil.
Con esto podremos, por ejemplo, realizar triangulación de posiciones entre otras cosas.
Finalización
Para terminar de detectar la monitorización y rango del beacon se utilizarán las siguientes funciones:
beaconManager.stopMonitoringBeaconsInRegion(region); beaconManager.stopRangingBeaconsInRegion(region); beaconManager.unbind(this);//Desvinculamos el monitor y el rango
Ejemplos
Más información del código
Códigos completos del beacon se pueden encontrar en el siguiente enlace:
Actualización de UI respecto al beacon
Para llevar a cabo cambios en la interfaz debido a la detección de beacons o de la proximidad, utilizaremos una hebra (AsyncTask) que consultará con frecuencia ciertas variables de la Activity las cuales cambian su valor a través de los métodos del Beacon anteriormente vistos.
Código del activity
public class MyActivity extends AppCompatActivity implements BeaconConsumer{ public updateUIByBeacon beaconUpdateUi; public BeaconManager beaconManager; public boolean beaconDetected; //Con esta variable cambiará la interfaz @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my); ... //Inizializamos el beaconManager beaconManager = BeaconManager.getInstanceForApplication(this); beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("…")); beaconManager.bind(this); //Lanzamos la hebra de actualización de interfaz beaconUpdateUi = new updateUIByBeacon(); beaconUpdateUi.execute(); } @Override public void onDestroy(){ super.onDestroy(); if(beaconManager != null) beaconManager.unbind(this); } public void updateUI() {//Aquí haremos los cambios que queramos en la interfaz } @Override public void onBeaconServiceConnect() { final Region region = new Region("myBeacons", Identifier.parse("…"), null, null); //Monitor beaconManager.setMonitorNotifier(new MonitorNotifier() { @Override public void didEnterRegion(Region region) { try { beaconDetected = true;//Cuando esto ocurra cambiará la interfaz } catch (RemoteException e) { } } @Override public void didExitRegion(Region region) { ... } @Override public void didDetermineStateForRegion(int i, Region region) { ... } }); } }
Código de la hebra
public class updateUIByBeacon extends AsyncTask<Void, Double, Boolean> { @Override protected Boolean doInBackground(Void... params) { while (!beaconDetected){ try { Thread.sleep(250);//Cada 0,25 seg vemos si hemos entrado en región beacon } catch (InterruptedException e) { e.printStackTrace(); } } return null; } @Override protected void onPreExecute() { beaconDetected = false;//Inicialmente que el beacon se haya detectado es falso } @Override protected void onPostExecute(Boolean result) { Toast.makeText(getApplicationContext(),"¡Hemos llegado!", Toast.LENGTH_LONG).show();//En el activity notificamos la detección del beacon updateUI();//En este método hacemos los cambios pertinentes a la interfaz } }
En este ejemplo simplemente cambiamos la interfaz cuando se detecta un beacon. De esta manera la aplicación seguirá ejecutándose y mientras tanto podremos ver los cambios en la interfaz producidos por los beacons.
Otro ejemplo sería que podríamos ir mostrando en pantalla la distancia a la que está el beacon, solo que en este caso habría que definir además el notificador de rango.
Conclusiones
Con este esquema general de la aplicación podremos utilizar los Beacons para enviar información de posicionamiento y realizar acciones en consecuencia, como por ejemplo una acción en la aplicación al entrar en un área, o bien al salir de esta, o al llevar cierto tiempo en ella, etc. Cualquier duda o sugerencia ponedla en los comentarios.
Comentarios
Publicar un comentario