Nearby Messages API 是一种发布-订阅型 API,可让附近的设备交换少量数据载荷。设备发布消息后,附近的设备便可接收该消息。为保持良好的性能,消息大小应保持在较小的范围内。此服务不适用于交换照片和视频等较大对象。
附近设备集由通过蓝牙和近超声波(听不见)音频交换的小令牌确定。当设备检测到来自附近设备的令牌时,它会将令牌发送到 Nearby Messages 服务器以验证令牌,并检查是否有任何消息要为应用当前订阅集传送。
应用可以控制用于设备发现的媒介集,以及媒介是否用于广播令牌和/或扫描令牌。默认情况下,广播和扫描是在所有媒介上完成的。如需在部分媒介上进行发现,并控制是否广播或扫描,您必须在创建发布和订阅时传递其他参数。
此库可在 iOS 7 及更高版本上运行,并使用 iOS 8 SDK 构建。
创建消息管理器
此代码会创建一个消息管理器对象,让您可以发布和订阅。消息交换未经身份验证,因此您必须提供适用于 iOS 的公共 API 密钥。您可以使用项目的 Google Developers Console 条目创建一个。
Objective-C
#import <GNSMessages.h>
GNSMessageManager *messageManager =
[[GNSMessageManager alloc] initWithAPIKey:@"API_KEY"];
Swift
let messageManager = GNSMessageManager(APIKey: "API_KEY")
发布消息
此代码段演示了如何发布包含名称的消息。 只要发布对象存在,发布就会处于有效状态。如需停止发布,请释放发布对象。
Objective-C
id<GNSPublication> publication =
[messageManager publicationWithMessage:[GNSMessage messageWithContent:[name dataUsingEncoding:NSUTF8StringEncoding]]];
Swift
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
}];
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
})
发现媒介
默认情况下,系统会使用音频和蓝牙这两种媒介来发现附近的设备,并且这两种媒介都会广播和扫描。 在某些情况下,您需要将以下条目添加到应用的
Info.plist 中:
如果您的应用使用音频进行扫描,请添加
NSMicrophoneUsageDescription,这是一个字符串,用于描述您将使用麦克风的原因。 例如,“麦克风会监听来自附近设备的匿名令牌。”如果您的应用使用 BLE 进行广播,请添加
NSBluetoothPeripheralUsageDescription,这是一个字符串,用于描述您将在 BLE 上进行广播的原因。例如,“系统会通过蓝牙广播匿名令牌,以发现附近的设备。”
在某些情况下,您的应用可能只需要使用其中一种媒介,并且可能不需要在该媒介上同时进行广播和扫描。
例如,一款旨在连接到仅通过音频广播的机顶盒的应用只需要通过音频进行扫描即可发现该机顶盒。以下代码段展示了如何仅使用音频扫描进行发现,以向该机顶盒发布消息:
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
})
})
启用调试日志记录
调试日志记录会将重要的内部事件输出到控制台,这有助于跟踪您在将 Nearby Messages 集成到应用时可能遇到的问题。如果您与我们联系以寻求 技术支持,我们会要求您提供这些日志。
您应在创建消息管理器之前启用调试日志记录。 以下代码段展示了如何启用调试日志记录:
Objective-C
[GNSMessageManager setDebugLoggingEnabled:YES];
Swift
GNSMessageManager.setDebugLoggingEnabled(true)
跟踪 Nearby 权限状态
需要征得用户同意才能启用设备发现。这由 Nearby
权限状态表示。首次调用以创建发布内容或订阅时,系统会向用户显示意见征求对话框。如果用户不同意,设备发现将无法正常运行。在这种情况下,您的应用应显示一条消息,提醒用户设备发现已停用。权限状态存储在
NSUserDefaults 中。
以下代码段演示了如何订阅权限状态。 每当状态发生变化时,系统都会调用权限状态更改处理程序,并且在用户授予或拒绝权限之前,系统不会首次调用该处理程序。 释放权限对象以停止订阅。
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
})
您的应用可以提供一种方式,让用户可以更改权限状态;例如,在设置页面上使用切换开关。
下面是一个关于如何获取和设置权限状态的示例。
Objective-C
BOOL permissionState = [GNSPermission isGranted];
[GNSPermission setGranted:!permissionState]; // toggle the state
Swift
let permissionState = GNSPermission.isGranted()
GNSPermission.setGranted(!permissionState) // toggle the state
跟踪影响 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
};
}];
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
}
})
替换 Nearby 权限对话框
根据您传递到发布和订阅中的参数,iOS 可能会要求您授予各种权限,然后才允许“附近分享”正常运行。例如,默认策略会监听通过近超声波音频传输的数据,因此 iOS 会要求您授予使用麦克风的权限。在这种情况下,附近分享会显示一个“预检”对话框,说明系统要求用户授予权限的原因。
如果您想提供自定义“预检”对话框,请在发布或订阅参数中将 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.
};
}];
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.
}
})
后台操作
使用 BLE 进行设备发现的发布和订阅可以在后台运行。在决定使用后台模式时,您应注意以下事项:
- 后台操作必须仅使用 BLE 媒介;不支持音频。
- 后台 BLE 会增加电池消耗。 消耗量很低,但您应先进行精准衡量,然后再决定是否使用后台模式。
- iOS 会要求用户授予通过 BLE 在后台投放广告的权限。
如需向发布或订阅添加后台模式,请执行以下额外步骤:
通过传入正确配置的
GNSStrategy对象,在发布内容或订阅中启用后台模式和仅 BLE 模式。以下代码段展示了如何为订阅执行此操作: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 }) })将以下条目添加到应用的
Info.plist中:UIBackgroundModes条目:bluetooth-central,用于在后台进行 BLE 扫描。 仅当发现模式包含扫描时才需要;默认情况下,发现模式包含扫描。bluetooth-peripheral,用于在后台进行 BLE 广告投放。仅当发现模式包含广播时才需要;默认情况下,发现模式包含广播。
NSBluetoothPeripheralUsageDescription字符串,用于描述您将在 BLE 上投放广告的原因。例如,“系统会通过蓝牙广播匿名令牌,以发现附近的设备。” 如需了解详情,请参阅 Apple 文档 。
您的应用可能会在后台随时被系统终止。 如果后台模式是用户可以启用或停用的设置,您的应用应执行以下操作:
- 每当用户更改后台模式值时,都将其保存到
NSUserDefaults。 - 启动时,从
NSUserDefaults中读取该值,并在启用后台模式后恢复 Nearby 发布和/或订阅。
- 每当用户更改后台模式值时,都将其保存到
后台通知
如果您希望应用在订阅在后台收到消息时通知用户,可以使用 本地通知。
请按照以下步骤将其添加到您的应用中:
在启动时注册接收本地通知:
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))在订阅的消息发现处理程序中发送本地通知:
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... }