聊聊 Apple 的 iBeacon 技術(shù)
轉(zhuǎn)自:掘金 阿華12年
https://juejin.cn/post/6995857698747056142
前言
網(wǎng)上查資料說蘋果在13年的WWDC上發(fā)布iOS7上配備的新功能。之前,利用iBeacon設(shè)備做了下定位的算法研究,故此來總結(jié)下,也希望能和大家交流下。
什么是iBeacon
首先,iBeacon 的標志是下面這張圖片

下面進入正題,iBeacon這項技術(shù)是蘋果建立在低功耗藍牙的技術(shù)上做出來的東西。具體來說是利用BLE中名為"通告幀"的廣播幀。
通告幀是由配備BLE的設(shè)備定期發(fā)出,只要是支持BLE的終端,都可以接受到信號。通告幀的有效載荷部分,寫入了蘋果定義的數(shù)據(jù)。
一個iBeacon基站的數(shù)據(jù)大致由四部分信息組成:
1 、UUID(universally unique identifier):一個128位的唯一標識一個或多個Beacon基站為特定類型或特定的組織。 2、 Major:一個16位的無符號整數(shù),可以將具有相同proximity UUID的Beacon基站組織聯(lián)系起來。(用戶可以自定義) 3、 Minor:同上。 4、Measured Power :是iBeacon發(fā)送模塊與接收器之間距離為1米時的信號強度(RSSI)參照值。
通過藍牙低功耗技術(shù)(BLE)發(fā)送特定的識別信息,來確定Beacon基站和設(shè)備之間的相對距離。而這個距離并不是精密推算的,而是將其分為三級:
約10厘米(immediate) 1米以內(nèi)(near) 1米以外(far)
這是因為,發(fā)送和接受設(shè)備之間的距離在1米之內(nèi)時,RSSI值基本是按照理論值減少的,而在1米外,收到發(fā)射波的影響,RSSI不會明顯的隨距離增加減少,而是會上下波動。也就是說,1米外的距離無法非常精密推測,可以用far來概括。
接下來,進入重點:
既然,用一個iBeacon我們可以測出Beacon設(shè)備和掃描Beacon設(shè)備之間的距離(Apple的API中已給出距離值)。那么,猜想下,有三個Beacon,然后知道他們的坐標信息,那么我們拿著手機去不斷的掃描這三個Beacon的RSSI信息就可以利用定位算法來進行定位了。
下面,上代碼
關(guān)于開始定位的部分
在這,我設(shè)置了三個基準點作為坐標點固定,用來探測手持設(shè)備的位置。
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
NSArray *myBeacon = @[UUID_BEACON_O, UUID_BEACON_T, UUID_BEACON_H];
for (NSString *uuid in myBeacon) {
NSString *identifier = @"";
if ([uuid isEqualToString:UUID_BEACON_O]) {
identifier = @"左后";
}else if ([uuid isEqualToString:UUID_BEACON_T]) {
identifier = @"右后";
}else if ([uuid isEqualToString:UUID_BEACON_H]) {
identifier = @"左前";
}
CLBeaconRegion *beacon = [[CLBeaconRegion alloc] initWithProximityUUID:[[NSUUID alloc] initWithUUIDString:uuid]
identifier:identifier];
beacon.notifyOnExit = YES;
beacon.notifyOnEntry = YES;
beacon.notifyEntryStateOnDisplay = YES;
[self.locationManager startMonitoringForRegion:beacon];
[self.locationManager startRangingBeaconsInRegion:beacon];
}
[self.locationManager requestAlwaysAuthorization];
關(guān)于位置的Delegate部分
處理收到的系統(tǒng)發(fā)給的信號, 在這里主要是做了本地消息的推送。在持續(xù)探測信號強度的時候,可以按照最后的參考文章,實現(xiàn)三角定位原理,來實現(xiàn)設(shè)備的定位。
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
if ([region isKindOfClass:[CLBeaconRegion class]]) {
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = [NSString stringWithFormat:@"你已進入到 %@ 范圍內(nèi)", region.identifier];
notification.soundName = @"Default";
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
NSLog(@"%@", [NSString stringWithFormat:@"你已進入到 %@ 范圍內(nèi)", region.identifier]);
}
}
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
if ([region isKindOfClass:[CLBeaconRegion class]]) {
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = [NSString stringWithFormat:@"你已離開 %@ 的范圍", region.identifier];
notification.soundName = @"Default";
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
NSLog(@"%@", [NSString stringWithFormat:@"你已離開 %@ 的范圍", region.identifier]);
}
}
- (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray<CLBeacon *> *)beacons inRegion:(CLBeaconRegion *)region {
for (CLBeacon *beacon in beacons) {
// NSLog(@"beacon Info : rssi is %ld, major is %@, minor is %@, accuracy is %f, proximity is %ld.", beacon.rssi, beacon.major, beacon.minor, beacon.accuracy, beacon.proximity);
if (self.beaconDataSource.count == 3) {
if ([[beacon.proximityUUID UUIDString] isEqualToString:UUID_BEACON_O]) {
[self.beaconDataSource replaceObjectAtIndex:0 withObject:beacon];
[self.wait1 addObject:beacon]; //采集數(shù)據(jù) 左后
}
if ([[beacon.proximityUUID UUIDString]isEqualToString:UUID_BEACON_T]) {
[self.beaconDataSource replaceObjectAtIndex:1 withObject:beacon];
[self.wait2 addObject:beacon]; //采集數(shù)據(jù) 右后
}
if ([[beacon.proximityUUID UUIDString]isEqualToString:UUID_BEACON_H]) {
[self.beaconDataSource replaceObjectAtIndex:2 withObject:beacon];
[self.wait3 addObject:beacon]; //采集數(shù)據(jù) 左前
}
if (!self.testButton.selected) { //測試按鈕沒有選中
//實時刷新位置信息
if (self.wait1.count == 20 && self.wait2.count == 20 && self.wait3.count == 20) {
// NSArray *result = [DealModel dealWithBaseData:@[@[@"0", @"0"], @[@"220", @"0"], @[@"110", @"110"]] andThreeAuxData:@[self.wait1, self.wait2, self.wait3] andReal:@[self.textX.text, self.textY.text]];
DataProcessing *data = [[DataProcessing alloc] init];
NSArray *result2 = [data dealWithBaseData:@[@[@"0", @"0"], @[@"220", @"0"], @[@"110", @"110"]] andThreeAuxData:@[self.wait1, self.wait2, self.wait3] andReal:@[@"",@""]];
self.result1.text = self.result2.text;
self.result2.text = [NSString stringWithFormat:@"X : %@\nY : %@", result2[0], result2[1]];
NSLog(@"%@", data);
// self.xyView.center = CGPointMake([result[0] floatValue], [result[1] floatValue]);
[self.wait1 removeAllObjects];
[self.wait2 removeAllObjects];
[self.wait3 removeAllObjects];
self.sureButton.selected = NO;
self.sureButton.backgroundColor = [UIColor blackColor];
}
}else {
//開始測試單個設(shè)備誤差
if (self.wait1.count == 20) {
if (![self.textX.text isEqualToString:@""])
[DataProcessing testErrorWithUUID:UUID_BEACON_O andRealValue:self.textX.text andTestArray:self.wait1];
[self.wait1 removeAllObjects];
[self.wait2 removeAllObjects];
[self.wait3 removeAllObjects];
}else if (self.wait2.count == 20) {
if (![self.textX.text isEqualToString:@""])
[DataProcessing testErrorWithUUID:UUID_BEACON_T andRealValue:self.textX.text andTestArray:self.wait2];
[self.wait1 removeAllObjects];
[self.wait2 removeAllObjects];
[self.wait3 removeAllObjects];
}else if (self.wait3.count == 20) {
if (![self.textX.text isEqualToString:@""])
[DataProcessing testErrorWithUUID:UUID_BEACON_H andRealValue:self.textX.text andTestArray:self.wait3];
[self.wait1 removeAllObjects];
[self.wait2 removeAllObjects];
[self.wait3 removeAllObjects];
}
}
[self.localView refreshWithArray:self.beaconDataSource];
}else {
if ([[beacon.proximityUUID UUIDString] isEqualToString:UUID_BEACON_O] || [[beacon.proximityUUID UUIDString]isEqualToString:UUID_BEACON_T] || [[beacon.proximityUUID UUIDString]isEqualToString:UUID_BEACON_H]) {
[self.beaconDataSource addObject:beacon];
}
}
}
[self.beaconTableView reloadData];
}
總結(jié)
iOS設(shè)備不僅可以探測周圍iBeacon信號,也可以把自身作為一個iBeacon來向外界發(fā)送信號內(nèi)容(具體實現(xiàn)很簡單,大家自行查閱資料)。
最后在實際的使用中,參照最后的那片文章實現(xiàn)了三角定位的算法,但是,信號的波動還是很大的,并不符合理想,就沒有在繼續(xù)研究下去。如果大家有興趣可以一起研究討論。
參考文獻
基于iBeacon基站的室內(nèi)定位技術(shù)研究[1]
參考資料
https://github.com/wangjianhuajoysuccess/iOSCoreLib/blob/main/6%E5%9F%BA%E4%BA%8EiBeacon%E5%9F%BA%E7%AB%99%E7%9A%84%E5%AE%A4%E5%86%85%E5%AE%9A%E4%BD%8D%E6%8A%80%E6%9C%AF%E7%A0%94%E7%A9%B6.pdf
-End-
最近有一些小伙伴,讓我?guī)兔φ乙恍?nbsp;面試題 資料,于是我翻遍了收藏的 5T 資料后,匯總整理出來,可以說是程序員面試必備!所有資料都整理到網(wǎng)盤了,歡迎下載!

面試題】即可獲取