-
Notifications
You must be signed in to change notification settings - Fork 21
/
ReactNativeDiscovery.m
195 lines (154 loc) · 7.34 KB
/
ReactNativeDiscovery.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
//
// DiscoveryReact.m
// DiscoveryReact
#import "ReactNativeDiscovery.h"
#import <React/RCTBridge.h>
#import <React/RCTConvert.h>
#import <React/RCTEventDispatcher.h>
#import "Discovery.h"
@interface ReactNativeDiscovery()
@property (strong, nonatomic) id bleStateObserver;
@property (strong, nonatomic) NSMutableDictionary *discoveryDict;
@end
@implementation ReactNativeDiscovery
RCT_EXPORT_MODULE()
@synthesize bridge = _bridge;
#pragma mark Initialization
/**
* Initialize the Discovery object with a UUID specific to your app, and a username specific to your device.
*/
RCT_REMAP_METHOD(initialize, initialize:(NSString *)uuidString username:(NSString *)username resolve:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{
if (self.bleStateObserver == nil) {
self.bleStateObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kBluetoothStateNotificationKey object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
NSInteger centralState = [(NSNumber *)note.userInfo[kBluetoothCentralStateKey] integerValue];
BOOL isOn = centralState == CBCentralManagerStatePoweredOn;
NSDictionary *event = @{ @"isOn" : @(isOn)};
[self.bridge.eventDispatcher sendDeviceEventWithName:@"bleStateChanged" body:event];
}];
}
if (self.discoveryDict == nil) {
self.discoveryDict = [NSMutableDictionary dictionary];
}
Discovery *discovery = [self.discoveryDict objectForKey:uuidString];
if (discovery != nil) {
[discovery setShouldDiscover: NO];
[discovery setShouldAdvertise: NO];
[self.discoveryDict removeObjectForKey:uuidString];
}
discovery = [[Discovery alloc] initWithUUID: [CBUUID UUIDWithString:uuidString]
username: username
startOption:DIStartNone
usersBlock:^(NSArray *users, BOOL usersChanged) {
[self discovery:uuidString discoveredUsers:users didChange:usersChanged];
}];
[self.discoveryDict setObject:discovery forKey:uuidString];
resolve(uuidString);
}
/**
* run on the main queue otherwise discovery timers dont work.
*/
- (dispatch_queue_t)methodQueue {
return dispatch_get_main_queue();
}
-(void)discovery:(NSString *)uuidString discoveredUsers:(NSArray *)users didChange:(BOOL) usersChanged {
NSMutableArray *array = [NSMutableArray array];
for (BLEUser *user in users) {
[array addObject:[self convertBLEUserToDict:user]];
}
NSDictionary *event = @{
@"uuid": uuidString,
@"users": array,
@"didChange": @(usersChanged)
};
[self.bridge.eventDispatcher sendDeviceEventWithName:@"discoveredUsers" body:event];
}
-(NSDictionary *)convertBLEUserToDict:(BLEUser *)bleUser{
NSDictionary *dict = @{
@"peripheralId":bleUser.peripheralId,
@"username":bleUser.username,
@"identified":@(bleUser.identified),
@"rssi":@(bleUser.rssi),
@"proximity":@(bleUser.proximity),
@"updateTime":@(bleUser.updateTime)
};
return dict;
}
/**
* Returns the user user from our user dictionary according to its peripheralId.
*/
RCT_REMAP_METHOD(userWithPeripheralId, userWithPeripheralId:(NSString *)uuidString peripheralId:(NSString *)peripheralId resolve:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{
Discovery *discovery = [self.discoveryDict objectForKey:uuidString];
if (discovery) {
BLEUser *user = [discovery userWithPeripheralId:peripheralId];
resolve(user ? [self convertBLEUserToDict:user] : @{});
} else {
reject(@"not_initialized", [NSString stringWithFormat:@"UUID %@ not initialized", uuidString], [NSError errorWithDomain:@"ReactNativeDiscovery" code:0 userInfo:nil]);
}
}
/**
* Changing these properties will start/stop advertising/discovery
*/
RCT_REMAP_METHOD(setShouldAdvertise, setShouldAdvertise:(NSString *)uuidString shouldAdvertise:(BOOL)shouldAdvertise resolve:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{
Discovery *discovery = [self.discoveryDict objectForKey:uuidString];
if (discovery) {
[discovery setShouldAdvertise:shouldAdvertise];
resolve(@YES);
} else {
reject(@"not_initialized", [NSString stringWithFormat:@"UUID %@ not initialized", uuidString], [NSError errorWithDomain:@"ReactNativeDiscovery" code:0 userInfo:nil]);
}
}
RCT_REMAP_METHOD(setShouldDiscover, setShouldDiscover:(NSString *)uuidString shouldDiscover:(BOOL)shouldDiscover resolve:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{
Discovery *discovery = [self.discoveryDict objectForKey:uuidString];
if (discovery) {
[discovery setShouldDiscover:shouldDiscover];
resolve(@YES);
} else {
reject(@"not_initialized", [NSString stringWithFormat:@"UUID %@ not initialized", uuidString], [NSError errorWithDomain:@"ReactNativeDiscovery" code:0 userInfo:nil]);
}
}
/*
* Discovery removes the users if can not re-see them after some amount of time, assuming the device-user is gone.
* The default value is 3 seconds. You can set your own values.
*/
RCT_REMAP_METHOD(setUserTimeoutInterval, setUserTimeoutInterval:(NSString *)uuidString userTimeoutInterval:(int)userTimeoutInterval resolve:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{
Discovery *discovery = [self.discoveryDict objectForKey:uuidString];
if (discovery) {
[discovery setUserTimeoutInterval:userTimeoutInterval];
resolve(@YES);
} else {
reject(@"not_initialized", [NSString stringWithFormat:@"UUID %@ not initialized", uuidString], [NSError errorWithDomain:@"ReactNativeDiscovery" code:0 userInfo:nil]);
}
}
/*
* Update interval is the interval that your usersBlock gets triggered.
*/
RCT_REMAP_METHOD(setUpdateInterval, setUpdateInterval:(NSString *)uuidString updateInterval:(int)updateInterval resolve:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{
Discovery *discovery = [self.discoveryDict objectForKey:uuidString];
if (discovery) {
[discovery setUpdateInterval:updateInterval];
resolve(@YES);
} else {
reject(@"not_initialized", [NSString stringWithFormat:@"UUID %@ not initialized", uuidString], [NSError errorWithDomain:@"ReactNativeDiscovery" code:0 userInfo:nil]);
}
}
/**
* Set this to YES, if your app will disappear, or set to NO when it will appear.
* You don't have to set YES when your app goes to background state, Discovery handles that.
*/
RCT_REMAP_METHOD(setPaused, setPaused:(NSString *)uuidString paused:(BOOL)paused resolve:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{
Discovery *discovery = [self.discoveryDict objectForKey:uuidString];
if (discovery) {
[discovery setPaused:paused];
resolve(@YES);
} else {
reject(@"not_initialized", [NSString stringWithFormat:@"UUID %@ not initialized", uuidString], [NSError errorWithDomain:@"ReactNativeDiscovery" code:0 userInfo:nil]);
}
}
@end