Browse Source

refactor. started adding request permissions

Yonah Forst 8 years ago
parent
commit
c040506d7c

+ 26
- 0
PermissionsAsker.h View File

@@ -0,0 +1,26 @@
1
+//
2
+//  PermissionsAsker.h
3
+//  ReactNativePermissions
4
+//
5
+//  Created by Yonah Forst on 07/07/16.
6
+//  Copyright © 2016 Yonah Forst. All rights reserved.
7
+//
8
+
9
+#import <Foundation/Foundation.h>
10
+#import <UIKit/UIKit.h>
11
+#import "RCTConvert+RNPermissionsStatus.h"
12
+
13
+@interface PermissionsAsker : NSObject
14
+
15
++ (instancetype)sharedInstance;
16
+- (void)location:(NSString *)type;
17
+- (void)notification:(UIUserNotificationType)types completionHandler:(void (^)(RNPermissionsStatus))completionHandler;
18
+- (void)bluetooth;
19
+- (void)camera;
20
+- (void)microphone;
21
+- (void)photo;
22
+- (void)contacts;
23
+- (void)event;
24
+- (void)reminder;
25
+- (void)backgroundRefresh;
26
+@end

+ 114
- 0
PermissionsAsker.m View File

@@ -0,0 +1,114 @@
1
+//
2
+//  PermissionsAsker.m
3
+//  ReactNativePermissions
4
+//
5
+//  Created by Yonah Forst on 07/07/16.
6
+//  Copyright © 2016 Yonah Forst. All rights reserved.
7
+//
8
+
9
+#import "PermissionsAsker.h"
10
+
11
+#import <AddressBook/AddressBook.h>
12
+#import <AssetsLibrary/AssetsLibrary.h>
13
+#import <EventKit/EventKit.h>
14
+#import <CoreLocation/CoreLocation.h>
15
+#import <AVFoundation/AVFoundation.h>
16
+#import <CoreBluetooth/CoreBluetooth.h>
17
+
18
+#import "PermissionsChecker.h"
19
+
20
+static PermissionsAsker *__sharedInstance;
21
+
22
+@interface PermissionsAsker() <CLLocationManagerDelegate, CBPeripheralManagerDelegate>
23
+@property (strong, nonatomic) CLLocationManager *locationManager;
24
+@property (strong, nonatomic) CBPeripheralManager *peripheralManager;
25
+@property (copy) void (^notificationCompletionBlock)(RNPermissionsStatus);
26
+
27
+@end
28
+
29
+
30
+@implementation PermissionsAsker
31
+
32
++ (instancetype) sharedInstance
33
+{
34
+    static dispatch_once_t onceToken;
35
+    dispatch_once(&onceToken, ^{
36
+        __sharedInstance = [[PermissionsAsker alloc] init];
37
+    });
38
+    return __sharedInstance;
39
+}
40
+
41
+
42
+- (void)location:(NSString *)type
43
+{
44
+    self.locationManager = [[CLLocationManager alloc] init];
45
+    self.locationManager.delegate = self;
46
+    if ([type isEqualToString:@"always"]) {
47
+        [self.locationManager requestAlwaysAuthorization];
48
+    } else {
49
+        [self.locationManager requestWhenInUseAuthorization];
50
+    }
51
+}
52
+
53
+- (void)notification:(UIUserNotificationType)types completionHandler:(void (^)(RNPermissionsStatus))completionHandler
54
+{
55
+    BOOL didAskForPermission = [[NSUserDefaults standardUserDefaults] boolForKey:@"DidAskForNotifications"];
56
+    if (!didAskForPermission) {
57
+        self.notificationCompletionBlock = completionHandler;
58
+        
59
+        [[NSNotificationCenter defaultCenter] addObserver:self
60
+                                                 selector:@selector(applicationDidBecomeActive)
61
+                                                     name:UIApplicationDidBecomeActiveNotification
62
+                                                   object:nil];
63
+        
64
+        if ([[UIApplication sharedApplication] respondsToSelector:@selector(isRegisteredForRemoteNotifications)]) {
65
+            // iOS8+
66
+            UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
67
+            [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
68
+            [[UIApplication sharedApplication] registerForRemoteNotifications];
69
+        } else {
70
+            [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationType)types];
71
+        }
72
+        
73
+        [[NSUserDefaults standardUserDefaults] setBool:YES
74
+                                                forKey:@"DidAskForNotifications"];
75
+        [[NSUserDefaults standardUserDefaults] synchronize];
76
+    } else {
77
+        RNPermissionsStatus status = [PermissionsChecker notification];
78
+        completionHandler(status);
79
+    }
80
+
81
+}
82
+
83
+- (void)applicationDidBecomeActive
84
+{
85
+    [[NSNotificationCenter defaultCenter] removeObserver:self
86
+                                                    name:UIApplicationDidBecomeActiveNotification
87
+                                                  object:nil];
88
+
89
+    //for some reason, checking permission right away returns denied. need to wait a tiny bit
90
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
91
+        RNPermissionsStatus status = [PermissionsChecker notification];
92
+        self.notificationCompletionBlock(status);
93
+        self.notificationCompletionBlock = nil;
94
+    });
95
+}
96
+
97
+- (void)bluetooth
98
+{
99
+    self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];
100
+    [self.peripheralManager startAdvertising:@{}];
101
+}
102
+
103
+- (void) peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheralManager
104
+{
105
+    if (self.peripheralManager) {
106
+        [self.peripheralManager stopAdvertising];
107
+        self.peripheralManager = nil;
108
+    }
109
+}
110
+
111
+
112
+
113
+
114
+@end

+ 10
- 10
PermissionsChecker.h View File

@@ -11,15 +11,15 @@
11 11
 
12 12
 + (BOOL)canOpenSettings;
13 13
 + (void)openSettings;
14
-+ (RNPermissionsStatus)locationPermissionStatus;
15
-+ (RNPermissionsStatus)cameraPermissionStatus;
16
-+ (RNPermissionsStatus)microphonePermissionStatus;
17
-+ (RNPermissionsStatus)photoPermissionStatus;
18
-+ (RNPermissionsStatus)contactsPermissionStatus;
19
-+ (RNPermissionsStatus)eventPermissionStatus;
20
-+ (RNPermissionsStatus)reminderPermissionStatus;
21
-+ (RNPermissionsStatus)bluetoothPermissionStatus;
22
-+ (RNPermissionsStatus)notificationPermissionStatus;
23
-+ (RNPermissionsStatus)backgroundRefreshPermissionStatus;
14
++ (RNPermissionsStatus)location;
15
++ (RNPermissionsStatus)camera;
16
++ (RNPermissionsStatus)microphone;
17
++ (RNPermissionsStatus)photo;
18
++ (RNPermissionsStatus)contacts;
19
++ (RNPermissionsStatus)event;
20
++ (RNPermissionsStatus)reminder;
21
++ (RNPermissionsStatus)bluetooth;
22
++ (RNPermissionsStatus)notification;
23
++ (RNPermissionsStatus)backgroundRefresh;
24 24
 
25 25
 @end

+ 30
- 29
PermissionsChecker.m View File

@@ -42,7 +42,7 @@
42 42
 }
43 43
 
44 44
 
45
-+ (RNPermissionsStatus)locationPermissionStatus
45
++ (RNPermissionsStatus)location
46 46
 {
47 47
     int status = [CLLocationManager authorizationStatus];
48 48
     switch (status) {
@@ -61,7 +61,7 @@
61 61
 
62 62
 
63 63
 
64
-+ (RNPermissionsStatus)cameraPermissionStatus
64
++ (RNPermissionsStatus)camera
65 65
 {
66 66
     int status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
67 67
     switch (status) {
@@ -76,7 +76,7 @@
76 76
     }
77 77
 }
78 78
 
79
-+ (RNPermissionsStatus)microphonePermissionStatus
79
++ (RNPermissionsStatus)microphone
80 80
 {
81 81
     int status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
82 82
     switch (status) {
@@ -91,7 +91,7 @@
91 91
     }
92 92
 }
93 93
 
94
-+ (RNPermissionsStatus)photoPermissionStatus
94
++ (RNPermissionsStatus)photo
95 95
 {
96 96
 #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0
97 97
     int status = [PHPhotoLibrary authorizationStatus];
@@ -121,7 +121,7 @@
121 121
 }
122 122
 
123 123
 
124
-+ (RNPermissionsStatus)contactsPermissionStatus
124
++ (RNPermissionsStatus)contacts
125 125
 {
126 126
 #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0
127 127
     int status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
@@ -151,7 +151,7 @@
151 151
 }
152 152
 
153 153
 
154
-+ (RNPermissionsStatus)eventPermissionStatus
154
++ (RNPermissionsStatus)event
155 155
 {
156 156
     int status = [EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent];
157 157
     switch (status) {
@@ -166,7 +166,7 @@
166 166
     }
167 167
 }
168 168
 
169
-+ (RNPermissionsStatus)reminderPermissionStatus
169
++ (RNPermissionsStatus)reminder
170 170
 {
171 171
     int status = [EKEventStore authorizationStatusForEntityType:EKEntityTypeReminder];
172 172
     switch (status) {
@@ -182,7 +182,7 @@
182 182
 }
183 183
 
184 184
 
185
-+ (RNPermissionsStatus)bluetoothPermissionStatus
185
++ (RNPermissionsStatus)bluetooth
186 186
 {
187 187
     int status = [CBPeripheralManager authorizationStatus];
188 188
     switch (status) {
@@ -198,34 +198,35 @@
198 198
 }
199 199
 
200 200
 //problem here is that we can only return Authorized or Undetermined
201
-+ (RNPermissionsStatus)notificationPermissionStatus
201
++ (RNPermissionsStatus)notification
202 202
 {
203
-    if ([[UIApplication sharedApplication] respondsToSelector:@selector(isRegisteredForRemoteNotifications)]) {
204
-        // iOS8+
205
-        BOOL isRegistered = [[UIApplication sharedApplication] isRegisteredForRemoteNotifications];
206
-        BOOL isEnabled = [[[UIApplication sharedApplication] currentUserNotificationSettings] types] != UIUserNotificationTypeNone;
207
-        if (isRegistered || isEnabled) {
208
-            return isEnabled ? RNPermissionsStatusAuthorized : RNPermissionsStatusDenied;
209
-        }
210
-        else {
211
-            return RNPermissionsStatusUndetermined;
203
+    BOOL didAskForPermission = [[NSUserDefaults standardUserDefaults] boolForKey:@"DidAskForNotifications"];
204
+
205
+    if (didAskForPermission) {
206
+        if ([[UIApplication sharedApplication] respondsToSelector:@selector(isRegisteredForRemoteNotifications)]) {
207
+            // iOS8+
208
+            BOOL isRegistered = [[UIApplication sharedApplication] isRegisteredForRemoteNotifications];
209
+            BOOL isEnabled = [[[UIApplication sharedApplication] currentUserNotificationSettings] types] != UIUserNotificationTypeNone;
210
+            if (isRegistered || isEnabled) {
211
+                return isEnabled ? RNPermissionsStatusAuthorized : RNPermissionsStatusDenied;
212
+            }
213
+            else {
214
+                return RNPermissionsStatusDenied;
215
+            }
216
+        } else {
217
+            if ([[UIApplication sharedApplication] enabledRemoteNotificationTypes] == UIRemoteNotificationTypeNone) {
218
+                return RNPermissionsStatusDenied;
219
+            }
220
+            else {
221
+                return RNPermissionsStatusAuthorized;
222
+            }
212 223
         }
213 224
     } else {
214
-#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0
215
-        if ([[UIApplication sharedApplication] enabledRemoteNotificationTypes] == UIRemoteNotificationTypeNone) {
216
-            return RNPermissionsStatusUndetermined;
217
-        }
218
-        else {
219
-            return RNPermissionsStatusAuthorized;
220
-        }
221
-#else
222 225
         return RNPermissionsStatusUndetermined;
223
-#endif
224
-        
225 226
     }
226 227
 }
227 228
 
228
-+ (RNPermissionsStatus)backgroundRefreshPermissionStatus
229
++ (RNPermissionsStatus)backgroundRefresh
229 230
 {
230 231
     int status = [[UIApplication sharedApplication] backgroundRefreshStatus];
231 232
     switch (status) {

+ 11
- 0
ReactNativePermissions.ios.js View File

@@ -40,6 +40,17 @@ class ReactNativePermissions {
40 40
 		}
41 41
 	}
42 42
 
43
+	requestPermission(permission, type) {
44
+		switch (permission) {
45
+			case 'location':
46
+				return RNPermissions.requestLocation(type)
47
+			case 'notification':
48
+				return RNPermissions.requestNotification(type)
49
+			case 'bluetooth':
50
+				return RNPermissions.requestBluetooth();
51
+		}
52
+	}
53
+
43 54
 	//recursive funciton to chain a promises for a list of permissions
44 55
 	checkMultiplePermissions(permissions) {
45 56
 		let i = permissions.length

+ 50
- 8
ReactNativePermissions.m View File

@@ -17,6 +17,7 @@
17 17
 #import "RCTConvert+RNPermissionsStatus.h"
18 18
 
19 19
 #import "PermissionsChecker.h"
20
+#import "PermissionsAsker.h"
20 21
 
21 22
 @interface ReactNativePermissions()
22 23
 @end
@@ -39,25 +40,66 @@ RCT_EXPORT_MODULE();
39 40
 
40 41
 - (NSDictionary *)constantsToExport
41 42
 {
42
-    return @{ @"StatusUndetermined" : @(RNPermissionsStatusUndetermined),
43
-              @"StatusDenied" : @(RNPermissionsStatusDenied),
44
-              @"StatusAuthorized" : @(RNPermissionsStatusAuthorized),
45
-              @"StatusRestricted" : @(RNPermissionsStatusRestricted)};
43
+    return @{ @"PermissionTypes" : @[
44
+                      @"location",
45
+                      @"camera",
46
+                      @"microphone",
47
+                      @"photo",
48
+                      @"contacts",
49
+                      @"event",
50
+                      @"reminder",
51
+                      @"bluetooth",
52
+                      @"notification",
53
+                      @"backgroundRefresh",
54
+                      ]};
46 55
 };
47 56
 
48 57
 
49
-RCT_REMAP_METHOD(canOpenSettings, canOpenSettings:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
58
+RCT_REMAP_METHOD(canOpenSettings, canOpenSettings:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
59
+{
50 60
     resolve(@([PermissionsChecker canOpenSettings]));
51 61
 }
52
-RCT_EXPORT_METHOD(openSettings) {
62
+
63
+RCT_EXPORT_METHOD(openSettings)
64
+{
53 65
     [PermissionsChecker openSettings];
54 66
 }
55
-RCT_REMAP_METHOD(getPermissionStatus, getPermissionStatus:(NSString *)permission resolve:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
56
-    SEL s = NSSelectorFromString([NSString stringWithFormat:@"%@PermissionStatus", permission]);
67
+
68
+RCT_REMAP_METHOD(getPermissionStatus, getPermissionStatus:(NSString *)permission resolve:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
69
+{
70
+    SEL s = NSSelectorFromString(permission);
57 71
     RNPermissionsStatus status = (RNPermissionsStatus)[PermissionsChecker performSelector:s];
58 72
     resolve([self stringForStatus:status]);
59 73
 }
60 74
 
75
+RCT_EXPORT_METHOD(requestLocation:(NSString *)type)
76
+{
77
+    [[PermissionsAsker sharedInstance] location:type];
78
+}
79
+
80
+RCT_REMAP_METHOD(requestNotification, requestNotification:(NSArray *)typeStrings resolve:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
81
+{
82
+    UIUserNotificationType types;
83
+    if ([typeStrings containsObject:@"alert"])
84
+        types = types | UIUserNotificationTypeAlert;
85
+    
86
+    if ([typeStrings containsObject:@"badge"])
87
+        types = types | UIUserNotificationTypeBadge;
88
+    
89
+    if ([typeStrings containsObject:@"sound"])
90
+        types = types | UIUserNotificationTypeSound;
91
+
92
+    [[PermissionsAsker sharedInstance] notification:types completionHandler:^(RNPermissionsStatus status) {
93
+        resolve([self stringForStatus:status]);
94
+    }];
95
+}
96
+
97
+
98
+
99
+RCT_EXPORT_METHOD(requestBluetooth) {
100
+    [[PermissionsAsker sharedInstance] bluetooth];
101
+}
102
+
61 103
 - (NSString *)stringForStatus:(RNPermissionsStatus) status{
62 104
     switch (status) {
63 105
         case RNPermissionsStatusAuthorized:

+ 6
- 0
ReactNativePermissions.xcodeproj/project.pbxproj View File

@@ -7,6 +7,7 @@
7 7
 	objects = {
8 8
 
9 9
 /* Begin PBXBuildFile section */
10
+		9D6F44381D2E604500BF17F4 /* PermissionsAsker.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D6F44371D2E604500BF17F4 /* PermissionsAsker.m */; };
10 11
 		9D8FB2701D2D68C500AAFC55 /* PermissionsChecker.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D8FB26F1D2D68C500AAFC55 /* PermissionsChecker.m */; };
11 12
 		9DE8D2821CA3188D009CE8CC /* ReactNativePermissions.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DE8D2811CA3188D009CE8CC /* ReactNativePermissions.m */; };
12 13
 		9DE8D28B1CA31E95009CE8CC /* RCTConvert+RNPermissionsStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DE8D28A1CA31E95009CE8CC /* RCTConvert+RNPermissionsStatus.m */; };
@@ -26,6 +27,8 @@
26 27
 
27 28
 /* Begin PBXFileReference section */
28 29
 		9D23B34F1C767B80008B4819 /* libReactNativePermissions.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libReactNativePermissions.a; sourceTree = BUILT_PRODUCTS_DIR; };
30
+		9D6F44361D2E604500BF17F4 /* PermissionsAsker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PermissionsAsker.h; sourceTree = SOURCE_ROOT; };
31
+		9D6F44371D2E604500BF17F4 /* PermissionsAsker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PermissionsAsker.m; sourceTree = SOURCE_ROOT; };
29 32
 		9D8FB26E1D2D68C500AAFC55 /* PermissionsChecker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PermissionsChecker.h; sourceTree = SOURCE_ROOT; };
30 33
 		9D8FB26F1D2D68C500AAFC55 /* PermissionsChecker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PermissionsChecker.m; sourceTree = SOURCE_ROOT; };
31 34
 		9DE8D2801CA31888009CE8CC /* ReactNativePermissions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ReactNativePermissions.h; sourceTree = SOURCE_ROOT; };
@@ -68,6 +71,8 @@
68 71
 				9DE8D28A1CA31E95009CE8CC /* RCTConvert+RNPermissionsStatus.m */,
69 72
 				9D8FB26E1D2D68C500AAFC55 /* PermissionsChecker.h */,
70 73
 				9D8FB26F1D2D68C500AAFC55 /* PermissionsChecker.m */,
74
+				9D6F44361D2E604500BF17F4 /* PermissionsAsker.h */,
75
+				9D6F44371D2E604500BF17F4 /* PermissionsAsker.m */,
71 76
 				9DE8D2801CA31888009CE8CC /* ReactNativePermissions.h */,
72 77
 				9DE8D2811CA3188D009CE8CC /* ReactNativePermissions.m */,
73 78
 			);
@@ -133,6 +138,7 @@
133 138
 				9DE8D28B1CA31E95009CE8CC /* RCTConvert+RNPermissionsStatus.m in Sources */,
134 139
 				9D8FB2701D2D68C500AAFC55 /* PermissionsChecker.m in Sources */,
135 140
 				9DE8D2821CA3188D009CE8CC /* ReactNativePermissions.m in Sources */,
141
+				9D6F44381D2E604500BF17F4 /* PermissionsAsker.m in Sources */,
136 142
 			);
137 143
 			runOnlyForDeploymentPostprocessing = 0;
138 144
 		};