iBeacon的使用

听说可以通过iBeacon激活IOS App,便研究了一下。

一、基本原理

iBeacon一般用于外设的,外设加入了iBeacon后,就会不断广播一定范围的信号。如果App加入了iBeacon的监听,那么如果App进入了外设的广播范围,那么App里面的iBeacon回调就会有反应,也是通过这种方法激活被挂起的App。因为我没有嵌入了iBeacon的外设,这里我是通过把mac改造成iBeacon外设,网上有个mac平台的软件:
https://github.com/timd/MactsAsBeacon
这软件界面如下:

iBeacon的使用_第1张图片
image.png

然后,看到这个界面你知道App怎么初始化iBeacon了吧:

NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:IBEACON_UUID];
_beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid major:2 minor:1000 identifier:[[NSBundle mainBundle] bundleIdentifier]];

二、IOS端IBeacon的开发

iBeacon的使用是基于蓝牙和定位的,所以我这里使用了权限:(网上都说是需要基于蓝牙的,但我测试过程中,把蓝牙关闭了,也是可以的,但我还是加入了蓝牙的权限)

Location Always and When In Use Usage Description
Bluetooth Peripheral Usage Description




    bluetooth-peripheral
    location


App的代码部分:

@property(nonatomic) CLLocationManager *locationManager;
@property(nonatomic) CLBeaconRegion *beaconRegion;

- (CLLocationManager *)locationManager{
    if(!_locationManager){
        
        _locationManager = [[CLLocationManager alloc] init];
        _locationManager.distanceFilter = 1.0f; //kCLDistanceFilterNone
        _locationManager.delegate = self;
        //控制定位精度,越高耗电量越
//        _locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
    }
    
    return _locationManager;
}

- (CLBeaconRegion *)beaconRegion{
    if(!_beaconRegion){
        
        NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:IBEACON_UUID];
//        _beaconRegion = [[CLBeaconRegion alloc]initWithProximityUUID:uuid identifier: [[NSBundle mainBundle] bundleIdentifier]];
        _beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid major:2 minor:1000 identifier:[[NSBundle mainBundle] bundleIdentifier]];
        _beaconRegion.notifyOnExit = YES;
        _beaconRegion.notifyOnEntry = YES;
        _beaconRegion.notifyEntryStateOnDisplay = YES;
    
    }
    
    return _beaconRegion;
}

//申请定位权限并且开启iBeacon监听
- (void)startLocation{
    
    CLAuthorizationStatus state = [CLLocationManager authorizationStatus];
    if(state == kCLAuthorizationStatusNotDetermined){
        
        if([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]){
            [self.locationManager requestAlwaysAuthorization];
        }
    }
    if(state == kCLAuthorizationStatusDenied){
        NSString *message = @"您的手机目前未开启定位服务,如欲开启定位服务,请至设定开启定位服务功能";
        UIAlertController * ac = [UIAlertController alertControllerWithTitle:@"Tip" message:message preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction * action1 = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            ;
        }];
        
        [ac addAction:action1];
        [self presentViewController:ac animated:YES completion:nil];
        return;
    }
    if(state == kCLAuthorizationStatusRestricted){
        NSString *message = @"定位权限被限制";
        UIAlertController * ac = [UIAlertController alertControllerWithTitle:@"Tip" message:message preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction * action1 = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            ;
        }];
        
        [ac addAction:action1];
        [self presentViewController:ac animated:YES completion:nil];
        return;
    }
    
    if( [CLLocationManager isMonitoringAvailableForClass:[self.beaconRegion class]] ) {
        //开始定位
        [self.locationManager startMonitoringForRegion:self.beaconRegion];
    }
    
    if (_beaconRegion && [CLLocationManager isRangingAvailable]) {
        NSLog(@"startRangingBeaconsInRegion");
        //开启监听
        [_locationManager startRangingBeaconsInRegion:_beaconRegion];
    }
}

iBeacon的各种回调:

// delegate
- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region{
    _errorLab.text = @"didStartMonitoringForRegion";
    WLlog(@"didStartMonitoringForRegion");
}
// 设备进入该区域时的回调
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region{
    //App在后台才会执行
    self.view.backgroundColor = [UIColor redColor];
    _errorLab.text = @"didEnterRegion";
    WLlog(@"didEnterRegion");
}
// 设备退出该区域时的回调
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region{
    //App在后台才会执行
    self.view.backgroundColor = [UIColor blackColor];
    _errorLab.text = @"didExitRegion";
    WLlog(@"didExitRegion");
}
// 有错误产生时的回调
- (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(nullable CLRegion *)region withError:(NSError *)error{
    _errorLab.text = @"monitoringDidFailForRegion";
}

- (void)locationManager:(CLLocationManager *)manager
        didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region{
    NSString *proximity = @"unKnow";
    CLBeacon *beacon = [beacons firstObject];
    switch (beacon.proximity) {
        case CLProximityImmediate:
        {
//            NSLog(@"very close");
            proximity = @"very close";
        }
            break;
        case CLProximityNear:
        {
//            NSLog(@"near");
            proximity = @"near";
        }
            break;
        case CLProximityFar:
        {
//            NSLog(@"far");
            proximity = @"far";
        }
            break;
            
        default:
        {
            NSLog(@"unKnow");
        }
            break;
    }
    proximity = [NSString stringWithFormat:@"%@\n%f meter\nrssi:%zi",proximity,beacon.accuracy,beacon.rssi];
    
    _textLab.text = proximity;
    
//    NSLog(@">>>>%f meter  rssi:%zi",beacon.accuracy,beacon.rssi);
}

- (void)locationManager:(CLLocationManager *)manager
      didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region API_AVAILABLE(ios(7.0), macos(10.10)) API_UNAVAILABLE(watchos, tvos){

    //第一次运行的时候,会走这里,之后App在前台的情况下,这里就算状态发送改变了,也没有执行。App在后台才会执行
    NSString *msg = @"didDetermineState";
    
    if(state == CLRegionStateInside){
        msg = @"Inside";
        [[LocalNotifyManager sharedInstanced] pushLocalNotification:@"Tip" alertBody:msg flag:@"test" infoDic:nil];
        [self checkAppLiveTime];
    }
    if(state == CLRegionStateOutside){
        msg = @"Outside";
        [[LocalNotifyManager sharedInstanced] pushLocalNotification:@"Tip" alertBody:msg flag:@"test" infoDic:nil];
        [self checkAppLiveTime];
    }
    
    _errorLab.text = msg;
    WLlog(msg);
}

很多人说didEnterRegion和didExitRegion都没有执行,我测试过了,只有App进入到后台时候,这两个方法才有机会执行。

三、App后台被激活的时间

我使用了通知来测试后台的激活。App进入到后台了,通知被激活了,说明App确实被激活了。
我接着测试了App被激活的时间:

- (void)checkAppLiveTime{
    //经过测试,每次App可有10秒左右的激活时间,加上starBGTask后,可以存活几分钟
//    [self starBGTask];
    if(_liveTimer){
        [_liveTimer invalidate];
        _liveTimer = nil;
    }
    
    _liveTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeAction) userInfo:nil repeats:YES];
}

通过定时器,每秒写入内容到文件中。测试的结论是,激活时间大概10秒左右。当然可以通过设置后台任务让时间延长一点,代码如下:

- (void)starBGTask {
    if (_bgTask == UIBackgroundTaskInvalid) {
        UIApplication *app = [UIApplication sharedApplication];
        __block UIBackgroundTaskIdentifier bgTask;
        bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
            NSLog(@"EndBackgroundTask");
            bgTask = UIBackgroundTaskInvalid;
        }];
        _bgTask = bgTask;
    }
}

你可能感兴趣的:(iBeacon的使用)