iBeacon的使用

作者: Johnny_Wu | 来源:发表于2018-12-24 10:53 被阅读0次

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

    一、基本原理

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

    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
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <array>
        <string>bluetooth-peripheral</string>
        <string>location</string>
    </array>
    </plist>
    

    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<CLBeacon *> *)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的使用

        本文链接:https://www.haomeiwen.com/subject/iaeakqtx.html