Опубликовать и подписаться

API Nearby Messages — это API типа «публикация-подписка», позволяющий находящимся поблизости устройствам обмениваться небольшими объемами данных. После того, как устройство опубликует сообщение, находящиеся поблизости устройства смогут его получить. Размер сообщения должен быть достаточно небольшим для обеспечения хорошей производительности. Этот сервис не предназначен для обмена более крупными объектами, такими как фотографии и видео.

Набор ближайших устройств определяется обменом небольшими токенами по Bluetooth и ближнему ультразвуковому (неслышимому) звуку. Когда устройство обнаруживает токен от ближайшего устройства, оно отправляет его на сервер Nearby Messages для проверки и определения наличия сообщений для доставки в рамках текущей подписки приложения.

Приложение может управлять набором носителей, используемых для обнаружения устройств, а также тем, будут ли эти носители использоваться для трансляции токенов и/или сканирования токенов. По умолчанию трансляция и сканирование выполняются на всех носителях. Для обнаружения на подмножестве или нескольких носителях, а также для управления трансляцией или сканированием, необходимо передать дополнительные параметры при создании публикаций и подписок.

Эта библиотека работает на iOS 7 и выше и компилируется с помощью SDK iOS 8 .

Создание менеджера сообщений

Этот код создает объект менеджера сообщений, который позволяет публиковать и подписываться на сообщения. Обмен сообщениями происходит без аутентификации, поэтому вам необходимо указать открытый ключ API для iOS. Вы можете создать его, используя запись в консоли разработчиков Google для вашего проекта.

Objective-C

#import <GNSMessages.h>

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

Быстрый

let messageManager = GNSMessageManager(APIKey: "API_KEY")

Публикация сообщения

Этот фрагмент кода демонстрирует публикацию сообщения, содержащего имя. Публикация активна до тех пор, пока существует объект публикации. Чтобы остановить публикацию, освободите объект публикации.

Objective-C

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

Быстрый

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

Подписка на сообщения

Этот фрагмент кода демонстрирует подписку на все имена, общие для предыдущего фрагмента публикации. Подписка активна до тех пор, пока существует объект подписки. Чтобы прекратить подписку, освободите объект подписки.

Обработчик "Сообщение найдено" вызывается при обнаружении находящихся поблизости устройств, публикующих сообщения. Обработчик "Сообщение потеряно" вызывается, когда сообщение больше не наблюдается (устройство вышло за пределы зоны действия или перестало публиковать сообщение).

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
    }];

Быстрый

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
    })

Средства для открытия

По умолчанию для обнаружения ближайших устройств будут использоваться оба канала связи (аудио и Bluetooth), при этом оба канала будут осуществлять передачу и сканирование. В некоторых случаях необходимо добавить следующие записи в Info.plist вашего приложения:

  • Если ваше приложение использует аудиосканирование, добавьте строку NSMicrophoneUsageDescription , описывающую причину использования микрофона. Например, "Микрофон прослушивает анонимные токены от находящихся поблизости устройств".

  • Если ваше приложение использует BLE для передачи данных, добавьте строку NSBluetoothPeripheralUsageDescription , описывающую причину передачи данных по BLE. Например: «Анонимный токен передается по Bluetooth для обнаружения находящихся поблизости устройств».

В некоторых случаях вашему приложению может потребоваться использовать только один из каналов связи, и ему может не понадобиться одновременно осуществлять трансляцию и сканирование на этом канале.

Например, приложению, предназначенному для подключения к телеприставке, передающей аудиосигнал, достаточно выполнить сканирование аудиоканала, чтобы обнаружить её. Следующий фрагмент кода показывает, как отправить сообщение на эту телеприставку, используя только сканирование аудиоканала для обнаружения:

Objective-C

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

Быстрый

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
      })
    })

Включение отладочного логирования

Отладочные записи выводят в консоль важные внутренние события, которые могут быть полезны для выявления проблем, возникающих при интеграции Nearby Messages в ваше приложение. Мы запросим эти записи, если вы обратитесь к нам за технической поддержкой.

Эту функцию следует включить перед созданием менеджера сообщений. В этом фрагменте кода показано, как включить отладочное логирование:

Objective-C

[GNSMessageManager setDebugLoggingEnabled:YES];

Быстрый

GNSMessageManager.setDebugLoggingEnabled(true)

Отслеживание состояния разрешения "Рядом"

Для включения обнаружения устройств требуется согласие пользователя. Это указывается состоянием разрешения Nearby. При первом вызове для создания публикации или подписки пользователю отображается диалоговое окно согласия. Если пользователь не дает согласия, обнаружение устройств работать не будет. В этом случае ваше приложение должно показать сообщение, напоминающее пользователю о том, что обнаружение устройств отключено. Состояние разрешения хранится в NSUserDefaults .

Следующий фрагмент кода демонстрирует подписку на состояние разрешений. Обработчик изменения состояния разрешений вызывается всякий раз, когда состояние изменяется, и он не вызывается в первый раз, пока пользователь не предоставит или не отклонит разрешение. Освободите объект разрешения, чтобы прекратить подписку.

Objective-C

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

Быстрый

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

Ваше приложение может предоставить пользователю возможность изменять состояние разрешений; например, с помощью переключателя на странице настроек.

Вот пример того, как получить и установить состояние разрешений.

Objective-C

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

Быстрый

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

Отслеживание настроек пользователя, влияющих на работу приложения Nearby.

Если пользователь запретил использование микрофона, Bluetooth или отключил Bluetooth, функция Nearby также не будет работать или может не работать вовсе. В таких случаях ваше приложение должно отображать сообщение, предупреждающее пользователя о том, что работа Nearby затруднена. Следующий фрагмент кода показывает, как отслеживать состояние этих пользовательских настроек, передавая обработчики при создании менеджера сообщений:

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
         };
}];

Быстрый

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
      }
    })

Отмена диалогового окна разрешения "Рядом"

В зависимости от параметров, передаваемых в ваши публикации и подписки, iOS может запрашивать различные разрешения, прежде чем разрешить работу Nearby. Например, стратегия по умолчанию прослушивает данные, передаваемые в ближнем ультразвуковом диапазоне, поэтому iOS запросит разрешение на использование микрофона. В таких случаях Nearby покажет диалоговое окно «предварительного запроса», объясняющее, почему пользователю предлагается дать разрешение.

Если вы хотите добавить пользовательское диалоговое окно предварительного запроса, установите параметр permissionRequestHandler в значение пользовательского блока в параметрах публикации или подписки. Ваш пользовательский блок должен вызывать блок permissionHandler после того, как пользователь ответит. Следующий фрагмент кода показывает, как это сделать для публикации:

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.
                                 };
                               }];

Быстрый

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.
          }
        })

Фоновая операция

Публикации и подписки, использующие BLE для обнаружения устройств, могут работать в фоновом режиме. Вот несколько моментов, которые следует учитывать при выборе фонового режима:

  • Для фоновых операций необходимо использовать только протокол BLE; воспроизведение звука не поддерживается.
  • Фоновый режим BLE влечет за собой дополнительные затраты заряда батареи. Затраты невелики, но перед принятием решения об использовании фонового режима следует их оценить.
  • iOS запросит у пользователя разрешение на показ рекламы через BLE в фоновом режиме.

Чтобы добавить фоновый режим к публикации или подписке, выполните следующие дополнительные действия:

  • Включите фоновый режим и использование только BLE в вашей публикации или подписке, передав правильно настроенный объект GNSStrategy . Следующий фрагмент кода показывает, как это сделать для подписки:

    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;
          }];
        }];
    

    Быстрый

    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
          })
        })
    

  • Добавьте следующие записи в Info.plist вашего приложения:

    • Записи UIBackgroundModes :

      • bluetooth-central — для сканирования BLE в фоновом режиме. Необходим только тогда, когда режим обнаружения включает сканирование; по умолчанию он его включает.
      • bluetooth-peripheral — периферийное устройство для BLE-рекламы в фоновом режиме. Необходимо только в том случае, если режим обнаружения включает широковещательную рассылку; по умолчанию она включена.
    • NSBluetoothPeripheralUsageDescription строка, описывающая причину использования BLE для передачи данных. Например: «Анонимный токен передается через Bluetooth для обнаружения находящихся поблизости устройств». Подробности см. в документации Apple .

  • Ваше приложение может быть в любой момент закрыто системой, пока оно находится в фоновом режиме. Если фоновый режим — это параметр, который пользователь может включить или выключить, ваше приложение должно выполнять следующие действия:

    • Значение режима фоновой работы всегда сохраняется в переменной NSUserDefaults при каждом изменении пользователем этого параметра.
    • При запуске считать данные из NSUserDefaults и восстановить публикации и/или подписки Nearby, если включен фоновый режим.

Фоновые уведомления

Если вы хотите, чтобы ваше приложение уведомляло пользователя о получении сообщения по подписке в фоновом режиме, вы можете использовать локальные уведомления .

Чтобы добавить их в приложение, выполните следующие действия:

  • Зарегистрируйтесь для получения локальных уведомлений о запуске:

    Objective-C

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

    Быстрый

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

  • Отправьте локальное уведомление в обработчике сообщения "message-found" вашей подписки:

    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...
      };
    

    Быстрый

    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...
    }