@rodrigo7/react-native-beacons-manager 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/.flowconfig +21 -0
  2. package/.nvmrc +1 -0
  3. package/.prettierignore +4 -0
  4. package/.prettierrc +12 -0
  5. package/.vscode/settings.json +24 -0
  6. package/LICENSE +21 -0
  7. package/README.md +246 -0
  8. package/ReactNativeBeaconsManager.podspec +13 -0
  9. package/android/.project +17 -0
  10. package/android/.settings/org.eclipse.buildship.core.prefs +2 -0
  11. package/android/build.gradle +108 -0
  12. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  13. package/android/gradle/wrapper/gradle-wrapper.properties +6 -0
  14. package/android/gradle/wrapper/gradle.properties +2 -0
  15. package/android/gradlew +160 -0
  16. package/android/gradlew.bat +90 -0
  17. package/android/src/main/AndroidManifest.xml +8 -0
  18. package/android/src/main/java/com/mackentoch/beaconsandroid/BeaconsAndroidModule.java +457 -0
  19. package/android/src/main/java/com/mackentoch/beaconsandroid/BeaconsAndroidPackage.java +29 -0
  20. package/index.js +10 -0
  21. package/ios/RNiBeacon/RNiBeacon/ESSBeaconScanner.h +41 -0
  22. package/ios/RNiBeacon/RNiBeacon/ESSBeaconScanner.m +204 -0
  23. package/ios/RNiBeacon/RNiBeacon/ESSEddystone.h +117 -0
  24. package/ios/RNiBeacon/RNiBeacon/ESSEddystone.m +352 -0
  25. package/ios/RNiBeacon/RNiBeacon/ESSTimer.h +72 -0
  26. package/ios/RNiBeacon/RNiBeacon/ESSTimer.m +107 -0
  27. package/ios/RNiBeacon/RNiBeacon/RNiBeacon.h +16 -0
  28. package/ios/RNiBeacon/RNiBeacon/RNiBeacon.m +467 -0
  29. package/ios/RNiBeacon/RNiBeacon.xcodeproj/project.pbxproj +290 -0
  30. package/jsconfig.json +9 -0
  31. package/lib/next/module.types.js +169 -0
  32. package/lib/next/new.module.android.js +451 -0
  33. package/lib/next/new.module.ios.js +176 -0
  34. package/package.json +65 -0
  35. package/typings/index.d.ts +174 -0
  36. package/typings.json +7 -0
  37. package/yarn-error.log +4182 -0
@@ -0,0 +1,204 @@
1
+ // Copyright 2015 Google Inc. All rights reserved.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #import <CoreBluetooth/CoreBluetooth.h>
16
+
17
+ #import "ESSBeaconScanner.h"
18
+ #import "ESSEddystone.h"
19
+ #import "ESSTimer.h"
20
+
21
+ static const char *const kBeaconsOperationQueueName = "kESSBeaconScannerBeaconsOperationQueueName";
22
+ static NSString *const kESSEddystoneServiceID = @"FEAA";
23
+ static NSString *const kSeenCacheBeaconInfo = @"beacon_info";
24
+ static NSString *const kSeenCacheOnLostTimer = @"on_lost_timer";
25
+
26
+ /**
27
+ *=-----------------------------------------------------------------------------------------------=
28
+ * Private Additions to ESSBeaconScanner
29
+ *=-----------------------------------------------------------------------------------------------=
30
+ */
31
+ @interface ESSBeaconScanner () <CBCentralManagerDelegate> {
32
+ CBCentralManager *_centralManager;
33
+ dispatch_queue_t _beaconOperationsQueue;
34
+
35
+ /**
36
+ * This cache maps Core Bluetooth deviceIDs to NSData objects containing Eddystone telemetry.
37
+ * Then, the next time we see a UID frame for that Eddystone, we can add the most recently seen
38
+ * telemetry frame to the sighting.
39
+ */
40
+ NSMutableDictionary *_tlmCache;
41
+
42
+ /**
43
+ * Beacons we've seen list.
44
+ */
45
+ NSMutableDictionary *_eddystoneBeaconsCache;
46
+
47
+ BOOL _shouldBeScanning;
48
+ }
49
+
50
+ @end
51
+
52
+ /**
53
+ *=-----------------------------------------------------------------------------------------------=
54
+ * Implementation for ESSBeaconScanner
55
+ *=-----------------------------------------------------------------------------------------------=
56
+ */
57
+ @implementation ESSBeaconScanner
58
+
59
+ - (instancetype)init {
60
+ if ((self = [super init]) != nil) {
61
+ _onLostTimeout = 5.0;
62
+ _tlmCache = [NSMutableDictionary dictionary];
63
+ _beaconOperationsQueue = dispatch_queue_create(kBeaconsOperationQueueName, NULL);
64
+ _centralManager = [[CBCentralManager alloc] initWithDelegate:self
65
+ queue:_beaconOperationsQueue];
66
+ }
67
+
68
+ return self;
69
+ }
70
+
71
+ - (void)startScanning {
72
+ dispatch_async(_beaconOperationsQueue, ^{
73
+ if (_centralManager.state != CBCentralManagerStatePoweredOn) {
74
+ NSLog(@"CBCentralManager state is %ld, cannot start or stop scanning",
75
+ (long)_centralManager.state);
76
+ _shouldBeScanning = YES;
77
+ } else {
78
+ NSLog(@"Starting to scan for Eddystones");
79
+ _eddystoneBeaconsCache = [[NSMutableDictionary alloc] init];
80
+ NSArray *services = @[
81
+ [CBUUID UUIDWithString:kESSEddystoneServiceID]
82
+ ];
83
+
84
+ // We do not want multiple discoveries of the same beacon to be coalesced into one.
85
+ // (Unfortunately this is ignored when we are in the background.)
86
+ NSDictionary *options = @{ CBCentralManagerScanOptionAllowDuplicatesKey : @YES };
87
+ [_centralManager scanForPeripheralsWithServices:services options:options];
88
+ }
89
+ });
90
+ }
91
+
92
+ - (void)stopScanning {
93
+ _shouldBeScanning = NO;
94
+ [_centralManager stopScan];
95
+ [self clearRemainingTimers];
96
+ }
97
+
98
+ - (void)centralManagerDidUpdateState:(CBCentralManager *)central {
99
+ if (central.state == CBCentralManagerStatePoweredOn && _shouldBeScanning) {
100
+ [self startScanning];
101
+ }
102
+ }
103
+
104
+ // This will be called from the |beaconsOperationQueue|.
105
+ - (void)centralManager:(CBCentralManager *)central
106
+ didDiscoverPeripheral:(CBPeripheral *)peripheral
107
+ advertisementData:(NSDictionary *)advertisementData
108
+ RSSI:(NSNumber *)RSSI {
109
+ NSDictionary *serviceData = advertisementData[CBAdvertisementDataServiceDataKey];
110
+ NSData *beaconServiceData = serviceData[[ESSBeaconInfo eddystoneServiceID]];
111
+
112
+ ESSFrameType frameType = [ESSBeaconInfo frameTypeForFrame:beaconServiceData];
113
+
114
+ // If it's a telemetry (TLM) frame, then save it into our cache so that the next time we get a
115
+ // UID frame (i.e. an Eddystone "sighting"), we can include the telemetry with it.
116
+ if (frameType == kESSEddystoneTelemetryFrameType) {
117
+ _tlmCache[peripheral.identifier] = beaconServiceData;
118
+ } else if (frameType == kESSEddystoneURLFrameType) {
119
+ NSURL *url = [ESSBeaconInfo parseURLFromFrameData:beaconServiceData];
120
+
121
+ // Report the sighted URL frame.
122
+ if ([_delegate respondsToSelector:@selector(beaconScanner:didFindURL:)]) {
123
+ [_delegate beaconScanner:self didFindURL:url];
124
+ }
125
+ } else if (frameType == kESSEddystoneUIDFrameType
126
+ || frameType == kESSEddystoneEIDFrameType) {
127
+ CBUUID *eddystoneServiceUUID = [ESSBeaconInfo eddystoneServiceID];
128
+ NSData *eddystoneServiceData = serviceData[eddystoneServiceUUID];
129
+
130
+ // If we have telemetry data for this Eddystone, include it in the construction of the
131
+ // ESSBeaconInfo object. Otherwise, nil is fine.
132
+ NSData *telemetry = _tlmCache[peripheral.identifier];
133
+
134
+ ESSBeaconInfo *beaconInfo;
135
+ if (frameType == kESSEddystoneUIDFrameType) {
136
+ beaconInfo = [ESSBeaconInfo beaconInfoForUIDFrameData:eddystoneServiceData
137
+ telemetry:telemetry
138
+ RSSI:RSSI];
139
+ } else {
140
+ beaconInfo = [ESSBeaconInfo beaconInfoForEIDFrameData:eddystoneServiceData
141
+ telemetry:telemetry
142
+ RSSI:RSSI];
143
+ }
144
+
145
+ if (beaconInfo) {
146
+ // NOTE: At this point you can choose whether to keep or get rid of the telemetry data. You
147
+ // can either opt to include it with every single beacon sighting for this beacon, or
148
+ // delete it until we get a new / "fresh" TLM frame. We'll treat it as "report it only
149
+ // when you see it", so we'll delete it each time.
150
+ [_tlmCache removeObjectForKey:peripheral.identifier];
151
+
152
+ // If we haven't seen this Eddystone before, fire a beaconScanner:didFindBeacon: and mark it
153
+ // as seen.
154
+ if (!_eddystoneBeaconsCache[beaconInfo.beaconID]) {
155
+ ESSTimer *onLostTimer = [ESSTimer scheduledTimerWithDelay:_onLostTimeout
156
+ onQueue:dispatch_get_main_queue()
157
+ block:
158
+ ^(ESSTimer *timer) {
159
+ ESSBeaconInfo *lostBeaconInfo =
160
+ _eddystoneBeaconsCache[beaconInfo.beaconID][kSeenCacheBeaconInfo];
161
+ if (lostBeaconInfo) {
162
+ [_eddystoneBeaconsCache removeObjectForKey:beaconInfo.beaconID];
163
+ [self notifyDidRangeBeacon:_eddystoneBeaconsCache];
164
+ }
165
+ }];
166
+
167
+ _eddystoneBeaconsCache[beaconInfo.beaconID] = @{
168
+ kSeenCacheBeaconInfo: beaconInfo,
169
+ kSeenCacheOnLostTimer: onLostTimer,
170
+ };
171
+ [self notifyDidRangeBeacon:_eddystoneBeaconsCache];
172
+ } else {
173
+ // Reset the onLost timer.
174
+ [_eddystoneBeaconsCache[beaconInfo.beaconID][kSeenCacheOnLostTimer] reschedule];
175
+ [self notifyDidRangeBeacon:_eddystoneBeaconsCache];
176
+ }
177
+ }
178
+ } else {
179
+ NSLog(@"Unsupported frame type (%d) detected. Ignorning.", (int)frameType);
180
+ }
181
+ }
182
+
183
+ /**
184
+ * Commont event about beacons changes in region
185
+ */
186
+ - (void)notifyDidRangeBeacon:(NSMutableDictionary *)beacons {
187
+ if (![_delegate respondsToSelector:@selector(beaconScanner:didRangeBeacon:)]) return;
188
+
189
+ NSMutableArray *beaconArray = [[NSMutableArray alloc] init];
190
+ for (id key in beacons) {
191
+ [beaconArray addObject:beacons[key][kSeenCacheBeaconInfo]];
192
+ }
193
+ [_delegate beaconScanner:self didRangeBeacon:beaconArray];
194
+ }
195
+
196
+ - (void)clearRemainingTimers {
197
+ for (ESSBeaconID *beaconID in _eddystoneBeaconsCache) {
198
+ [_eddystoneBeaconsCache[beaconID][kSeenCacheOnLostTimer] cancel];
199
+ }
200
+
201
+ _eddystoneBeaconsCache = nil;
202
+ }
203
+
204
+ @end
@@ -0,0 +1,117 @@
1
+ // Copyright 2015 Google Inc. All rights reserved.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #import <Foundation/Foundation.h>
16
+ #import <CoreBluetooth/CoreBluetooth.h>
17
+
18
+ typedef NS_ENUM(NSUInteger, ESSBeaconType) {
19
+ kESSBeaconTypeEddystone = 1,
20
+ kESSBeaconTypeEddystoneEID = 2,
21
+ };
22
+
23
+ typedef NS_ENUM(NSUInteger, ESSFrameType) {
24
+ kESSEddystoneUnknownFrameType = 0,
25
+ kESSEddystoneUIDFrameType,
26
+ kESSEddystoneURLFrameType,
27
+ kESSEddystoneEIDFrameType,
28
+ kESSEddystoneTelemetryFrameType,
29
+ };
30
+
31
+ /**
32
+ *=-----------------------------------------------------------------------------------------------=
33
+ * ESSBeaconID
34
+ *=-----------------------------------------------------------------------------------------------=
35
+ */
36
+ @interface ESSBeaconID : NSObject <NSCopying>
37
+
38
+ /**
39
+ * The type of the beacon. Currently only a couple of types are supported.
40
+ */
41
+ @property(nonatomic, assign, readonly) ESSBeaconType beaconType;
42
+
43
+ /**
44
+ * The raw beaconID data.
45
+ */
46
+ @property(nonatomic, copy, readonly) NSData *beaconID;
47
+
48
+ @end
49
+
50
+
51
+ /**
52
+ *=-----------------------------------------------------------------------------------------------=
53
+ * ESSBeaconInfo
54
+ *=-----------------------------------------------------------------------------------------------=
55
+ */
56
+ @interface ESSBeaconInfo : NSObject
57
+
58
+ /**
59
+ * The most recent RSSI we got for this sighting. Sometimes the OS cannot compute one reliably, so
60
+ * this value can be null.
61
+ */
62
+ @property(nonatomic, strong, readonly) NSNumber *RSSI;
63
+
64
+ /**
65
+ * The beaconID for this Eddystone. All beacons have an ID.
66
+ */
67
+ @property(nonatomic, strong, readonly) ESSBeaconID *beaconID;
68
+
69
+ /**
70
+ * The telemetry that may or may not have been seen for this beacon. If it's set, the contents of
71
+ * it aren't terribly relevant to us, in general. See the Eddystone spec for more information
72
+ * if you're really interested in the exact details.
73
+ */
74
+ @property(nonatomic, copy, readonly) NSData *telemetry;
75
+
76
+ /**
77
+ * Transmission power reported by beacon. This is in dB.
78
+ */
79
+ @property(nonatomic, strong, readonly) NSNumber *txPower;
80
+
81
+ /**
82
+ * The scanner has seen a frame for an Eddystone. We'll need to know what type of Eddystone frame
83
+ * it is, as there are a few types.
84
+ */
85
+ + (ESSFrameType)frameTypeForFrame:(NSData *)frameData;
86
+
87
+ /**
88
+ * Given the service data for a frame we know to be a UID frame, an RSSI sighting,
89
+ * and -- optionally -- telemetry data (if we've seen it), create a new ESSBeaconInfo object to
90
+ * represent this Eddystone
91
+ */
92
+ + (instancetype)beaconInfoForUIDFrameData:(NSData *)UIDFrameData
93
+ telemetry:(NSData *)telemetry
94
+ RSSI:(NSNumber *)initialRSSI;
95
+
96
+ /**
97
+ * Given the service data for a frame we know to be a UID frame, an RSSI sighting,
98
+ * and -- optionally -- telemetry data (if we've seen it), create a new ESSBeaconInfo object to
99
+ * represent this Eddystone
100
+ */
101
+ + (instancetype)beaconInfoForEIDFrameData:(NSData *)EIDFrameData
102
+ telemetry:(NSData *)telemetry
103
+ RSSI:(NSNumber *)initialRSSI;
104
+
105
+ /**
106
+ * If we're given a URL frame, extract the URL from it.
107
+ */
108
+ + (NSURL *)parseURLFromFrameData:(NSData *)URLFrameData;
109
+
110
+ /**
111
+ * Convenience method to save everybody from creating these things all the time.
112
+ */
113
+ + (CBUUID *)eddystoneServiceID;
114
+
115
+ + (ESSBeaconInfo *)testBeaconFromBeaconIDString:(NSString *)beaconID;
116
+
117
+ @end
@@ -0,0 +1,352 @@
1
+ // Copyright 2015 Google Inc. All rights reserved.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #import "ESSEddystone.h"
16
+
17
+ #import <CoreBluetooth/CoreBluetooth.h>
18
+
19
+ /**
20
+ * The Bluetooth Service ID for Eddystones.
21
+ */
22
+ static NSString *const kEddystoneServiceID = @"FEAA";
23
+
24
+ /**
25
+ * Eddystones can have different frame types. Within the frames, these are (some of) the possible
26
+ * values. See the Eddystone spec for complete details.
27
+ */
28
+ static const uint8_t kEddystoneUIDFrameTypeID = 0x00;
29
+ static const uint8_t kEddystoneURLFrameTypeID = 0x10;
30
+ static const uint8_t kEddystoneTLMFrameTypeID = 0x20;
31
+ static const uint8_t kEddystoneEIDFrameTypeID = 0x30;
32
+
33
+ // Note that for these Eddystone structures, the endianness of the individual fields is big-endian,
34
+ // so you'll want to translate back to host format when necessary.
35
+ // Note that in the Eddystone spec, the beaconID (UID) is divided into 2 fields, a 10 byte namespace
36
+ // and a 6 byte instance id. However, since we ALWAYS use these in combination as a 16 byte
37
+ // beaconID, we'll have our structure here reflect that.
38
+ typedef struct __attribute__((packed)) {
39
+ uint8_t frameType;
40
+ int8_t txPower;
41
+ uint8_t beaconID[16];
42
+ uint8_t RFU[2];
43
+ } ESSEddystoneUIDFrameFields;
44
+
45
+ typedef struct __attribute__((packed)) {
46
+ uint8_t frameType;
47
+ int8_t txPower;
48
+ uint8_t beaconID[8];
49
+ } ESSEddystoneEIDFrameFields;
50
+
51
+ // Test equality, ensuring that nil is equal to itself.
52
+ static inline BOOL IsEqualOrBothNil(id a, id b) {
53
+ return ((a == b) || (a && b && [a isEqual:b]));
54
+ }
55
+
56
+ /**
57
+ *=-----------------------------------------------------------------------------------------------=
58
+ * ESSBeaconID
59
+ *=-----------------------------------------------------------------------------------------------=
60
+ */
61
+ @implementation ESSBeaconID
62
+
63
+ /**
64
+ * This property is orginally declared in a superclass (NSObject), so cannot be auto-synthesized.
65
+ */
66
+ @synthesize hash = _hash;
67
+
68
+ - (instancetype)initWithType:(ESSBeaconType)beaconType
69
+ beaconID:(NSData *)beaconID {
70
+ self = [super init];
71
+ if (self) {
72
+ _beaconType = beaconType;
73
+ _beaconID = [beaconID copy];
74
+ _hash = 31 * self.beaconType + [self.beaconID hash];
75
+ }
76
+ return self;
77
+ }
78
+
79
+ /**
80
+ * So that whenever you convert this to a string, you get something useful.
81
+ */
82
+ - (NSString *)description {
83
+ if (self.beaconType == kESSBeaconTypeEddystone) {
84
+ return [NSString stringWithFormat:@"ESSBeaconID: beaconID=%@", self.beaconID];
85
+ } else if (self.beaconType == kESSBeaconTypeEddystoneEID) {
86
+ return [NSString stringWithFormat:@"ESSBeaconID (EID): beaconID=%@", self.beaconID];
87
+ } else {
88
+ return [NSString stringWithFormat:@"ESSBeaconID with invalid type %lu",
89
+ (unsigned long)self.beaconType];
90
+ }
91
+ }
92
+
93
+ - (BOOL)isEqual:(id)object {
94
+ if (object == self) {
95
+ return YES;
96
+ }
97
+ if (!self
98
+ || !object
99
+ || !([self isKindOfClass:[object class]] || [object isKindOfClass:[self class]])) {
100
+ return NO;
101
+ }
102
+
103
+ ESSBeaconID *other = (ESSBeaconID *)object;
104
+ return ((self.beaconType == other.beaconType) &&
105
+ IsEqualOrBothNil(self.beaconID, other.beaconID));
106
+ }
107
+
108
+ - (id)copyWithZone:(NSZone *)zone {
109
+ // Immutable object: 'copy' by reusing the same instance.
110
+ return self;
111
+ }
112
+
113
+ @end
114
+
115
+
116
+ /**
117
+ *=-----------------------------------------------------------------------------------------------=
118
+ * ESSBeaconInfo
119
+ *=-----------------------------------------------------------------------------------------------=
120
+ */
121
+ @implementation ESSBeaconInfo
122
+
123
+ /**
124
+ * Given the advertising frames from CoreBluetooth for a device with the Eddystone Service ID,
125
+ * figure out what type of frame it is.
126
+ */
127
+ + (ESSFrameType)frameTypeForFrame:(NSData *)frameData {
128
+ // It's an Eddystone ADV frame. Now check if it's a UID (ID) or TLM (telemetry) frame.
129
+ if (frameData) {
130
+ uint8_t frameType;
131
+ if ([frameData length] > 1) {
132
+ frameType = ((uint8_t *)[frameData bytes])[0];
133
+ switch (frameType) {
134
+ case kEddystoneUIDFrameTypeID:
135
+ return kESSEddystoneUIDFrameType;
136
+ case kEddystoneURLFrameTypeID:
137
+ return kESSEddystoneURLFrameType;
138
+ case kEddystoneTLMFrameTypeID:
139
+ return kESSEddystoneTelemetryFrameType;
140
+ case kEddystoneEIDFrameTypeID:
141
+ return kESSEddystoneEIDFrameType;
142
+ }
143
+ }
144
+ }
145
+
146
+ return kESSEddystoneUnknownFrameType;
147
+ }
148
+
149
+ + (NSURL *)parseURLFromFrameData:(NSData *)URLFrameData {
150
+ NSAssert([ESSBeaconInfo frameTypeForFrame:URLFrameData] == kESSEddystoneURLFrameType,
151
+ @"This should be a URL frame, but it's not. Whooops");
152
+
153
+ if (!(URLFrameData.length > 0)) {
154
+ return nil;
155
+ }
156
+
157
+ unsigned char urlFrame[20];
158
+ [URLFrameData getBytes:&urlFrame length:URLFrameData.length];
159
+
160
+ NSString *urlScheme = [self getURLScheme:*(urlFrame+2)];
161
+
162
+ NSString *urlString = urlScheme;
163
+ for (int i = 0; i < URLFrameData.length - 3; i++) {
164
+ urlString = [urlString stringByAppendingString:[self getEncodedString:*(urlFrame + i + 3)]];
165
+ }
166
+
167
+ return [NSURL URLWithString:urlString];
168
+ }
169
+
170
+ - (instancetype)initWithBeaconID:(ESSBeaconID *)beaconID
171
+ txPower:(NSNumber *)txPower
172
+ RSSI:(NSNumber *)RSSI
173
+ telemetry:(NSData *)telemetry {
174
+ if ((self = [super init]) != nil) {
175
+ _beaconID = beaconID;
176
+ _txPower = txPower;
177
+ _RSSI = RSSI;
178
+ _telemetry = [telemetry copy];
179
+ }
180
+
181
+ return self;
182
+ }
183
+
184
+ + (instancetype)beaconInfoForUIDFrameData:(NSData *)UIDFrameData
185
+ telemetry:(NSData *)telemetry
186
+ RSSI:(NSNumber *)RSSI {
187
+ NSAssert([ESSBeaconInfo frameTypeForFrame:UIDFrameData] == kESSEddystoneUIDFrameType,
188
+ @"This should be a UID frame, but it's not. Whooops");
189
+
190
+ // Make sure this frame has the correct frame type identifier
191
+ uint8_t frameType;
192
+ [UIDFrameData getBytes:&frameType length:1];
193
+ if (frameType != kEddystoneUIDFrameTypeID) {
194
+ return nil;
195
+ }
196
+
197
+ ESSEddystoneUIDFrameFields uidFrame;
198
+
199
+ if ([UIDFrameData length] == sizeof(ESSEddystoneUIDFrameFields)
200
+ || [UIDFrameData length] == sizeof(ESSEddystoneUIDFrameFields) - sizeof(uidFrame.RFU)) {
201
+
202
+ [UIDFrameData getBytes:&uidFrame length:(sizeof(ESSEddystoneUIDFrameFields)
203
+ - sizeof(uidFrame.RFU))];
204
+
205
+ NSData *beaconIDData = [NSData dataWithBytes:&uidFrame.beaconID
206
+ length:sizeof(uidFrame.beaconID)];
207
+
208
+ ESSBeaconID *beaconID = [[ESSBeaconID alloc] initWithType:kESSBeaconTypeEddystone
209
+ beaconID:beaconIDData];
210
+ if (beaconID == nil) {
211
+ return nil;
212
+ }
213
+
214
+ return [[ESSBeaconInfo alloc] initWithBeaconID:beaconID
215
+ txPower:@(uidFrame.txPower)
216
+ RSSI:RSSI
217
+ telemetry:telemetry];
218
+ } else {
219
+ return nil;
220
+ }
221
+ }
222
+
223
+ + (instancetype)beaconInfoForEIDFrameData:(NSData *)EIDFrameData
224
+ telemetry:(NSData *)telemetry
225
+ RSSI:(NSNumber *)RSSI {
226
+ NSAssert([ESSBeaconInfo frameTypeForFrame:EIDFrameData] == kESSEddystoneEIDFrameType,
227
+ @"This should be an EID frame, but it's not. Whooops");
228
+
229
+ // Make sure this frame has the correct frame type identifier
230
+ uint8_t frameType;
231
+ [EIDFrameData getBytes:&frameType length:1];
232
+ if (frameType != kEddystoneEIDFrameTypeID) {
233
+ return nil;
234
+ }
235
+
236
+ ESSEddystoneEIDFrameFields eidFrame;
237
+
238
+ if ([EIDFrameData length] == sizeof(ESSEddystoneEIDFrameFields)) {
239
+ [EIDFrameData getBytes:&eidFrame length:sizeof(ESSEddystoneEIDFrameFields)];
240
+ NSData *beaconIDData = [NSData dataWithBytes:&eidFrame.beaconID
241
+ length:sizeof(eidFrame.beaconID)];
242
+
243
+ ESSBeaconID *beaconID = [[ESSBeaconID alloc] initWithType:kESSBeaconTypeEddystoneEID
244
+ beaconID:beaconIDData];
245
+ if (beaconID == nil) {
246
+ return nil;
247
+ }
248
+
249
+ return [[ESSBeaconInfo alloc] initWithBeaconID:beaconID
250
+ txPower:@(eidFrame.txPower)
251
+ RSSI:RSSI
252
+ telemetry:telemetry];
253
+ } else {
254
+ return nil;
255
+ }
256
+ }
257
+
258
+ - (NSString *)description {
259
+ NSString *str = [NSString stringWithFormat:@"Eddystone, id: %@, RSSI: %@, txPower: %@",
260
+ _beaconID, _RSSI, _txPower];
261
+ return str;
262
+ }
263
+
264
+ + (CBUUID *)eddystoneServiceID {
265
+ static CBUUID *_singleton;
266
+ static dispatch_once_t oncePredicate;
267
+
268
+ dispatch_once(&oncePredicate, ^{
269
+ _singleton = [CBUUID UUIDWithString:kEddystoneServiceID];
270
+ });
271
+
272
+ return _singleton;
273
+ }
274
+
275
+ + (ESSBeaconInfo *)testBeaconFromBeaconIDString:(NSString *)beaconID {
276
+ NSData *beaconIDData = [ESSBeaconInfo hexStringToNSData:beaconID];
277
+ ESSBeaconID *beaconIDObj = [[ESSBeaconID alloc] initWithType:kESSBeaconTypeEddystone
278
+ beaconID:beaconIDData];
279
+
280
+ return [[ESSBeaconInfo alloc] initWithBeaconID:beaconIDObj
281
+ txPower:@(-20)
282
+ RSSI:@(-100)
283
+ telemetry:nil];
284
+ }
285
+
286
+ + (NSData *)hexStringToNSData:(NSString *)hexString {
287
+ NSMutableData *data = [[NSMutableData alloc] init];
288
+ unsigned char whole_byte;
289
+ char byte_chars[3] = {'\0','\0','\0'};
290
+
291
+ int i;
292
+ for (i = 0; i < [hexString length]/2; i++) {
293
+ byte_chars[0] = [hexString characterAtIndex:i * 2];
294
+ byte_chars[1] = [hexString characterAtIndex:i * 2 + 1];
295
+ whole_byte = strtol(byte_chars, NULL, 16);
296
+ [data appendBytes:&whole_byte length:1];
297
+ }
298
+
299
+ return data;
300
+ }
301
+
302
+ + (NSString *)getURLScheme:(char)hexChar {
303
+ switch (hexChar) {
304
+ case 0x00:
305
+ return @"http://www.";
306
+ case 0x01:
307
+ return @"https://www.";
308
+ case 0x02:
309
+ return @"http://";
310
+ case 0x03:
311
+ return @"https://";
312
+ default:
313
+ return nil;
314
+ }
315
+ }
316
+
317
+ + (NSString *)getEncodedString:(char)hexChar {
318
+ switch (hexChar) {
319
+ case 0x00:
320
+ return @".com/";
321
+ case 0x01:
322
+ return @".org/";
323
+ case 0x02:
324
+ return @".edu/";
325
+ case 0x03:
326
+ return @".net/";
327
+ case 0x04:
328
+ return @".info/";
329
+ case 0x05:
330
+ return @".biz/";
331
+ case 0x06:
332
+ return @".gov/";
333
+ case 0x07:
334
+ return @".com";
335
+ case 0x08:
336
+ return @".org";
337
+ case 0x09:
338
+ return @".edu";
339
+ case 0x0a:
340
+ return @".net";
341
+ case 0x0b:
342
+ return @".info";
343
+ case 0x0c:
344
+ return @".biz";
345
+ case 0x0d:
346
+ return @".gov";
347
+ default:
348
+ return [NSString stringWithFormat:@"%c", hexChar];
349
+ }
350
+ }
351
+
352
+ @end