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

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

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

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

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

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

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

Цель-C

#import <GNSMessages.h>

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

Быстрый

let messageManager = GNSMessageManager(APIKey: "API_KEY")

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

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

Цель-C

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

Быстрый

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

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

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

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

Цель-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 для обнаружения ближайших устройств».

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

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

Цель-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
      })
    })

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

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

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

Цель-C

[GNSMessageManager setDebugLoggingEnabled:YES];

Быстрый

GNSMessageManager.setDebugLoggingEnabled(true)

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

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

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

Цель-C

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

Быстрый

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

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

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

Цель-C

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

Быстрый

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

Отслеживание пользовательских настроек, влияющих на функцию «Рядом».

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

Цель-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 может запрашивать различные разрешения, прежде чем разрешить работу функции «Рядом». Например, стратегия по умолчанию прослушивает данные, передаваемые в режиме, близком к ультразвуку, поэтому iOS запросит разрешение на использование микрофона. В этих случаях Nearby отобразит «предварительный» диалог, в котором объясняется, почему пользователя просят дать разрешение.

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

Цель-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 . В следующем фрагменте показано, как это сделать для подписки:

    Цель-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 и восстановите близлежащие публикации и/или подписки, если включен фоновый режим.

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

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

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

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

    Цель-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))
    

  • Отправьте локальное уведомление в обработчике найденных сообщений вашей подписки:

    Цель-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...
    }