1.iBeacon简介

iBeacon是苹果公司2013年9月发布的移动设备用OS(iOS7)上装备的新功用。其作业办法是,装备有 低功耗蓝牙(BLE)通信功用的设备运用BLE技能向周围发送自己特有的ID,接纳到该ID的应用软件会依据该ID采取一些举动。比如,在店肆里设置iBeacon通信模块的话,便可让iPhone和iPad上运行一资讯告知服务器,或者由服务器向顾客发送扣头券及进店积分。此外,还能够在家电发生故障或中止作业时运用iBeacon向应用软件发送资讯。

2.iBeacon权限相关

在Signing & Capabilities 中增加 Background Modes 然后再勾选以下选项

iOS制作iBeacon相关SDK,在程序杀死后无法收到本地通知
在info.plist中增加相应的权限

iOS制作iBeacon相关SDK,在程序杀死后无法收到本地通知

3.iBeacon相关代码完成

在自己的类中增加以下代码

@property (retain, nonatomic) CLLocationManager *locationManager;

创立 CLLocationManager

self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.activityType = CLActivityTypeFitness;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.distanceFilter = 100;
if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0){
  [self.locationManager requestAlwaysAuthorization];
}
// 答应后台获取用户方位(iOS9.0)
if([[UIDevice currentDevice].systemVersion floatValue] >= 9.0) {
// 一定要勾选后台模式 location updates 否者程序奔溃  
 self.locationManager.allowsBackgroundLocationUpdates = YES;
}
self.locationManager.pausesLocationUpdatesAutomatically = NO;
[self.locationManager startUpdatingLocation];

创立CLBeaconRegion目标

CLBeaconRegion *region = [[CLBeaconRegion alloc] initWithProximityUUID:[[NSUUID alloc] initWithUUIDString:@"xxxx"] major:1 minor:2 identifier:@"SomeIdentifier"];
region.notifyEntryStateOnDisplay = YES;
region.notifyOnEntry = YES;
region.notifyOnExit = YES;
[self.locationManager startMonitoringForRegion:region];

iBeacon接纳者供给了两种办法来接纳iBeacon信号

Monitoring: 能够用来在设备进入/退出某个地舆区域时取得告诉, 运用这种办法能够在应用程序的后台运行时检测iBeacon,但是只能同时检测20个region区域,而且不能够估测设备与iBeacon的间隔,程序kill后也能够监听。

// 开端检测区域
[self.locationManager startMonitoringForRegion:beaconRegion]; 
// 中止检测区域
[self.locationManager stopMonitoringForRegion:beaconRegion]; 
// Monitoring成功对应回调函数
- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region;
//设备状况改动回调
- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(nonnull CLRegion *)region;
// 设备进入该区域时的回调
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region;
// 设备退出该区域时的回调
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region;
// Monitoring有错误发生时的回调
- (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(nullable CLRegion *)region withError:(NSError *)error;

Ranging: iOS 7之后供给的 API, 用于确认设备的近似间隔iBeacon 技能,能够用来检测某区域内的一切iBeacons,而且能够精度估量发射者与接纳者的间隔。

// 开端检测区域
[self.locationManager startRangingBeaconsInRegion:beaconRegion];
// 中止检测区域
[self.locationManager stopRangingBeaconsInRegion:beaconRegion];
// Ranging成功对应回调函数  1秒钟履行1次
- (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray<CLBeacon *> *)beacons inRegion:(CLBeaconRegion *)region 
// Ranging有错误发生时的回调
- (void)locationManager:(CLLocationManager *)manager rangingBeaconsDidFailForRegion:(CLBeaconRegion *)region withError:(NSError *)error

咱们要完成后台监听和app被kill掉也能监听就需求运用 Monitoring 办法 以下这3个办法是在后台或者app被kill掉也能回调

//设备状况改动回调
- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(nonnull CLRegion *)region;
// 设备进入该区域时的回调
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region;
// 设备退出该区域时的回调
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region;

给app增加本地告诉

UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
// 标题
content.title = @"发现beacon设备";
content.subtitle = @"";
// 内容
content.body = @"";
// 默许声响
//content.sound = [UNNotificationSound defaultSound];
// 增加自定义声响
content.sound = [UNNotificationSound soundNamed:@"Alert_ActivityGoalAttained_Salient_Haptic.caf"];
// 角标 (我这里测验的角标无效,暂时没找到原因)
content.badge = @1;
// 多少秒后发送,能够将固定的日期转化为时刻
NSTimeInterval time = [[NSDate dateWithTimeIntervalSinceNow:2] timeIntervalSinceNow];
//NSTimeInterval time = 10;
// repeats,是否重复,假如重复的话时刻必须大于60s,要不会报错
UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:time repeats:NO];
// 增加告诉的标识符,能够用于移除,更新等操作
NSString *identifier = @"noticeId";
// 告诉恳求
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifier content:content trigger:trigger];
//增加告诉
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
    NSLog(@"error:%@",error);
}];

然后把本地告诉写在Monitoring的3个办法里边,就能够做到后台和kill后都能够监听得到了。

4.iBeacon代码处于SDK怎么完成后台和kill之后的监听

假如你是把iBeacon相关代码封装成SDK(Frameworks),你会发现以上代码完成之后是无法在程序kill之后收到本地告诉的,为什么呢?分明写在Demo里边是能够的,下面咱们来看下怎么解决?

iBeacon相关SDK:

一般咱们制造SDK(Frameworks 静态库)都是暴露一些办法出来供他人运用,内部完成是无法看到的,像有 init , startAction, stopAction ,releseAction办法等等,一般init办法会在AppDelegate中初始化,其他办法都是在特定的时机触发和运用。

当前APP处于kill状况下(彻底退出)。扫描的办法就必须在AppDelegatedidFinishLaunchingWithOptions中完成,不然就无法在kill的状况下收到本地告诉内容。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // 开端检测区域
    [self.locationManager startMonitoringForRegion:beaconRegion];
}

既然是这样那咱们直接把扫描写在这里不就能够了,一般咱们都是在这里进行初始化SDK,后续的开端扫描作业都需求依据各自的事务去进行发动的,但是又必须在这里边完成startMonitoringForRegion办法,所以针对SDK完成iBeacon的办法,我加了一个监听处理。

1.在SDK的Manager中增加代理

备注: IBeaconManager 是自己SDK暴露出去的管理器目标,每个人的不一样。

@protocol BeaconRegionDelegate <NSObject>
/** 进入区域
* @param manager 管理器
* @param region 区域
*/
- (void)beaconManager:(IBeaconManager *)manager
       didEnterRegion:(CLRegion *)region;
/** 退出区域
* @param manager 管理器
* @param region 区域
*/
- (void)beaconManager:(IBeaconManager *)manager
        didExitRegion:(CLRegion *)region;
/** 状况改动
* @param manager 管理器
* @param state 区域状况
* @param region 区域
*/        
- (void)beaconManager:(IBeaconManager *)manager
    didDetermineState:(CLRegionState)state
            forRegion:(CLRegion *)region;
@end

IBeaconManager.h类中增加以下办法,把需求监听的目标传进来

/// 增加代理属性
@property (nonatomic, weak) id<BeaconRegionDelegate> delegate;
/* 用于初始化接纳后台区域监听回调类,此函数以及handler实体类都必须是与AppDelegate伴随发动,不然无法接纳到后台beacon推送
 * @param handler 用于接纳后台区域监听回调函数的类。传入的handler类用作接纳回调(该类必须随程序的发动即初始化,不然无法接纳到回调,默许handler为AppDelegate)
 */
- (void)regionHandler:(id<BeaconRegionDelegate>)handler;

IBeaconManager.m中完成regionHandler办法

- (void)regionHandler:(id<BeaconRegionDelegate>)handler {
    self.delegate = handler;
    //开启扫描
    /*
    主张创立一个暂时的beaconRegion来运用,运用后立马调用stopMonitoringForRegion办法封闭,
    毕竟仅仅为了让程序初始化时分能呼应扫描区域而已,然后在3个呼应办法中做identifier比照剔除,假如是自己暂时创立的beaconRegion的identifier就能够return了,不呼应本地告诉。
    */
    [self.locationManager startMonitoringForRegion:beaconRegion];
    [self.locationManager stopMonitoringForRegion:beaconRegion];
}

2.在SDK里边的CLLocationManagerDelegate办法回传状况

- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(nonnull CLRegion *)region {
    if([region.identifier isEqualToString:beaconRegion.identifier]) {
        return;
    }
    if (self.delegate && [self.delegate respondsToSelector:@selector(beaconManager:didDetermineState:forRegion:)]) {
    [self.delegate beaconManager:self didDetermineState:state forRegion:region];
  }
}
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
    if([region.identifier isEqualToString:beaconRegion.identifier]) {
        return;
    }
    if (self.delegate && [self.delegate respondsToSelector:@selector(beaconManager:didEnterRegion:)]) {
        [self.delegate beaconManager:self didEnterRegion:region];
    }
}
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
    if([region.identifier isEqualToString:beaconRegion.identifier]) {
        return;
    }
    if (self.delegate && [self.delegate respondsToSelector:@selector(beaconManager:didExitRegion:)]) {
    [self.delegate beaconManager:self didExitRegion:region];
  }
}

regionHandler假如你传的是AppDelegate进来,那你在AppDelegate完成BeaconRegionDelegate办法即可。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [[IBeaconManager manager] regionHandler:self];
}

依照以上办法就能够完成SDK运用IBeacon程序在后台或者被kill之后也能获取本地告诉了。

至于为什么直接在demo中实iBeacon能够收到本地告诉,而在SDK中完成就无法收到本地告诉原因。

个人猜想如下:

SDK是一个的单独的模块,是引进进app中运用的属所以外部关联,所以需求在程序初始化的时分开启扫描,直接在app中完成iBeacon操作是直接作用于这个应用傍边的,所以不需求在程序初始化的时分扫描后续其他地方触发也是能够收到系统监听。

由所以第一次研究iBeacon,以上属于个人的想法,假如有大神有愈加专业的解释和更好的办法欢迎谈论交流。