ReactNativePermissions.m 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. //
  2. // ReactNativePermissions.m
  3. // ReactNativePermissions
  4. //
  5. // Created by Yonah Forst on 18/02/16.
  6. // Copyright © 2016 Yonah Forst. All rights reserved.
  7. //
  8. @import Contacts;
  9. #import "ReactNativePermissions.h"
  10. #import "RCTBridge.h"
  11. #import "RCTConvert.h"
  12. #import "RCTEventDispatcher.h"
  13. #import "RCTConvert+RNPermissionsStatus.h"
  14. #import <AddressBook/AddressBook.h>
  15. #import <AssetsLibrary/AssetsLibrary.h>
  16. #import <EventKit/EventKit.h>
  17. #import <CoreLocation/CoreLocation.h>
  18. #import <AVFoundation/AVFoundation.h>
  19. #import <CoreBluetooth/CoreBluetooth.h>
  20. #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0
  21. @import Contacts;
  22. @import Photos;
  23. #endif
  24. @interface ReactNativePermissions()
  25. @end
  26. @implementation ReactNativePermissions
  27. RCT_EXPORT_MODULE();
  28. @synthesize bridge = _bridge;
  29. #pragma mark Initialization
  30. - (instancetype)init
  31. {
  32. if (self = [super init]) {
  33. }
  34. return self;
  35. }
  36. - (NSDictionary *)constantsToExport
  37. {
  38. return @{ @"StatusUndetermined" : @(RNPermissionsStatusUndetermined),
  39. @"StatusDenied" : @(RNPermissionsStatusDenied),
  40. @"StatusAuthorized" : @(RNPermissionsStatusAuthorized),
  41. @"StatusRestricted" : @(RNPermissionsStatusRestricted)};
  42. };
  43. - (BOOL)canOpenSettings {
  44. return UIApplicationOpenSettingsURLString != nil;
  45. }
  46. RCT_REMAP_METHOD(canOpenSettings, canOpenSettings:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  47. {
  48. resolve(@([self canOpenSettings]));
  49. }
  50. RCT_EXPORT_METHOD(openSettings)
  51. {
  52. if ([self canOpenSettings]) {
  53. NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
  54. [[UIApplication sharedApplication] openURL:url];
  55. }
  56. }
  57. RCT_REMAP_METHOD(locationPermissionStatus, locationPermission:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  58. {
  59. int status = [CLLocationManager authorizationStatus];
  60. switch (status) {
  61. case kCLAuthorizationStatusAuthorizedAlways:
  62. case kCLAuthorizationStatusAuthorizedWhenInUse:
  63. return resolve(@(RNPermissionsStatusAuthorized));
  64. case kCLAuthorizationStatusDenied:
  65. return resolve(@(RNPermissionsStatusDenied));
  66. case kCLAuthorizationStatusRestricted:
  67. return resolve(@(RNPermissionsStatusRestricted));
  68. default:
  69. return resolve(@(RNPermissionsStatusUndetermined));
  70. }
  71. }
  72. RCT_REMAP_METHOD(cameraPermissionStatus, cameraPermission:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  73. {
  74. int status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
  75. switch (status) {
  76. case AVAuthorizationStatusAuthorized:
  77. return resolve(@(RNPermissionsStatusAuthorized));
  78. case AVAuthorizationStatusDenied:
  79. return resolve(@(RNPermissionsStatusDenied));
  80. case AVAuthorizationStatusRestricted:
  81. return resolve(@(RNPermissionsStatusRestricted));
  82. default:
  83. return resolve(@(RNPermissionsStatusUndetermined));
  84. }
  85. }
  86. RCT_REMAP_METHOD(microphonePermissionStatus, microphonePermission:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  87. {
  88. int status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
  89. switch (status) {
  90. case AVAuthorizationStatusAuthorized:
  91. return resolve(@(RNPermissionsStatusAuthorized));
  92. case AVAuthorizationStatusDenied:
  93. return resolve(@(RNPermissionsStatusDenied));
  94. case AVAuthorizationStatusRestricted:
  95. return resolve(@(RNPermissionsStatusRestricted));
  96. default:
  97. return resolve(@(RNPermissionsStatusUndetermined));
  98. }
  99. }
  100. RCT_REMAP_METHOD(photoPermissionStatus, photoPermission:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  101. {
  102. #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0
  103. int status = [PHPhotoLibrary authorizationStatus];
  104. switch (status) {
  105. case PHAuthorizationStatusAuthorized:
  106. return resolve(@(RNPermissionsStatusAuthorized));
  107. case PHAuthorizationStatusDenied:
  108. return resolve(@(RNPermissionsStatusDenied));
  109. case PHAuthorizationStatusRestricted:
  110. return resolve(@(RNPermissionsStatusRestricted));
  111. default:
  112. return resolve(@(RNPermissionsStatusUndetermined));
  113. }
  114. #else
  115. int status = ABAddressBookGetAuthorizationStatus();
  116. switch (status) {
  117. case kABAuthorizationStatusAuthorized:
  118. return resolve(@(RNPermissionsStatusAuthorized));
  119. case kABAuthorizationStatusDenied:
  120. return resolve(@(RNPermissionsStatusDenied));
  121. case kABAuthorizationStatusRestricted:
  122. return resolve(@(RNPermissionsStatusRestricted));
  123. default:
  124. return resolve(@(RNPermissionsStatusUndetermined));
  125. }
  126. #endif
  127. }
  128. RCT_REMAP_METHOD(contactsPermissionStatus, contactsPermission:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  129. {
  130. #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0
  131. int status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
  132. switch (status) {
  133. case CNAuthorizationStatusAuthorized:
  134. return resolve(@(RNPermissionsStatusAuthorized));
  135. case CNAuthorizationStatusDenied:
  136. return resolve(@(RNPermissionsStatusDenied));
  137. case CNAuthorizationStatusRestricted:
  138. return resolve(@(RNPermissionsStatusRestricted));
  139. default:
  140. return resolve(@(RNPermissionsStatusUndetermined));
  141. }
  142. #else
  143. int status = ABAddressBookGetAuthorizationStatus();
  144. switch (status) {
  145. case kABAuthorizationStatusAuthorized:
  146. return resolve(@(RNPermissionsStatusAuthorized));
  147. case kABAuthorizationStatusDenied:
  148. return resolve(@(RNPermissionsStatusDenied));
  149. case kABAuthorizationStatusRestricted:
  150. return resolve(@(RNPermissionsStatusRestricted));
  151. default:
  152. return resolve(@(RNPermissionsStatusUndetermined));
  153. }
  154. #endif
  155. }
  156. RCT_REMAP_METHOD(eventPermissionStatus, eventPermission:(NSString *)eventString resolve:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  157. {
  158. int status;
  159. if ([eventString isEqualToString:@"reminder"]) {
  160. status = [EKEventStore authorizationStatusForEntityType:EKEntityTypeReminder];
  161. } else if ([eventString isEqualToString:@"event"]) {
  162. status = [EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent];
  163. } else {
  164. NSError *error = [NSError errorWithDomain:@"invalidOption" code:-1 userInfo:NULL];
  165. return reject(@"-1", @"Type must be 'reminder' or 'event'", error);
  166. }
  167. switch (status) {
  168. case EKAuthorizationStatusAuthorized:
  169. return resolve(@(RNPermissionsStatusAuthorized));
  170. case EKAuthorizationStatusDenied:
  171. return resolve(@(RNPermissionsStatusDenied));
  172. case EKAuthorizationStatusRestricted:
  173. return resolve(@(RNPermissionsStatusRestricted));
  174. default:
  175. return resolve(@(RNPermissionsStatusUndetermined));
  176. }
  177. }
  178. RCT_REMAP_METHOD(bluetoothPermissionStatus, bluetoothPermission:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  179. {
  180. int status = [CBPeripheralManager authorizationStatus];
  181. switch (status) {
  182. case CBPeripheralManagerAuthorizationStatusAuthorized:
  183. return resolve(@(RNPermissionsStatusAuthorized));
  184. case CBPeripheralManagerAuthorizationStatusDenied:
  185. return resolve(@(RNPermissionsStatusDenied));
  186. case CBPeripheralManagerAuthorizationStatusRestricted:
  187. return resolve(@(RNPermissionsStatusRestricted));
  188. default:
  189. return resolve(@(RNPermissionsStatusUndetermined));
  190. }
  191. }
  192. //problem here is that we can we can't know if the user was never prompted for permission, or if they were prompted and deneied
  193. RCT_REMAP_METHOD(notificationPermissionStatus, notificationPermission:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  194. {
  195. if ([[UIApplication sharedApplication] respondsToSelector:@selector(isRegisteredForRemoteNotifications)]) {
  196. // iOS8+
  197. BOOL isRegistered = [[UIApplication sharedApplication] isRegisteredForRemoteNotifications];
  198. BOOL isEnabled = [[[UIApplication sharedApplication] currentUserNotificationSettings] types] != UIUserNotificationTypeNone;
  199. if (isRegistered || isEnabled) {
  200. return resolve(@(isEnabled ? RNPermissionsStatusAuthorized : RNPermissionsStatusDenied));
  201. }
  202. else {
  203. return resolve(@(RNPermissionsStatusUndetermined));
  204. }
  205. } else {
  206. #if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0
  207. if ([[UIApplication sharedApplication] enabledRemoteNotificationTypes] == UIRemoteNotificationTypeNone) {
  208. return resolve(@(RNPermissionsStatusUndetermined));
  209. }
  210. else {
  211. return resolve(@(RNPermissionsStatusAuthorized));
  212. }
  213. #else
  214. return resolve(@(RNPermissionsStatusUndetermined));
  215. #endif
  216. }
  217. }
  218. RCT_REMAP_METHOD(backgroundRefreshStatus, backgroundRefresh:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  219. {
  220. int status = [[UIApplication sharedApplication] backgroundRefreshStatus];
  221. switch (status) {
  222. case UIBackgroundRefreshStatusAvailable:
  223. return resolve(@(RNPermissionsStatusAuthorized));
  224. case UIBackgroundRefreshStatusDenied:
  225. return resolve(@(RNPermissionsStatusDenied));
  226. case UIBackgroundRefreshStatusRestricted:
  227. return resolve(@(RNPermissionsStatusRestricted));
  228. default:
  229. return resolve(@(RNPermissionsStatusUndetermined));
  230. }
  231. }
  232. @end