iBeacon的使用

听说可以通过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;
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,911评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,014评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,129评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,283评论 1 264
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,159评论 4 357
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,161评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,565评论 3 382
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,251评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,531评论 1 292
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,619评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,383评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,255评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,624评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,916评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,199评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,553评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,756评论 2 335