Students Save 30%! Learn & create with unlimited courses & creative assets Students Save 30%! Save Now
Advertisement
  1. Code
  2. iOS SDK
Code

iOS 7 SDK: Core Bluetooth - Lección práctica

Difficulty:IntermediateLength:LongLanguages:
This post is part of a series called iOS 7 SDK Essentials.
iOS 7 SDK: Core Bluetooth - Theoretical Overview
iOS 7 SDK: iBeacons Game

Spanish (Español) translation by Elías Nicolás (you can also view the original English article)

El marco Core Bluetooth (CB) proporciona los recursos que sus aplicaciones iOS necesitan para comunicarse con dispositivos que están equipados con tecnología Bluetooth de baja energía (BTLE). Este tutorial lo guiará a través de la evolución de CB desde iOS 5 a iOS 7. Además, aprenderá cómo configurar un Core Bluetooth central y periférico, cómo comunicarse entre ellos y las mejores prácticas de programación inherentes cuando trabaje con CB.


Introducción

Los tutoriales Core Bluetooth están divididos en dos partes. El primero cubre el aspecto teórico de Core Bluetooth, mientras que este tutorial es una lección práctica completa. Encontrará el código fuente completo adjunto a esta publicación.


1. Descargue el código fuente de muestra

El objetivo de este tutorial es enseñarle cómo usar el marco Core Bluetooth. Preparamos un código fuente de muestra que hará que su vida sea más fácil y eludirá la configuración del proyecto y las vistas de creación. Debe descargar el código de muestra al principio de esta página.

Suponemos que conoce los conceptos básicos de Xcode e iOS, ya que solo nos centraremos en los datos Core Bluetooth. El código de muestra contiene lo siguiente:

  • Una aplicación que usa el controlador de navegación, tres vistas y los controladores inherentes.
  • El controlador de vista inicial ViewController con dos botones
  • Un CBCentralManagerViewController que crea un iBeacon personalizado
  • Un CBPeripheralViewController que recibe el iBeacon y la información inherente
  • Un archivo de encabezado SERVICES con algunas variables para usar en la aplicación.

Todas las vistas ya están en su lugar y debidamente definidas. Solo necesita agregar el código para el proceso Core Bluetooth. Abra el proyecto, ejecútelo y juegue con los objetos para familiarizarse con el código.

El archivo SERVICES.h contiene dos UUID únicos. Esos fueron generados usando el comando terminal uuidgen. Debe generarlos en su aplicación, o puede usar esos.

Tenga en cuenta que esta lección necesita dos dispositivos iOS para funcionar correctamente. Ejecute Run el proyecto y verá una interfaz similar a esta:

iOS_CB_Image4
Ilustración de la interfaz CB

2. Programación de un rol central

En este tutorial, centrará la clase CBCentralManagerViewController. El primer paso es agregar los dos protocolos que admiten CBCentralManager y CBPeripheral. La declaración de esos protocolos define métodos (más sobre esto más adelante). Su interfaz interface debería ser así:

Ahora debe definir tres propiedades: CBCentralManager, CBPeripheral y NSMutableData. Los dos primeros son obvios y el último se usa para almacenar información que se comparte entre dispositivos.

En este punto, puede cambiar al archivo de implementación. Verá una advertencia, pero antes de resolver eso, debe iniciar el administrador central centralManger y los objetos de datos data.  Debe iniciar el centralManager con un auto delegado y sin ninguna cola. Debería usar el método viewDidLoad y el resultado debería ser similar a esto:

Para resolver el problema de advertencia, debe agregar el método - (void)centralManagerDidUpdateState:(CBCentralManager *)central.

Es un método de protocolo obligatorio. Comprueba el estado del dispositivo y actúa en consecuencia. Existen varios estados posibles y en su aplicación siempre debe verificarlos. Los estados son:

  • CBCentralManagerStateUnknown
  • CBCentralManagerStateResetting
  • CBCentralManagerStateUnsupported
  • CBCentralManagerStateUnauthorized
  • CBCentralManagerStatePoweredOff
  • CBCentralManagerStatePoweredOn

Por ejemplo, si ejecuta esta aplicación en un dispositivo que no es Bluetooth 4.0, obtendrá el código CBCentralManagerStateUnsupported. Aquí irá a CBCentralManagerStatePoweredOn y cuando ocurra, comenzará a buscar dispositivos. Para eso, use el método scanForPeripheralsWithServices. Si pasa nil como primer argumento, CBCentralManager comienza a buscar cualquier servicio. Aquí usará el UUID almacenado en SERVICES.h.

El método completo es:

En este momento, su aplicación buscará otros dispositivos. Pero a pesar de que ninguno o ninguno está disponible, no obtendrá ninguna información. Podemos arreglarlo. Debería agregar el - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI . Se llamará cada vez que se descubra un dispositivo. Sin embargo, lo programará para que reaccione solo a los periféricos que anuncian TRANSFER_SERVICE_UUID.

Además, utilizaremos el nuevo sistema de caché y almacenaremos el dispositivo para referencia futura y comunicación más rápida. El código fuente completo es el siguiente:

La conexión a ese dispositivo puede fallar. Necesitamos lidiar con ese escenario usando un método específico llamado: - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error. Añádalo e informe al usuario sobre ese error.

Notará una advertencia, ya que el método de limpieza cleanup todavía no se ha declarado. ¡Vamos a declararlo! En este punto, puede encontrar que el código fuente del método es complicado. Sin embargo, lo explicaremos más adelante. Debería regresar al final del tutorial para una comprensión completa.

Este método cancela todas las suscripciones a un dispositivo remoto (si hay alguno) o se desconecta directamente si no es así. Recorre los servicios, luego las características y elimina los enlaces a ellos. El método completo es:

Teniendo en cuenta que nos conectamos con éxito al dispositivo, ahora tenemos que descubrir los servicios y las características de la misma. Debe declarar el - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral. Una vez establecida la conexión, detenga el proceso de escaneo. Luego borre los datos que podamos haber recibido. Luego, asegúrese de obtener las devoluciones de llamadas de descubrimiento y, finalmente, buscar servicios que coincidan con su UUID (TRANSFER_SERVICE_UUID). Aquí está el código:

En este punto, el periférico comienza a notificar a su delegado con varias devoluciones de llamada. Una de esas devoluciones es el - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error. Se usa para descubrir las características de un servicio determinado. No es que siempre deba verificar si ese método arroja un error. Si no se encuentra ningún error, debe encontrar las características que necesita, en este caso el TRANSFER_CHARACTERISTIC_UUID. Aquí está el método completo:

En este punto, si todo es correcto, se descubrió la característica de transferencia. Una vez más, se llama un método delegado: - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error. Una vez que haya encontrado esto, desea suscribirse, lo que le permite a su CBCentralManager recibir los datos de ese periférico.

Una vez más, debe lidiar con los errores (si los hubiera). Puedes dar un salto de fe y suscribirte directamente a la característica. Sin embargo, debe recorrer el conjunto de características y verificar si la característica es la correcta. Si es así, suscríbete a él. Una vez que esto esté completo, solo necesita esperar a que ingresen los datos (otro método). El método completo está debajo.

Cada vez que el periférico envía datos nuevos, el delegado periférico utiliza el método de error - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error . El segundo argumento contiene la característica que puedes leer.

Inicialmente, creará un NSString para almacenar el valor característico. Luego, verificará si los datos recibidos están completos o si se entregarán más. Simultáneamente, actualizará su vista de texto textview  tan pronto como se reciban nuevos datos. Una vez completados todos los datos, puede desconectarse de la característica y desconectarse del dispositivo (aunque puede permanecer conectado).

Tenga en cuenta que, después de los datos entrantes, puede desconectarse o esperar por otros datos. Esta devolución de llamada nos permite saber si ha llegado más información mediante la notificación de la característica. La fuente completa está a continuación:

Además, hay un método que asegura que CBCentral sabe cuándo cambia un estado de notificación para una característica dada. Es muy importante rastrearlo para comprender cuándo cambia un estado característico (actualizar los valores de la aplicación). El método es: - (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error. Debería verificar si la notificación característica se ha detenido. Si es así, debes desconectarte de él:

Si se produce la desconexión entre dispositivos, debe limpiar su copia local del periférico. Para eso use el método de error - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error. Este método es simple y establece el periférico a cero. Además, puede reiniciar el escaneo del dispositivo o salir de la aplicación (u otra). En este ejemplo, reiniciará el proceso de escaneo.

Finalmente, se requiere un paso adicional. Cada vez que desaparece la vista, debe detener el proceso de escaneo. En el método animado viewWillDisappear:(BOOL)animated debe agregar:

Puede Run ejecutar la aplicación, sin embargo, necesita la aplicación periférica para recibir algunos datos. La siguiente imagen presenta la interfaz final de CBCentralManager.

iOS_CB_Image5
Ilustración del CBCentralManager.

3. Programando un rol periférico

En este tutorial, se centrará en la clase CBPeripheralViewController. El primer paso es agregar dos protocolos: CBPeripheralManagerDelegate y UITextViewDelegate. Su interfaz interface ahora debe verse así:

Ahora debe definir cuatro propiedades: CBPeripheralManager, CBMutableCharacteristic, NSData, y NSInterger. Los dos primeros representan el administrador periférico y sus características, mientras que el tercero son los datos que se enviarán. El último representa el índice de datos.

Ahora cambie al archivo de implementación. Nuestro primer paso es iniciar _peripheralManager y configurarlo para comenzar a publicitar. La publicidad del servicio debe iniciarse con el UUID del servicio antes mencionado. Su viewDidLoad debe verse así:

Deberías ver una advertencia. Para solucionarlo, declare el método de protocolo periférico - (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral. Al igual que CBCentralManager, debe controlar y probar todos los estados de la aplicación. Si el estado es CBPeripheralManagerStatePoweredOn debe construir y definir su servicio y características (una de las características reales de iOS 7).

Cada servicio y característica debe identificarse mediante un UUID único. Tenga en cuenta que el tercer argumento del método init está en nada. Al hacerlo, declara que los datos que se intercambiarán se definirán más adelante. Esto generalmente se hace cuando desea crear datos dinámicamente. Si desea tener un valor estático para transmitir, puede declararlo aquí.

Las propiedades determinan cómo se puede usar el valor característico y hay varios valores posibles:

  • CBCharacteristicPropertyBroadcast
  • CBCharacteristicPropertyRead
  • CBCharacteristicPropertyWriteWithoutResponse
  • CBCharacteristicPropertyWrite
  • CBCharacteristicPropertyWrite
  • CBCharacteristicPropertyNotify
  • CBCharacteristicPropertyIndicate
  • CBCharacteristicPropertyAuthenticatedSignedWrites
  • CBCharacteristicPropertyExtendedProperties
  • CBCharacteristicPropertyNotifyEncryptionRequired
  • CBCharacteristicPropertyIndicateEncryptionRequired

Para una comprensión completa de esas propiedades, debe verificar la Referencia de clase de característica CBC.

El último argumento de init es los permisos de lectura, escritura y encriptación para un atributo. De nuevo, hay varios valores posibles:

  • CBAttributePermissionsReadable
  • CBAttributePermissionsWriteable
  • CBAttributePermissionsReadEncryptionRequired
  • CBAttributePermissionsWriteEncryptionRequired

Después de que la característica lo definió, ahora es el momento de definir el servicio utilizando CBMutableService. Tenga en cuenta que el servicio debe definirse con TRANSFER_CHARACTERISTIC_UUID. Agregue la característica al servicio y luego agréguela al administrador de periféricos. El método completo está a continuación:

Ahora que tenemos el servicio y sus características (uno en este caso), ahora es el momento de detectar cuándo un dispositivo se conecta a este y reacciona en consecuencia. El - (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic el método característico capta cuando alguien se suscribe a nuestra característica y luego comienza a enviar datos.

La aplicación envía los datos disponibles en la vista de texto textview. Si el usuario lo cambia, la aplicación se lo envía en tiempo real a la suscripción central. El método llama a un método personalizado llamado sendData.

SendData es el método que trata con toda la lógica con respecto a la transferencia de datos. Puede hacer varias acciones como:

  • Enviar datos
  • Enviar el final de la bandera de comunicación
  • Prueba si la aplicación envió los datos
  • Verificar si se enviaron todos los datos
  • Reacciona a todos los temas anteriores

El código fuente completo se presenta a continuación. Varios comentarios se dejaron deliberadamente para facilitar su comprensión.

Finalmente, debe definir una devolución de llamada que se llama cuando el PeripheralManager está listo para enviar el siguiente fragmento de datos. Esto asegura que los paquetes lleguen en el orden en que se envían. El método es el - (void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral y solo llama al método sendData. La versión completa está a continuación:

Ahora puede ejecutar Run la aplicación y probar la comunicación Bluetooth. La siguiente imagen muestra la interfaz de CBCentralManager.

iOS_CB_Image6
Ilustración de la interfaz periférica.

Conclusión

Al final de este tutorial, debe comprender las especificaciones del marco Core Bluetooth. También debería poder definir y configurar un CBCentralManager y un rol CBPeripheral, y comprender y aplicar algunas de las mejores prácticas cuando se desarrolla con Core Bluetooth.

Si tiene alguna pregunta o comentario, ¡déjela abajo!

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.