Publicar y suscribirse

La API de Nearby Messages es una API de publicación y suscripción que permite que los dispositivos cercanos intercambien pequeñas cargas útiles de datos. Cuando un dispositivo publica un mensaje, los dispositivos cercanos pueden recibirlo. El tamaño de los mensajes debe ser bastante pequeño para mantener un buen rendimiento. Este servicio no se diseñó para intercambiar objetos más grandes, como fotos y videos.

El conjunto de dispositivos cercanos se determina mediante el intercambio de tokens pequeños a través de Bluetooth y audio casi ultrasónico (audible). Cuando un dispositivo detecta un token de un dispositivo cercano, lo envía al servidor de Nearby Messages para validarlo y verificar si hay mensajes que entregar para el conjunto actual de suscripciones de la aplicación.

Una aplicación puede controlar el conjunto de medios que se usan para el descubrimiento de dispositivos y si los medios se usan para transmitir tokens o buscar tokens. De forma predeterminada, la transmisión y la búsqueda se realizan en todos los medios. Para realizar el descubrimiento en un subconjunto o medios y controlar si se debe transmitir o analizar, debes pasar parámetros adicionales cuando creas publicaciones y suscripciones.

Esta biblioteca se ejecuta en iOS 7 y versiones posteriores, y se compila con el SDK de iOS 8.

Cómo crear un administrador de mensajes

Este código crea un objeto de administrador de mensajes, que te permite publicar y suscribirte. El intercambio de mensajes no está autenticado, por lo que debes proporcionar una clave de API pública para iOS. Puedes crear una con la entrada de Google Developers Console en tu proyecto.

Objective‑C

#import <GNSMessages.h>

GNSMessageManager *messageManager =
    [[GNSMessageManager alloc] initWithAPIKey:@"API_KEY"];

Swift

let messageManager = GNSMessageManager(APIKey: "API_KEY")

Cómo publicar un mensaje

Este fragmento de código muestra cómo publicar un mensaje que contiene un nombre. La publicación estará activa mientras exista el objeto de la publicación. Para dejar de publicar, libera el objeto de la publicación.

Objective‑C

id<GNSPublication> publication =
    [messageManager publicationWithMessage:[GNSMessage messageWithContent:[name dataUsingEncoding:NSUTF8StringEncoding]]];

Swift

let publication =
    messageManager.publication(with: GNSMessage(content: name.data(using: .utf8)))

Cómo suscribirse a mensajes

Este fragmento de código muestra la suscripción a todos los nombres que comparte el fragmento de la publicación anterior. La suscripción permanecerá activa mientras existan los objetos de suscripción. Para detener la suscripción, libera el objeto de suscripción.

Se llama al controlador de mensajes encontrados cuando se detectan dispositivos cercanos que publican mensajes. Se llama al controlador de mensajes perdidos cuando un mensaje ya no se observa (el dispositivo está fuera del alcance o ya no publica el mensaje).

Objective‑C

id<GNSSubscription> subscription =
    [messageManager subscriptionWithMessageFoundHandler:^(GNSMessage *message) {
      // Add the name to a list for display
    }
    messageLostHandler:^(GNSMessage *message) {
      // Remove the name from the list
    }];

Swift

let subscription =
    messageManager.subscription(messageFoundHandler: { (message: GNSMessage?) in
      // Add the name to a list for display
    },
    messageLostHandler: { (message: GNSMessage?) in
      // Remove the name from the list
    })

Medios de descubrimiento

De forma predeterminada, se usarán ambos medios (audio y Bluetooth) para detectar dispositivos cercanos, y ambos medios transmitirán y buscarán. En algunos casos, debes agregar las siguientes entradas al Info.plist de tu app:

  • Si tu app escanea con audio, agrega NSMicrophoneUsageDescription, que es una cadena que describe por qué usarás el micrófono. Por ejemplo, "El micrófono detecta tokens anónimos de dispositivos cercanos".

  • Si tu app transmite con BLE, agrega NSBluetoothPeripheralUsageDescription, que es una cadena que describe por qué harás publicidad en BLE. Por ejemplo, "Un token anónimo se anuncia a través de Bluetooth para descubrir dispositivos cercanos".

En algunos casos, es posible que tu app necesite usar solo uno de los medios y que no necesite realizar la transmisión y la búsqueda en ese medio.

Por ejemplo, una app diseñada para conectarse a un decodificador que transmite audio solo necesita escanear el audio para descubrirlo. En el siguiente fragmento, se muestra cómo publicar un mensaje en ese decodificador usando solo el análisis de audio para la detección:

Objective‑C

id<GNSPublication> publication = [messageManager publicationWithMessage:message
    paramsBlock:^(GNSPublicationParams *params) {
      params.strategy = [GNSStrategy strategyWithParamsBlock:^(GNSStrategyParams *params) {
        params.discoveryMediums = kGNSDiscoveryMediumsAudio;
        params.discoveryMode = kGNSDiscoveryModeScan;
      }];
    }];

Swift

let publication = messageManager.publication(with: message,
    paramsBlock: { (params: GNSPublicationParams?) in
      guard let params = params else { return }
      params.strategy = GNSStrategy(paramsBlock: { (params: GNSStrategyParams?) in
        guard let params = params else { return }
        params.discoveryMediums = .audio
        params.discoveryMode = .scan
      })
    })

Habilita el registro de depuración

El registro de depuración imprime eventos internos significativos en la consola que pueden ser útiles para localizar los problemas que pueden surgir durante la integración de Nearby Messages en tu app. Solicitaremos estos registros si te comunicas con nosotros para obtener asistencia técnica.

Debes habilitarlo antes de crear un administrador de mensajes. En este fragmento de código, se muestra cómo habilitar el registro de depuración:

Objective‑C

[GNSMessageManager setDebugLoggingEnabled:YES];

Swift

GNSMessageManager.setDebugLoggingEnabled(true)

Cómo realizar un seguimiento del estado del permiso de Nearby

Se requiere el consentimiento del usuario para habilitar el descubrimiento de dispositivos. Esto se indica mediante el estado del permiso de Nearby. En la primera llamada para crear una publicación o suscripción, se muestra un cuadro de diálogo de consentimiento al usuario. Si el usuario no da su consentimiento, no funcionará el descubrimiento de dispositivos. En este caso, tu app debe mostrar un mensaje para recordarle al usuario que el descubrimiento de dispositivos está inhabilitado. El estado del permiso se almacena en NSUserDefaults.

En el siguiente fragmento, se muestra la suscripción al estado del permiso. Se llama al controlador de estado modificado del permiso cada vez que cambia el estado y no se llama la primera vez hasta que el usuario otorga o rechaza el permiso. Libera el objeto de permiso para detener la suscripción.

Objective‑C

GNSPermission *nearbyPermission = [[GNSPermission alloc] initWithChangedHandler:^(BOOL granted) {
  // Update the UI here
}];

Swift

let nearbyPermission = GNSPermission(changedHandler: { (granted: Bool) in
  // Update the UI here
})

Tu app puede proporcionar al usuario una forma de cambiar el estado del permiso; por ejemplo, mediante un interruptor de activación en una página de configuración.

Este es un ejemplo de cómo obtener y establecer el estado del permiso.

Objective‑C

BOOL permissionState = [GNSPermission isGranted];
[GNSPermission setGranted:!permissionState];  // toggle the state

Swift

let permissionState = GNSPermission.isGranted()
GNSPermission.setGranted(!permissionState)  // toggle the state

Seguimiento de la configuración de usuario que afecta a Nearby

Si el usuario rechazó el permiso del micrófono o el Bluetooth, o bien desactivó el Bluetooth, Nearby no funcionará bien o es posible que no funcione en absoluto. En esos casos, tu app debería mostrar un mensaje que informe al usuario sobre el obstáculo de las operaciones de Nearby. En el siguiente fragmento, se muestra cómo hacer un seguimiento del estado de esta configuración del usuario pasando controladores cuando se crea el administrador de mensajes:

Objective‑C

GNSMessageManager *messageManager = [[GNSMessageManager alloc]
    initWithAPIKey:API_KEY
       paramsBlock:^(GNSMessageManagerParams *params) {
         params.microphonePermissionErrorHandler = ^(BOOL hasError) {
           // Update the UI for microphone permission
         };
         params.bluetoothPowerErrorHandler = ^(BOOL hasError) {
           // Update the UI for Bluetooth power
         };
         params.bluetoothPermissionErrorHandler = ^(BOOL hasError) {
           // Update the UI for Bluetooth permission
         };
}];

Swift

let messageManager = GNSMessageManager(
         APIKey: API_KEY,
    paramsBlock: { (params: GNSMessageManagerParams?) in
      guard let params = params else { return }
      params.microphonePermissionErrorHandler = { (hasError: Bool) in
        // Update the UI for microphone permission
      }
      params.bluetoothPowerErrorHandler = { (hasError: Bool) in
        // Update the UI for Bluetooth power
      }
      params.bluetoothPermissionErrorHandler = { (hasError: Bool) in
        // Update the UI for Bluetooth permission
      }
    })

Anula el diálogo del permiso de Nearby

Según los parámetros que pases a tus publicaciones y suscripciones, es posible que iOS solicite varios permisos antes de permitir que Nearby funcione. Por ejemplo, la estrategia predeterminada escucha los datos transmitidos en el audio casi ultrasónico, por lo que iOS solicita permiso para usar el micrófono. En estos casos, Nearby mostrará un diálogo de "verificación previa" que explica por qué se le solicita permiso al usuario.

Si quieres proporcionar un diálogo de "verificación previa" personalizado, establece el parámetro permissionRequestHandler en un bloque personalizado en los parámetros de publicación o suscripción. El bloque personalizado debe llamar al bloque permissionHandler después de que el usuario haya respondido. En el siguiente fragmento, se muestra cómo hacerlo para una publicación:

Objective‑C

id<GNSPublication> publication =
    [messageManager publicationWithMessage:[GNSMessage messageWithContent:[name dataUsingEncoding:NSUTF8StringEncoding]]
                               paramsBlock:^(GNSPublicationParams *params) {
                                 params.permissionRequestHandler = ^(GNSPermissionHandler permissionHandler) {
                                   // Show your custom dialog here.
                                   // Don't forget to call permissionHandler() with YES or NO when the user dismisses it.
                                 };
                               }];

Swift

let publication =
    messageManager.publication(with: GNSMessage(content: name.data(using: .utf8)),
        paramsBlock: { (params: GNSPublicationParams?) in
          guard let params = params else { return }
          params.permissionRequestHandler = { (permissionHandler: GNSPermissionHandler?) in
            // Show your custom dialog here.
            // Don't forget to call permissionHandler() with true or false when the user dismisses it.
          }
        })

Operación en segundo plano

Las publicaciones y suscripciones que usan BLE para la detección de dispositivos pueden funcionar en segundo plano. A continuación, se incluyen algunos aspectos que debes tener en cuenta cuando decidas usar el modo en segundo plano:

  • Las operaciones en segundo plano solo deben usar el medio BLE; no se admite audio.
  • Se aplica un costo de batería adicional para la reproducción en segundo plano de BLE. El costo es bajo, pero debes medirlo antes de decidir usar el modo en segundo plano.
  • iOS le pedirá al usuario permiso para publicar anuncios a través de BLE en segundo plano.

Para agregar el modo en segundo plano a una publicación o suscripción, sigue estos pasos adicionales:

  • Para habilitar el modo en segundo plano y solo BLE en tu publicación o suscripción, pasa un objeto GNSStrategy configurado correctamente. En el siguiente fragmento, se muestra cómo hacerlo para una suscripción:

    Objective‑C

    id<GNSSubscription> subscription =
        [messageManager subscriptionWithMessageFoundHandler:^(GNSMessage *message) {
          // Add the name to a list for display
        }
        messageLostHandler:^(GNSMessage *message) {
          // Remove the name from the list
        }
        paramsBlock:^(GNSSubscriptionParams *params) {
          params.strategy = [GNSStrategy strategyWithParamsBlock:^(GNSStrategyParams *params) {
            params.allowInBackground = YES;
            params.discoveryMediums = kGNSDiscoveryMediumsBLE;
          }];
        }];
    

    Swift

    let subscription =
        messageManager.subscription(messageFoundHandler: { (message: GNSMessage?) in
          // Add the name to a list for display
        },
        messageLostHandler: { (message: GNSMessage?) in
          // Remove the name from the list
        },
        paramsBlock:{ (params: GNSSubscriptionParams?) in
          guard let params = params else { return }
          params.strategy = GNSStrategy(paramsBlock: { (params: GNSStrategyParams?) in
            guard let params = params else { return }
            params.allowInBackground = true
            params.discoveryMediums = .BLE
          })
        })
    

  • Agrega estas entradas al Info.plist de tu app:

    • Entradas de UIBackgroundModes:

      • bluetooth-central para el escaneo BLE en segundo plano Solo se necesita cuando el modo de descubrimiento incluye análisis; lo hace de forma predeterminada.
      • bluetooth-peripheral para la publicidad BLE en segundo plano. Solo se necesita cuando el modo de descubrimiento incluye transmisiones; lo hace de forma predeterminada.
    • Es una cadena de NSBluetoothPeripheralUsageDescription que describe el motivo por el que publicarás anuncios en BLE. Por ejemplo, "Un token anónimo se anuncia a través de Bluetooth para descubrir dispositivos cercanos". Consulta la documentación de Apple para obtener más detalles.

  • El sistema puede cerrar tu app en cualquier momento mientras se encuentra en segundo plano. Si el modo en segundo plano es una configuración que el usuario puede habilitar o inhabilitar, tu app debería hacer lo siguiente:

    • Guarda el valor del modo en segundo plano en NSUserDefaults cada vez que el usuario lo cambie.
    • Durante el inicio, léelo desde NSUserDefaults y restablece las publicaciones o suscripciones de Nearby si el modo en segundo plano está habilitado.

Notificaciones en segundo plano

Si quieres que tu app notifique al usuario cuando una suscripción recibe un mensaje mientras está en segundo plano, puedes usar las notificaciones locales.

Sigue estos pasos para agregarlos a tu app:

  • Regístrate para recibir notificaciones locales en el inicio:

    Objective‑C

    if ([UIApplication instancesRespondToSelector:@selector(registerUserNotificationSettings:)]) {
      [[UIApplication sharedApplication] registerUserNotificationSettings:
          [UIUserNotificationSettings settingsForTypes:
              UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound
                                            categories:nil]];
    }
    

    Swift

    UIApplication.shared.registerUserNotificationSettings(
        UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil))
    

  • Envía una notificación local en el controlador de mensajes encontrados de tu suscripción:

    Objective‑C

    GNSMessageHandler myMessageFoundHandler = ^(GNSMessage *message) {
        // Send a local notification if not in the foreground.
        if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive) {
          UILocalNotification *localNotification = [[UILocalNotification alloc] init];
          localNotification.alertBody = @"Message received";
          [[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
        }
        // Process the new message...
      };
    

    Swift

    let myMessageFoundHandler: GNSMessageHandler = { (message: GNSMessage?) in
      // Send a local notification if not in the foreground.
      if UIApplication.shared.applicationState != .active {
        let localNotification = UILocalNotification()
        localNotification.alertBody = "Message received"
        UIApplication.shared.presentLocalNotificationNow(localNotification)
      }
      // Process the new message...
    }