【问题标题】:Why beacons cause Bluetooth to continuously toggle?为什么信标会导致蓝牙不断切换?
【发布时间】:2015-07-10 10:52:08
【问题描述】:

我在使用 iOS 和 iBeacon 时遇到了一个非常奇怪的错误。我有一个非常简单的BeaconManager,它对具有特定 UUID、主要和次要值的信标进行范围划分,并在找到它们后执行一些操作。我的应用程序似乎可以正常工作,直到它不断切换蓝牙状态并停止工作。唯一可见的结果是由于蓝牙停止和重新启动,状态栏中的蓝牙图标开始闪烁。

关注点在哪里?

这是我的类定义:

#import "BeaconManager.h"

@implementation BeaconManager

- (instancetype)init {
    self = [super init];
    if (self) {
        NSURL *beep = [[NSBundle mainBundle] URLForResource:@"beep" withExtension:@"aiff"];
        soundFileURLRef = (CFURLRef) CFBridgingRetain(beep);
        AudioServicesCreateSystemSoundID(soundFileURLRef, &soundFileObject);

        // Initializes properties
        beacon = [CLBeacon new];
        foundBeacons = [NSMutableArray new];
        _lastBeaconActionTimes = [[NSMutableDictionary alloc] init];
    }
    return self;
}

- (void)initRegion {
    // Initializes the beacon region by giving it an UUID and an identifier
    NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:BEACON];
    beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:@"beacon.region"];
    // Starts looking for beacon within the region
    [self.locationManager startMonitoringForRegion:beaconRegion];
}

- (void)checkBeacon {
    if (!self.locationManager) {
        self.locationManager = [[CLLocationManager alloc] init];
        self.locationManager.delegate = self;

        if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)])
            [self.locationManager requestWhenInUseAuthorization];
    }
    [self initRegion];
    [self locationManager:self.locationManager didStartMonitoringForRegion:beaconRegion];
}

#pragma mark - CLLocationManagerDelegate

- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {
    [self.locationManager startMonitoringForRegion:beaconRegion];
    [self.locationManager startRangingBeaconsInRegion:beaconRegion];
}

- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
    [self.locationManager startRangingBeaconsInRegion:beaconRegion];
}

- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
    [self.locationManager stopRangingBeaconsInRegion:beaconRegion];
}

- (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error {
    NSLog(@"Failed monitoring region: %@", error);
}

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
    NSLog(@"Location manager failed: %@", error);
}

- (void)locationManager:(CLLocationManager *)manager
        didRangeBeacons:(NSArray *)beacons
               inRegion:(CLBeaconRegion *)region {

    if (foundBeacons.count == 0) {
        for (CLBeacon *filterBeacon in beacons) {
            // If a beacon is located near the device and its major value is equal to 1000 (MAJOR constant)
            if (((filterBeacon.proximity == CLProximityImmediate) || (filterBeacon.proximity == CLProximityNear)))
                // Registers the beacon to the list of found beacons
                [foundBeacons addObject:filterBeacon];
        }
    }
    // Did some beacon get found?
    if (foundBeacons.count > 0) {
        // Takes first beacon of the list
        beacon = [foundBeacons firstObject];

        if (([beacon.major isEqualToNumber:[NSNumber numberWithInt:MAJOR]]) && ([beacon.minor isEqualToNumber:[NSNumber numberWithInt:MINOR]])) {
            // Takes the actual date and time
            NSDate *now = [[NSDate alloc] init];
            NSString *key = [NSString stringWithFormat:@"%@ %@ %@", [beacon.proximityUUID UUIDString], beacon.major, beacon.minor];
            NSDate *lastBeaconActionTime = [_lastBeaconActionTimes objectForKey:key];
            if ((lastBeaconActionTime == nil) || ([now timeIntervalSinceDate:lastBeaconActionTime] > MINIMUM_ACTION_INTERVAL_SECONDS)) {
                [_lastBeaconActionTimes setObject:now forKey:key];
                // Plays beep sound
                AudioServicesPlaySystemSound(soundFileObject);

                if (self.delegate) {
                    // Performs actions related to the beacon (i.e. delivers a coupon)
                    [self.delegate didFoundBeacon:self];
                }
                self.locationManager = nil;
            }
            // else [self.locationManager stopMonitoringForRegion:region];
        }
        [foundBeacons removeObjectAtIndex:0];
        beacon = nil;
    }
}
@end

【问题讨论】:

  • 那是什么设备?您是否连接到任何蓝牙外围设备(例如,智能手表或蓝牙耳机)?当您说图标闪烁时,您的意思是它正在改变颜色,还是它不断出现和消失?
  • @heypiotr 这是一部装有 iOS 8.3 的 iPhone 6,它没有连接到任何其他蓝牙设备。我还对应用程序进行了干净的构建以避免干扰。蓝牙图标不断出现和消失的速度非常快。
  • 您是否有机会在另一台设备上测试您的应用程序并查看是否相同?这看起来有点像可能的硬件问题。您使用的是 Core Location 还是其他信标 SDK?
  • @heypiotr 好吧,我不确定这是否是硬件问题,因为该错误也发生在装有 iOS 7.1.1 的 iPhone 4S 上。顺便说一句,我正在使用核心位置。
  • 您是否在反复启动/停止测距?您是否正在执行任何其他与位置相关的启动/停止行为?由于它发生在多个设备上,因此在我看来,您在响应测距和/或状态方面让设备感到困惑(或者可能完全按照您的代码编写的用途,尽管可能不是为 ;-) 设计的)变化。如果您想发布代码,请包括您如何设置您的区域、任何开始/停止代码、任何状态更改处理程序(包括身份验证和/或硬件)。

标签: ios bluetooth ibeacon


【解决方案1】:

不能肯定这就是蓝牙不断切换的原因,但这部分肯定是可疑的:

- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {
    [self.locationManager startMonitoringForRegion:beaconRegion];
    [self.locationManager startRangingBeaconsInRegion:beaconRegion];
}

这本质上是一个无限循环。一旦监控开始,iOS 就会调用didStartMonitoring 方法……它开始监控同一个区域,这使得iOS 再次调用didStartMonitoring 方法,这……

我将从您的这部分代码中删除 startMonitoringForRegion 行开始。

【讨论】:

  • 好的,现在它的行为似乎更稳定了。无论如何,如果我不立即关闭与didFoundBeacon: 方法关联的视图控制器,蓝牙仍然会快速切换一次。视图控制器只显示一个带有模态序列的标签和一个关闭视图控制器的按钮。出于测试目的,警报每 60 秒显示一次,所以如果我在计时器用完之前不关闭它,视图控制器就会堆栈。对于实际使用,计时器长度应该更长(大约 30 分钟)。会不会是相关问题?
  • 感谢您的帮助,非常感谢。
猜你喜欢
  • 2023-01-14
  • 2011-01-14
  • 2013-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多