Browse Source

refactor. finished adding request permissions

Yonah Forst 9 years ago
parent
commit
58e2d528f7

+ 0 - 26
PermissionsAsker.h

@@ -1,26 +0,0 @@
-//
-//  PermissionsAsker.h
-//  ReactNativePermissions
-//
-//  Created by Yonah Forst on 07/07/16.
-//  Copyright © 2016 Yonah Forst. All rights reserved.
-//
-
-#import <Foundation/Foundation.h>
-#import <UIKit/UIKit.h>
-#import "RCTConvert+RNPermissionsStatus.h"
-
-@interface PermissionsAsker : NSObject
-
-+ (instancetype)sharedInstance;
-- (void)location:(NSString *)type;
-- (void)notification:(UIUserNotificationType)types completionHandler:(void (^)(RNPermissionsStatus))completionHandler;
-- (void)bluetooth;
-- (void)camera;
-- (void)microphone;
-- (void)photo;
-- (void)contacts;
-- (void)event;
-- (void)reminder;
-- (void)backgroundRefresh;
-@end

+ 0 - 114
PermissionsAsker.m

@@ -1,114 +0,0 @@
-//
-//  PermissionsAsker.m
-//  ReactNativePermissions
-//
-//  Created by Yonah Forst on 07/07/16.
-//  Copyright © 2016 Yonah Forst. All rights reserved.
-//
-
-#import "PermissionsAsker.h"
-
-#import <AddressBook/AddressBook.h>
-#import <AssetsLibrary/AssetsLibrary.h>
-#import <EventKit/EventKit.h>
-#import <CoreLocation/CoreLocation.h>
-#import <AVFoundation/AVFoundation.h>
-#import <CoreBluetooth/CoreBluetooth.h>
-
-#import "PermissionsChecker.h"
-
-static PermissionsAsker *__sharedInstance;
-
-@interface PermissionsAsker() <CLLocationManagerDelegate, CBPeripheralManagerDelegate>
-@property (strong, nonatomic) CLLocationManager *locationManager;
-@property (strong, nonatomic) CBPeripheralManager *peripheralManager;
-@property (copy) void (^notificationCompletionBlock)(RNPermissionsStatus);
-
-@end
-
-
-@implementation PermissionsAsker
-
-+ (instancetype) sharedInstance
-{
-    static dispatch_once_t onceToken;
-    dispatch_once(&onceToken, ^{
-        __sharedInstance = [[PermissionsAsker alloc] init];
-    });
-    return __sharedInstance;
-}
-
-
-- (void)location:(NSString *)type
-{
-    self.locationManager = [[CLLocationManager alloc] init];
-    self.locationManager.delegate = self;
-    if ([type isEqualToString:@"always"]) {
-        [self.locationManager requestAlwaysAuthorization];
-    } else {
-        [self.locationManager requestWhenInUseAuthorization];
-    }
-}
-
-- (void)notification:(UIUserNotificationType)types completionHandler:(void (^)(RNPermissionsStatus))completionHandler
-{
-    BOOL didAskForPermission = [[NSUserDefaults standardUserDefaults] boolForKey:@"DidAskForNotifications"];
-    if (!didAskForPermission) {
-        self.notificationCompletionBlock = completionHandler;
-        
-        [[NSNotificationCenter defaultCenter] addObserver:self
-                                                 selector:@selector(applicationDidBecomeActive)
-                                                     name:UIApplicationDidBecomeActiveNotification
-                                                   object:nil];
-        
-        if ([[UIApplication sharedApplication] respondsToSelector:@selector(isRegisteredForRemoteNotifications)]) {
-            // iOS8+
-            UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
-            [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
-            [[UIApplication sharedApplication] registerForRemoteNotifications];
-        } else {
-            [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationType)types];
-        }
-        
-        [[NSUserDefaults standardUserDefaults] setBool:YES
-                                                forKey:@"DidAskForNotifications"];
-        [[NSUserDefaults standardUserDefaults] synchronize];
-    } else {
-        RNPermissionsStatus status = [PermissionsChecker notification];
-        completionHandler(status);
-    }
-
-}
-
-- (void)applicationDidBecomeActive
-{
-    [[NSNotificationCenter defaultCenter] removeObserver:self
-                                                    name:UIApplicationDidBecomeActiveNotification
-                                                  object:nil];
-
-    //for some reason, checking permission right away returns denied. need to wait a tiny bit
-    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
-        RNPermissionsStatus status = [PermissionsChecker notification];
-        self.notificationCompletionBlock(status);
-        self.notificationCompletionBlock = nil;
-    });
-}
-
-- (void)bluetooth
-{
-    self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];
-    [self.peripheralManager startAdvertising:@{}];
-}
-
-- (void) peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheralManager
-{
-    if (self.peripheralManager) {
-        [self.peripheralManager stopAdvertising];
-        self.peripheralManager = nil;
-    }
-}
-
-
-
-
-@end

+ 0 - 25
PermissionsChecker.h

@@ -1,25 +0,0 @@
-//
-//  PermissionsChecker
-//  PermissionsChecker
-//
-//  Created by Yonah Forst on 18/02/16.
-//  Copyright © 2016 Yonah Forst. All rights reserved.
-//
-#import "RCTConvert+RNPermissionsStatus.h"
-
-@interface PermissionsChecker : NSObject
-
-+ (BOOL)canOpenSettings;
-+ (void)openSettings;
-+ (RNPermissionsStatus)location;
-+ (RNPermissionsStatus)camera;
-+ (RNPermissionsStatus)microphone;
-+ (RNPermissionsStatus)photo;
-+ (RNPermissionsStatus)contacts;
-+ (RNPermissionsStatus)event;
-+ (RNPermissionsStatus)reminder;
-+ (RNPermissionsStatus)bluetooth;
-+ (RNPermissionsStatus)notification;
-+ (RNPermissionsStatus)backgroundRefresh;
-
-@end

+ 0 - 244
PermissionsChecker.m

@@ -1,244 +0,0 @@
-//
-//  PermissionsChecker
-//  PermissionsChecker
-//
-//  Created by Yonah Forst on 18/02/16.
-//  Copyright © 2016 Yonah Forst. All rights reserved.
-//
-
-@import Contacts;
-
-#import "PermissionsChecker.h"
-
-#import <AddressBook/AddressBook.h>
-#import <AssetsLibrary/AssetsLibrary.h>
-#import <EventKit/EventKit.h>
-#import <CoreLocation/CoreLocation.h>
-#import <AVFoundation/AVFoundation.h>
-#import <CoreBluetooth/CoreBluetooth.h>
-
-#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0
-@import Contacts;
-@import Photos;
-#endif
-
-
-@interface PermissionsChecker()
-@end
-
-@implementation PermissionsChecker
-
-+ (BOOL)canOpenSettings
-{
-    return UIApplicationOpenSettingsURLString != nil;
-}
-
-+ (void)openSettings
-{
-    if ([self canOpenSettings]) {
-        NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
-        [[UIApplication sharedApplication] openURL:url];
-    }
-}
-
-
-+ (RNPermissionsStatus)location
-{
-    int status = [CLLocationManager authorizationStatus];
-    switch (status) {
-        case kCLAuthorizationStatusAuthorizedAlways:
-        case kCLAuthorizationStatusAuthorizedWhenInUse:
-            return RNPermissionsStatusAuthorized;
-        case kCLAuthorizationStatusDenied:
-            return RNPermissionsStatusDenied;
-        case kCLAuthorizationStatusRestricted:
-            return RNPermissionsStatusRestricted;
-        default:
-            return RNPermissionsStatusUndetermined;
-    }
-}
-
-
-
-
-+ (RNPermissionsStatus)camera
-{
-    int status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
-    switch (status) {
-        case AVAuthorizationStatusAuthorized:
-            return RNPermissionsStatusAuthorized;
-        case AVAuthorizationStatusDenied:
-            return RNPermissionsStatusDenied;
-        case AVAuthorizationStatusRestricted:
-            return RNPermissionsStatusRestricted;
-        default:
-            return RNPermissionsStatusUndetermined;
-    }
-}
-
-+ (RNPermissionsStatus)microphone
-{
-    int status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
-    switch (status) {
-        case AVAuthorizationStatusAuthorized:
-            return RNPermissionsStatusAuthorized;
-        case AVAuthorizationStatusDenied:
-            return RNPermissionsStatusDenied;
-        case AVAuthorizationStatusRestricted:
-            return RNPermissionsStatusRestricted;
-        default:
-            return RNPermissionsStatusUndetermined;
-    }
-}
-
-+ (RNPermissionsStatus)photo
-{
-#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0
-    int status = [PHPhotoLibrary authorizationStatus];
-    switch (status) {
-        case PHAuthorizationStatusAuthorized:
-            return RNPermissionsStatusAuthorized;
-        case PHAuthorizationStatusDenied:
-            return RNPermissionsStatusDenied;
-        case PHAuthorizationStatusRestricted:
-            return RNPermissionsStatusRestricted;
-        default:
-            return RNPermissionsStatusUndetermined;
-    }
-#else
-    int status = ABAddressBookGetAuthorizationStatus();
-    switch (status) {
-        case kABAuthorizationStatusAuthorized:
-            return RNPermissionsStatusAuthorized;
-        case kABAuthorizationStatusDenied:
-            return RNPermissionsStatusDenied;
-        case kABAuthorizationStatusRestricted:
-            return RNPermissionsStatusRestricted;
-        default:
-            return RNPermissionsStatusUndetermined;
-    }
-#endif
-}
-
-
-+ (RNPermissionsStatus)contacts
-{
-#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0
-    int status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
-    switch (status) {
-        case CNAuthorizationStatusAuthorized:
-            return RNPermissionsStatusAuthorized;
-        case CNAuthorizationStatusDenied:
-            return RNPermissionsStatusDenied;
-        case CNAuthorizationStatusRestricted:
-            return RNPermissionsStatusRestricted;
-        default:
-            return RNPermissionsStatusUndetermined;
-    }
-#else
-    int status = ABAddressBookGetAuthorizationStatus();
-    switch (status) {
-        case kABAuthorizationStatusAuthorized:
-            return RNPermissionsStatusAuthorized;
-        case kABAuthorizationStatusDenied:
-            return RNPermissionsStatusDenied;
-        case kABAuthorizationStatusRestricted:
-            return RNPermissionsStatusRestricted;
-        default:
-            return RNPermissionsStatusUndetermined;
-    }
-#endif
-}
-
-
-+ (RNPermissionsStatus)event
-{
-    int status = [EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent];
-    switch (status) {
-        case EKAuthorizationStatusAuthorized:
-            return RNPermissionsStatusAuthorized;
-        case EKAuthorizationStatusDenied:
-            return RNPermissionsStatusDenied;
-        case EKAuthorizationStatusRestricted:
-            return RNPermissionsStatusRestricted;
-        default:
-            return RNPermissionsStatusUndetermined;
-    }
-}
-
-+ (RNPermissionsStatus)reminder
-{
-    int status = [EKEventStore authorizationStatusForEntityType:EKEntityTypeReminder];
-    switch (status) {
-        case EKAuthorizationStatusAuthorized:
-            return RNPermissionsStatusAuthorized;
-        case EKAuthorizationStatusDenied:
-            return RNPermissionsStatusDenied;
-        case EKAuthorizationStatusRestricted:
-            return RNPermissionsStatusRestricted;
-        default:
-            return RNPermissionsStatusUndetermined;
-    }
-}
-
-
-+ (RNPermissionsStatus)bluetooth
-{
-    int status = [CBPeripheralManager authorizationStatus];
-    switch (status) {
-        case CBPeripheralManagerAuthorizationStatusAuthorized:
-            return RNPermissionsStatusAuthorized;
-        case CBPeripheralManagerAuthorizationStatusDenied:
-            return RNPermissionsStatusDenied;
-        case CBPeripheralManagerAuthorizationStatusRestricted:
-            return RNPermissionsStatusRestricted;
-        default:
-            return RNPermissionsStatusUndetermined;
-    }
-}
-
-//problem here is that we can only return Authorized or Undetermined
-+ (RNPermissionsStatus)notification
-{
-    BOOL didAskForPermission = [[NSUserDefaults standardUserDefaults] boolForKey:@"DidAskForNotifications"];
-
-    if (didAskForPermission) {
-        if ([[UIApplication sharedApplication] respondsToSelector:@selector(isRegisteredForRemoteNotifications)]) {
-            // iOS8+
-            BOOL isRegistered = [[UIApplication sharedApplication] isRegisteredForRemoteNotifications];
-            BOOL isEnabled = [[[UIApplication sharedApplication] currentUserNotificationSettings] types] != UIUserNotificationTypeNone;
-            if (isRegistered || isEnabled) {
-                return isEnabled ? RNPermissionsStatusAuthorized : RNPermissionsStatusDenied;
-            }
-            else {
-                return RNPermissionsStatusDenied;
-            }
-        } else {
-            if ([[UIApplication sharedApplication] enabledRemoteNotificationTypes] == UIRemoteNotificationTypeNone) {
-                return RNPermissionsStatusDenied;
-            }
-            else {
-                return RNPermissionsStatusAuthorized;
-            }
-        }
-    } else {
-        return RNPermissionsStatusUndetermined;
-    }
-}
-
-+ (RNPermissionsStatus)backgroundRefresh
-{
-    int status = [[UIApplication sharedApplication] backgroundRefreshStatus];
-    switch (status) {
-        case UIBackgroundRefreshStatusAvailable:
-            return RNPermissionsStatusAuthorized;
-        case UIBackgroundRefreshStatusDenied:
-            return RNPermissionsStatusDenied;
-        case UIBackgroundRefreshStatusRestricted:
-            return RNPermissionsStatusRestricted;
-        default:
-            return RNPermissionsStatusUndetermined;
-    }
-}
-
-@end

+ 33 - 0
RCTConvert+RNPStatus.h

@@ -0,0 +1,33 @@
+//
+//  RCTConvert+RNPStatus
+//  ReactNativePermissions
+//
+//  Created by Yonah Forst on 23/03/16.
+//  Copyright © 2016 Yonah Forst. All rights reserved.
+//
+
+#import "RCTConvert.h"
+
+static NSString* RNPStatusUndetermined = @"undetermined";
+static NSString* RNPStatusDenied = @"denied";
+static NSString* RNPStatusAuthorized = @"authorized";
+static NSString* RNPStatusRestricted = @"restricted";
+
+
+typedef NS_ENUM(NSInteger, RNPType) {
+    RNPTypeUnknown,
+    RNPTypeLocation,
+    RNPTypeCamera,
+    RNPTypeMicrophone,
+    RNPTypePhoto,
+    RNPTypeContacts,
+    RNPTypeEvent,
+    RNPTypeReminder,
+    RNPTypeBluetooth,
+    RNPTypeNotification,
+    RNPTypeBackgroundRefresh
+};
+
+@interface RCTConvert (RNPStatus)
+
+@end

+ 27 - 0
RCTConvert+RNPStatus.m

@@ -0,0 +1,27 @@
+//
+//  RCTConvert+RNPermissionsStatus.m
+//  ReactNativePermissions
+//
+//  Created by Yonah Forst on 23/03/16.
+//  Copyright © 2016 Yonah Forst. All rights reserved.
+//
+
+#import "RCTConvert+RNPStatus.h"
+
+@implementation RCTConvert (RNPStatus)
+
+
+RCT_ENUM_CONVERTER(RNPType, (@{ @"location" : @(RNPTypeLocation),
+                                @"camera" : @(RNPTypeCamera),
+                                @"microphone" : @(RNPTypeMicrophone),
+                                @"photo" : @(RNPTypePhoto),
+                                @"contacts" : @(RNPTypeContacts),
+                                @"event" : @(RNPTypeEvent),
+                                @"reminder" : @(RNPTypeReminder),
+                                @"bluetooth" : @(RNPTypeBluetooth),
+                                @"notification" : @(RNPTypeNotification),
+                                @"backgroundRefresh": @(RNPTypeBackgroundRefresh)
+                                }),
+                                RNPTypeUnknown, integerValue)
+
+@end

+ 0 - 20
RCTConvert+RNPermissionsStatus.h

@@ -1,20 +0,0 @@
-//
-//  RCTConvert+RNPermissionsStatus.h
-//  ReactNativePermissions
-//
-//  Created by Yonah Forst on 23/03/16.
-//  Copyright © 2016 Yonah Forst. All rights reserved.
-//
-
-#import "RCTConvert.h"
-
-typedef NS_ENUM(NSInteger, RNPermissionsStatus) {
-    RNPermissionsStatusUndetermined,
-    RNPermissionsStatusDenied,
-    RNPermissionsStatusAuthorized,
-    RNPermissionsStatusRestricted
-};
-
-@interface RCTConvert (RNPermissionsStatus)
-
-@end

+ 0 - 21
RCTConvert+RNPermissionsStatus.m

@@ -1,21 +0,0 @@
-//
-//  RCTConvert+RNPermissionsStatus.m
-//  ReactNativePermissions
-//
-//  Created by Yonah Forst on 23/03/16.
-//  Copyright © 2016 Yonah Forst. All rights reserved.
-//
-
-#import "RCTConvert+RNPermissionsStatus.h"
-
-@implementation RCTConvert (RNPermissionsStatus)
-
-
-RCT_ENUM_CONVERTER(RNPermissionsStatus, (@{ @"StatusUndetermined" : @(RNPermissionsStatusUndetermined),
-                                             @"StatusDenied" : @(RNPermissionsStatusDenied),
-                                             @"StatusAuthorized" : @(RNPermissionsStatusAuthorized),
-                                             @"StatusRestricted" : @(RNPermissionsStatusRestricted)}),
-                   RNPermissionsStatusUndetermined, integerValue)
-
-
-@end

+ 25 - 24
ReactNativePermissions.ios.js

@@ -3,25 +3,6 @@
 var React = require('react-native');
 var RNPermissions = React.NativeModules.ReactNativePermissions;
 
-const permissionTypes = [
-	'location',
-	'camera',
-	'microphone',
-	'photo',
-	'contacts',
-	'event',
-	'reminder',
-	'bluetooth',
-	'notification',
-	'backgroundRefresh',
-]
-
-const permissionStatus = [
-	'undetermined',
-	'denied',
-	'authorized',
-	'restricted'
-]
 
 class ReactNativePermissions {
 	canOpenSettings() {
@@ -32,8 +13,12 @@ class ReactNativePermissions {
 		return RNPermissions.openSettings()
 	}
 
+	getPermissionTypes() {
+		return RNPermissions.PermissionTypes;
+	}
+
 	getPermissionStatus(permission) {
-		if (permissionTypes.includes(permission)) {
+		if (RNPermissions.PermissionTypes.includes(permission)) {
 			return RNPermissions.getPermissionStatus(permission)
 		} else {
 			return Promise.reject(`ReactNativePermissions: ${permission} is not a valid permission type`)
@@ -42,12 +27,28 @@ class ReactNativePermissions {
 
 	requestPermission(permission, type) {
 		switch (permission) {
-			case 'location':
+			case "location":
 				return RNPermissions.requestLocation(type)
-			case 'notification':
-				return RNPermissions.requestNotification(type)
-			case 'bluetooth':
+			case "camera":
+				return RNPermissions.requestCamera();
+			case "microphone":
+				return RNPermissions.requestMicrophone();
+			case "photo":
+				return RNPermissions.requestPhoto();
+			case "contacts":
+				return RNPermissions.requestContacts();
+			case "event":
+				return RNPermissions.requestEvent();
+			case "reminder":
+				return RNPermissions.requestReminder();
+			case "bluetooth":
 				return RNPermissions.requestBluetooth();
+			case "notification":
+				return RNPermissions.requestNotification(type)
+			case "backgroundRefresh":
+				return Promise.reject('You cannot request backgroundRefresh')
+			default:
+				return Promise.reject('invalid type: ' + type)
 		}
 	}
 

+ 119 - 41
ReactNativePermissions.m

@@ -14,12 +14,19 @@
 #import "RCTConvert.h"
 #import "RCTEventDispatcher.h"
 
-#import "RCTConvert+RNPermissionsStatus.h"
-
-#import "PermissionsChecker.h"
-#import "PermissionsAsker.h"
+#import "RNPLocation.h"
+#import "RNPBluetooth.h"
+#import "RNPNotification.h"
+#import "RNPAudioVideo.h"
+#import "RNPEvent.h"
+#import "RNPPhoto.h"
+#import "RNPContacts.h"
+#import "RNPBackgroundRefresh.h"
 
 @interface ReactNativePermissions()
+@property (strong, nonatomic) RNPLocation *locationMgr;
+@property (strong, nonatomic) RNPNotification *notificationMgr;
+@property (strong, nonatomic) RNPBluetooth *bluetoothMgr;
 @end
 
 @implementation ReactNativePermissions
@@ -40,41 +47,83 @@ RCT_EXPORT_MODULE();
 
 - (NSDictionary *)constantsToExport
 {
-    return @{ @"PermissionTypes" : @[
-                      @"location",
-                      @"camera",
-                      @"microphone",
-                      @"photo",
-                      @"contacts",
-                      @"event",
-                      @"reminder",
-                      @"bluetooth",
-                      @"notification",
-                      @"backgroundRefresh",
-                      ]};
+    return @{ @"PermissionTypes" : @[ @"location",
+                                      @"camera",
+                                      @"microphone",
+                                      @"photo",
+                                      @"contacts",
+                                      @"event",
+                                      @"reminder",
+                                      @"bluetooth",
+                                      @"notification",
+                                      @"backgroundRefresh" ]
+              };
 };
 
 
 RCT_REMAP_METHOD(canOpenSettings, canOpenSettings:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
 {
-    resolve(@([PermissionsChecker canOpenSettings]));
+    resolve(@(UIApplicationOpenSettingsURLString != nil));
 }
 
 RCT_EXPORT_METHOD(openSettings)
 {
-    [PermissionsChecker openSettings];
+    if (@(UIApplicationOpenSettingsURLString != nil)) {
+        NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
+        [[UIApplication sharedApplication] openURL:url];
+    }
 }
 
-RCT_REMAP_METHOD(getPermissionStatus, getPermissionStatus:(NSString *)permission resolve:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
+RCT_REMAP_METHOD(getPermissionStatus, getPermissionStatus:(RNPType)type resolve:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
 {
-    SEL s = NSSelectorFromString(permission);
-    RNPermissionsStatus status = (RNPermissionsStatus)[PermissionsChecker performSelector:s];
-    resolve([self stringForStatus:status]);
+    NSString *status;
+    
+    switch (type) {
+            
+        case RNPTypeLocation:
+            status = [RNPLocation getStatus];
+            break;
+        case RNPTypeCamera:
+            status = [RNPAudioVideo getStatus:@"video"];
+            break;
+        case RNPTypeMicrophone:
+            status = [RNPAudioVideo getStatus:@"audio"];
+            break;
+        case RNPTypePhoto:
+            status = [RNPPhoto getStatus];
+            break;
+        case RNPTypeContacts:
+            status = [RNPContacts getStatus];
+            break;
+        case RNPTypeEvent:
+            status = [RNPEvent getStatus:@"event"];
+            break;
+        case RNPTypeReminder:
+            status = [RNPEvent getStatus:@"reminder"];
+            break;
+        case RNPTypeBluetooth:
+            status = [RNPBluetooth getStatus];
+            break;
+        case RNPTypeNotification:
+            status = [RNPNotification getStatus];
+            break;
+        case RNPTypeBackgroundRefresh:
+            status = [RNPBackgroundRefresh getStatus];
+            break;
+        default:
+            break;
+    }
+
+    resolve(status);
 }
 
-RCT_EXPORT_METHOD(requestLocation:(NSString *)type)
+RCT_REMAP_METHOD(requestLocation, requestLocation:(NSString *)type resolve:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
 {
-    [[PermissionsAsker sharedInstance] location:type];
+    if (self.locationMgr == nil) {
+        self.locationMgr = [[RNPLocation alloc] init];
+    }
+    
+    [self.locationMgr request:type completionHandler:resolve];
 }
 
 RCT_REMAP_METHOD(requestNotification, requestNotification:(NSArray *)typeStrings resolve:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
@@ -88,30 +137,59 @@ RCT_REMAP_METHOD(requestNotification, requestNotification:(NSArray *)typeStrings
     
     if ([typeStrings containsObject:@"sound"])
         types = types | UIUserNotificationTypeSound;
+    
+    
+    if (self.notificationMgr == nil) {
+        self.notificationMgr = [[RNPNotification alloc] init];
+    }
+    
+    [self.notificationMgr request:types completionHandler:resolve];
 
-    [[PermissionsAsker sharedInstance] notification:types completionHandler:^(RNPermissionsStatus status) {
-        resolve([self stringForStatus:status]);
-    }];
 }
 
 
+RCT_REMAP_METHOD(requestBluetooth, requestBluetooth:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
+{
+    if (self.bluetoothMgr == nil) {
+        self.bluetoothMgr = [[RNPBluetooth alloc] init];
+    }
+    
+    [self.bluetoothMgr request:resolve];
+}
 
-RCT_EXPORT_METHOD(requestBluetooth) {
-    [[PermissionsAsker sharedInstance] bluetooth];
+RCT_REMAP_METHOD(requestCamera, requestCamera:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
+{
+    [RNPAudioVideo request:@"video" completionHandler:resolve];
 }
 
-- (NSString *)stringForStatus:(RNPermissionsStatus) status{
-    switch (status) {
-        case RNPermissionsStatusAuthorized:
-            return @"authorized";
-        case RNPermissionsStatusDenied:
-            return @"denied";
-        case RNPermissionsStatusRestricted:
-            return @"restricted";
-        case RNPermissionsStatusUndetermined:
-        default:
-            return @"undetermined";
-    }
+RCT_REMAP_METHOD(requestMicrophone, requestMicrophone:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
+{
+    [RNPAudioVideo request:@"audio" completionHandler:resolve];
+}
+
+RCT_REMAP_METHOD(requestEvent, requestEvents:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
+{
+    [RNPEvent request:@"event" completionHandler:resolve];
+}
+
+RCT_REMAP_METHOD(requestReminder, requestReminders:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
+{
+    [RNPEvent request:@"reminder" completionHandler:resolve];
+}
+
+RCT_REMAP_METHOD(requestPhoto, requestPhoto:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
+{
+    [RNPPhoto request:resolve];
 }
 
+RCT_REMAP_METHOD(requestContacts, requestContacts:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
+{
+    [RNPContacts request:resolve];
+}
+
+
+
+
+
+
 @end

+ 63 - 19
ReactNativePermissions.xcodeproj/project.pbxproj

@@ -7,10 +7,16 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
-		9D6F44381D2E604500BF17F4 /* PermissionsAsker.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D6F44371D2E604500BF17F4 /* PermissionsAsker.m */; };
-		9D8FB2701D2D68C500AAFC55 /* PermissionsChecker.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D8FB26F1D2D68C500AAFC55 /* PermissionsChecker.m */; };
+		9D46283E1D34719100346A5B /* RNPAudioVideo.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D46282F1D34719100346A5B /* RNPAudioVideo.m */; };
+		9D46283F1D34719100346A5B /* RNPBackgroundRefresh.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D4628311D34719100346A5B /* RNPBackgroundRefresh.m */; };
+		9D4628401D34719100346A5B /* RNPBluetooth.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D4628331D34719100346A5B /* RNPBluetooth.m */; };
+		9D4628411D34719100346A5B /* RNPContacts.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D4628351D34719100346A5B /* RNPContacts.m */; };
+		9D4628421D34719100346A5B /* RNPEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D4628371D34719100346A5B /* RNPEvent.m */; };
+		9D4628431D34719100346A5B /* RNPLocation.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D4628391D34719100346A5B /* RNPLocation.m */; };
+		9D4628441D34719100346A5B /* RNPNotification.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D46283B1D34719100346A5B /* RNPNotification.m */; };
+		9D4628451D34719100346A5B /* RNPPhoto.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D46283D1D34719100346A5B /* RNPPhoto.m */; };
 		9DE8D2821CA3188D009CE8CC /* ReactNativePermissions.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DE8D2811CA3188D009CE8CC /* ReactNativePermissions.m */; };
-		9DE8D28B1CA31E95009CE8CC /* RCTConvert+RNPermissionsStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DE8D28A1CA31E95009CE8CC /* RCTConvert+RNPermissionsStatus.m */; };
+		9DE8D28B1CA31E95009CE8CC /* RCTConvert+RNPStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DE8D28A1CA31E95009CE8CC /* RCTConvert+RNPStatus.m */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXCopyFilesBuildPhase section */
@@ -27,14 +33,26 @@
 
 /* Begin PBXFileReference section */
 		9D23B34F1C767B80008B4819 /* libReactNativePermissions.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libReactNativePermissions.a; sourceTree = BUILT_PRODUCTS_DIR; };
-		9D6F44361D2E604500BF17F4 /* PermissionsAsker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PermissionsAsker.h; sourceTree = SOURCE_ROOT; };
-		9D6F44371D2E604500BF17F4 /* PermissionsAsker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PermissionsAsker.m; sourceTree = SOURCE_ROOT; };
-		9D8FB26E1D2D68C500AAFC55 /* PermissionsChecker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PermissionsChecker.h; sourceTree = SOURCE_ROOT; };
-		9D8FB26F1D2D68C500AAFC55 /* PermissionsChecker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PermissionsChecker.m; sourceTree = SOURCE_ROOT; };
+		9D46282E1D34719100346A5B /* RNPAudioVideo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNPAudioVideo.h; path = permissions/RNPAudioVideo.h; sourceTree = SOURCE_ROOT; };
+		9D46282F1D34719100346A5B /* RNPAudioVideo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNPAudioVideo.m; path = permissions/RNPAudioVideo.m; sourceTree = SOURCE_ROOT; };
+		9D4628301D34719100346A5B /* RNPBackgroundRefresh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNPBackgroundRefresh.h; path = permissions/RNPBackgroundRefresh.h; sourceTree = SOURCE_ROOT; };
+		9D4628311D34719100346A5B /* RNPBackgroundRefresh.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNPBackgroundRefresh.m; path = permissions/RNPBackgroundRefresh.m; sourceTree = SOURCE_ROOT; };
+		9D4628321D34719100346A5B /* RNPBluetooth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNPBluetooth.h; path = permissions/RNPBluetooth.h; sourceTree = SOURCE_ROOT; };
+		9D4628331D34719100346A5B /* RNPBluetooth.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNPBluetooth.m; path = permissions/RNPBluetooth.m; sourceTree = SOURCE_ROOT; };
+		9D4628341D34719100346A5B /* RNPContacts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNPContacts.h; path = permissions/RNPContacts.h; sourceTree = SOURCE_ROOT; };
+		9D4628351D34719100346A5B /* RNPContacts.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNPContacts.m; path = permissions/RNPContacts.m; sourceTree = SOURCE_ROOT; };
+		9D4628361D34719100346A5B /* RNPEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNPEvent.h; path = permissions/RNPEvent.h; sourceTree = SOURCE_ROOT; };
+		9D4628371D34719100346A5B /* RNPEvent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNPEvent.m; path = permissions/RNPEvent.m; sourceTree = SOURCE_ROOT; };
+		9D4628381D34719100346A5B /* RNPLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNPLocation.h; path = permissions/RNPLocation.h; sourceTree = SOURCE_ROOT; };
+		9D4628391D34719100346A5B /* RNPLocation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNPLocation.m; path = permissions/RNPLocation.m; sourceTree = SOURCE_ROOT; };
+		9D46283A1D34719100346A5B /* RNPNotification.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNPNotification.h; path = permissions/RNPNotification.h; sourceTree = SOURCE_ROOT; };
+		9D46283B1D34719100346A5B /* RNPNotification.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNPNotification.m; path = permissions/RNPNotification.m; sourceTree = SOURCE_ROOT; };
+		9D46283C1D34719100346A5B /* RNPPhoto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNPPhoto.h; path = permissions/RNPPhoto.h; sourceTree = SOURCE_ROOT; };
+		9D46283D1D34719100346A5B /* RNPPhoto.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNPPhoto.m; path = permissions/RNPPhoto.m; sourceTree = SOURCE_ROOT; };
 		9DE8D2801CA31888009CE8CC /* ReactNativePermissions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ReactNativePermissions.h; sourceTree = SOURCE_ROOT; };
-		9DE8D2811CA3188D009CE8CC /* ReactNativePermissions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReactNativePermissions.m; sourceTree = SOURCE_ROOT; };
-		9DE8D2891CA31E95009CE8CC /* RCTConvert+RNPermissionsStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RCTConvert+RNPermissionsStatus.h"; sourceTree = SOURCE_ROOT; };
-		9DE8D28A1CA31E95009CE8CC /* RCTConvert+RNPermissionsStatus.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RCTConvert+RNPermissionsStatus.m"; sourceTree = SOURCE_ROOT; };
+		9DE8D2811CA3188D009CE8CC /* ReactNativePermissions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ReactNativePermissions.m; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
+		9DE8D2891CA31E95009CE8CC /* RCTConvert+RNPStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "RCTConvert+RNPStatus.h"; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
+		9DE8D28A1CA31E95009CE8CC /* RCTConvert+RNPStatus.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = "RCTConvert+RNPStatus.m"; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -67,18 +85,38 @@
 		9D23B3511C767B80008B4819 /* ReactNativePermissions */ = {
 			isa = PBXGroup;
 			children = (
-				9DE8D2891CA31E95009CE8CC /* RCTConvert+RNPermissionsStatus.h */,
-				9DE8D28A1CA31E95009CE8CC /* RCTConvert+RNPermissionsStatus.m */,
-				9D8FB26E1D2D68C500AAFC55 /* PermissionsChecker.h */,
-				9D8FB26F1D2D68C500AAFC55 /* PermissionsChecker.m */,
-				9D6F44361D2E604500BF17F4 /* PermissionsAsker.h */,
-				9D6F44371D2E604500BF17F4 /* PermissionsAsker.m */,
+				9D4628091D33C1EC00346A5B /* permissions */,
+				9DE8D2891CA31E95009CE8CC /* RCTConvert+RNPStatus.h */,
+				9DE8D28A1CA31E95009CE8CC /* RCTConvert+RNPStatus.m */,
 				9DE8D2801CA31888009CE8CC /* ReactNativePermissions.h */,
 				9DE8D2811CA3188D009CE8CC /* ReactNativePermissions.m */,
 			);
 			path = ReactNativePermissions;
 			sourceTree = "<group>";
 		};
+		9D4628091D33C1EC00346A5B /* permissions */ = {
+			isa = PBXGroup;
+			children = (
+				9D46282E1D34719100346A5B /* RNPAudioVideo.h */,
+				9D46282F1D34719100346A5B /* RNPAudioVideo.m */,
+				9D4628301D34719100346A5B /* RNPBackgroundRefresh.h */,
+				9D4628311D34719100346A5B /* RNPBackgroundRefresh.m */,
+				9D4628321D34719100346A5B /* RNPBluetooth.h */,
+				9D4628331D34719100346A5B /* RNPBluetooth.m */,
+				9D4628341D34719100346A5B /* RNPContacts.h */,
+				9D4628351D34719100346A5B /* RNPContacts.m */,
+				9D4628361D34719100346A5B /* RNPEvent.h */,
+				9D4628371D34719100346A5B /* RNPEvent.m */,
+				9D4628381D34719100346A5B /* RNPLocation.h */,
+				9D4628391D34719100346A5B /* RNPLocation.m */,
+				9D46283A1D34719100346A5B /* RNPNotification.h */,
+				9D46283B1D34719100346A5B /* RNPNotification.m */,
+				9D46283C1D34719100346A5B /* RNPPhoto.h */,
+				9D46283D1D34719100346A5B /* RNPPhoto.m */,
+			);
+			name = permissions;
+			sourceTree = "<group>";
+		};
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
@@ -135,10 +173,16 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				9DE8D28B1CA31E95009CE8CC /* RCTConvert+RNPermissionsStatus.m in Sources */,
-				9D8FB2701D2D68C500AAFC55 /* PermissionsChecker.m in Sources */,
+				9D46283F1D34719100346A5B /* RNPBackgroundRefresh.m in Sources */,
+				9D4628451D34719100346A5B /* RNPPhoto.m in Sources */,
+				9D4628431D34719100346A5B /* RNPLocation.m in Sources */,
+				9D46283E1D34719100346A5B /* RNPAudioVideo.m in Sources */,
+				9D4628401D34719100346A5B /* RNPBluetooth.m in Sources */,
+				9DE8D28B1CA31E95009CE8CC /* RCTConvert+RNPStatus.m in Sources */,
+				9D4628421D34719100346A5B /* RNPEvent.m in Sources */,
 				9DE8D2821CA3188D009CE8CC /* ReactNativePermissions.m in Sources */,
-				9D6F44381D2E604500BF17F4 /* PermissionsAsker.m in Sources */,
+				9D4628411D34719100346A5B /* RNPContacts.m in Sources */,
+				9D4628441D34719100346A5B /* RNPNotification.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

+ 17 - 0
permissions/RNPAudioVideo.h

@@ -0,0 +1,17 @@
+//
+//  RNPAudioVideo.h
+//  ReactNativePermissions
+//
+//  Created by Yonah Forst on 11/07/16.
+//  Copyright © 2016 Yonah Forst. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "RCTConvert+RNPStatus.h"
+
+@interface RNPAudioVideo : NSObject
+
++ (NSString *)getStatus:(NSString *)type;
++ (void)request:(NSString *)type completionHandler:(void (^)(NSString *))completionHandler;
+
+@end

+ 48 - 0
permissions/RNPAudioVideo.m

@@ -0,0 +1,48 @@
+//
+//  RNPCamera.m
+//  ReactNativePermissions
+//
+//  Created by Yonah Forst on 11/07/16.
+//  Copyright © 2016 Yonah Forst. All rights reserved.
+//
+
+#import "RNPAudioVideo.h"
+
+#import <AVFoundation/AVFoundation.h>
+
+@implementation RNPAudioVideo
+
++ (NSString *)getStatus:(NSString *)type
+{
+    int status = [AVCaptureDevice authorizationStatusForMediaType:[self typeFromString:type]];
+    switch (status) {
+        case AVAuthorizationStatusAuthorized:
+            return RNPStatusAuthorized;
+        case AVAuthorizationStatusDenied:
+            return RNPStatusDenied;
+        case AVAuthorizationStatusRestricted:
+            return RNPStatusRestricted;
+        default:
+            return RNPStatusUndetermined;
+    }
+}
+
++ (void)request:(NSString *)type completionHandler:(void (^)(NSString *))completionHandler
+{
+    [AVCaptureDevice requestAccessForMediaType:[self typeFromString:type]
+                             completionHandler:^(BOOL granted) {
+                                 dispatch_async(dispatch_get_main_queue(), ^{
+                                     completionHandler([RNPAudioVideo getStatus:type]);
+                                 });
+                             }];
+}
+
++ (NSString *)typeFromString:(NSString *)string {
+    if ([string isEqualToString:@"audio"]) {
+        return AVMediaTypeAudio;
+    } else {
+        return AVMediaTypeVideo;
+    }
+}
+
+@end

+ 16 - 0
permissions/RNPBackgroundRefresh.h

@@ -0,0 +1,16 @@
+//
+//  RNPBackgroundRefresh.h
+//  ReactNativePermissions
+//
+//  Created by Yonah Forst on 11/07/16.
+//  Copyright © 2016 Yonah Forst. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "RCTConvert+RNPStatus.h"
+
+@interface RNPBackgroundRefresh : NSObject
+
++ (NSString *)getStatus;
+
+@end

+ 28 - 0
permissions/RNPBackgroundRefresh.m

@@ -0,0 +1,28 @@
+//
+//  RNPBackgroundRefresh.m
+//  ReactNativePermissions
+//
+//  Created by Yonah Forst on 11/07/16.
+//  Copyright © 2016 Yonah Forst. All rights reserved.
+//
+
+#import "RNPBackgroundRefresh.h"
+
+@implementation RNPBackgroundRefresh
+
++(NSString *)getStatus
+{
+    int status = [[UIApplication sharedApplication] backgroundRefreshStatus];
+    switch (status) {
+        case UIBackgroundRefreshStatusAvailable:
+            return RNPStatusAuthorized;
+        case UIBackgroundRefreshStatusDenied:
+            return RNPStatusDenied;
+        case UIBackgroundRefreshStatusRestricted:
+            return RNPStatusRestricted;
+        default:
+            return RNPStatusUndetermined;
+    }
+
+}
+@end

+ 17 - 0
permissions/RNPBluetooth.h

@@ -0,0 +1,17 @@
+//
+//  RNPBluetooth.h
+//  ReactNativePermissions
+//
+//  Created by Yonah Forst on 11/07/16.
+//  Copyright © 2016 Yonah Forst. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "RCTConvert+RNPStatus.h"
+
+@interface RNPBluetooth : NSObject
+
++ (NSString *)getStatus;
+- (void)request:(void (^)(NSString *))completionHandler;
+
+@end

+ 66 - 0
permissions/RNPBluetooth.m

@@ -0,0 +1,66 @@
+//
+//  RNPBluetooth.m
+//  ReactNativePermissions
+//
+//  Created by Yonah Forst on 11/07/16.
+//  Copyright © 2016 Yonah Forst. All rights reserved.
+//
+
+#import "RNPBluetooth.h"
+#import <CoreBluetooth/CoreBluetooth.h>
+
+@interface RNPBluetooth() <CBPeripheralDelegate>
+@property (strong, nonatomic) CBPeripheralManager* peripheralManager;
+@property (copy) void (^completionHandler)(NSString *);
+@end
+
+@implementation RNPBluetooth
+
++ (NSString *)getStatus
+{
+    int status = [CBPeripheralManager authorizationStatus];
+    switch (status) {
+        case CBPeripheralManagerAuthorizationStatusAuthorized:
+            return RNPStatusAuthorized;
+        case CBPeripheralManagerAuthorizationStatusDenied:
+            return RNPStatusDenied;
+        case CBPeripheralManagerAuthorizationStatusRestricted:
+            return RNPStatusRestricted;
+        default:
+            return RNPStatusUndetermined;
+    }
+}
+
+- (void)request:(void (^)(NSString *))completionHandler
+{
+    NSString *status = [RNPBluetooth getStatus];
+    
+    if (status == RNPStatusUndetermined) {
+        self.completionHandler = completionHandler;
+        
+        self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];
+        [self.peripheralManager startAdvertising:@{}];
+    } else {
+        completionHandler(status);
+    }
+}
+
+- (void) peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheralManager
+{
+    if (self.peripheralManager) {
+        [self.peripheralManager stopAdvertising];
+        self.peripheralManager.delegate = nil;
+        self.peripheralManager = nil;
+    }
+    
+    if (self.completionHandler) {
+        //for some reason, checking permission right away returns denied. need to wait a tiny bit
+        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
+            self.completionHandler([self.class getStatus]);
+            self.completionHandler = nil;
+        });
+    }
+    
+}
+
+@end

+ 17 - 0
permissions/RNPContacts.h

@@ -0,0 +1,17 @@
+//
+//  RNPContacts.h
+//  ReactNativePermissions
+//
+//  Created by Yonah Forst on 11/07/16.
+//  Copyright © 2016 Yonah Forst. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "RCTConvert+RNPStatus.h"
+
+@interface RNPContacts : NSObject
+
++ (NSString *)getStatus;
++ (void)request:(void (^)(NSString *))completionHandler;
+
+@end

+ 66 - 0
permissions/RNPContacts.m

@@ -0,0 +1,66 @@
+//
+//  RNPContacts.m
+//  ReactNativePermissions
+//
+//  Created by Yonah Forst on 11/07/16.
+//  Copyright © 2016 Yonah Forst. All rights reserved.
+//
+
+#import "RNPContacts.h"
+#import <AddressBook/AddressBook.h>
+
+#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0
+@import Contacts;
+#endif
+
+@implementation RNPContacts
+
++ (NSString *)getStatus
+{
+#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0
+    int status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
+    switch (status) {
+        case CNAuthorizationStatusAuthorized:
+            return RNPStatusAuthorized;
+        case CNAuthorizationStatusDenied:
+            return RNPStatusDenied;
+        case CNAuthorizationStatusRestricted:
+            return RNPStatusRestricted;
+        default:
+            return RNPStatusUndetermined;
+    }
+#else
+    int status = ABAddressBookGetAuthorizationStatus();
+    switch (status) {
+        case kABAuthorizationStatusAuthorized:
+            return RNPStatusAuthorized;
+        case kABAuthorizationStatusDenied:
+            return RNPStatusDenied;
+        case kABAuthorizationStatusRestricted:
+            return RNPStatusRestricted;
+        default:
+            return RNPStatusUndetermined;
+    }
+#endif
+}
+
++ (void)request:(void (^)(NSString *))completionHandler
+{
+    void (^handler)(BOOL, NSError * _Nullable) =  ^(BOOL granted, NSError * _Nullable error) {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            completionHandler([self.class getStatus]);
+        });
+    };
+    
+    
+#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0
+    CNContactStore *contactStore = [[CNContactStore alloc] init];
+    [contactStore requestAccessForEntityType:CNEntityTypeContacts completionHandler:handler];
+#else
+    CFErrorRef error = nil;
+    ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(nil, &error);
+    ABAddressBookRequestAccessWithCompletion(addressBook, completionHandler);
+#endif
+}
+
+@end

+ 17 - 0
permissions/RNPEvent.h

@@ -0,0 +1,17 @@
+//
+//  RNPEvent.h
+//  ReactNativePermissions
+//
+//  Created by Yonah Forst on 11/07/16.
+//  Copyright © 2016 Yonah Forst. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "RCTConvert+RNPStatus.h"
+
+@interface RNPEvent : NSObject
+
++ (NSString *)getStatus:(NSString *)type;
++ (void)request:(NSString *)type completionHandler:(void (^)(NSString *))completionHandler;
+
+@end

+ 48 - 0
permissions/RNPEvent.m

@@ -0,0 +1,48 @@
+//
+//  RNPEvent.m
+//  ReactNativePermissions
+//
+//  Created by Yonah Forst on 11/07/16.
+//  Copyright © 2016 Yonah Forst. All rights reserved.
+//
+
+#import "RNPEvent.h"
+#import <EventKit/EventKit.h>
+
+@implementation RNPEvent
+
++ (NSString *)getStatus:(NSString *)type
+{
+    int status = [EKEventStore authorizationStatusForEntityType:[self typeFromString:type]];
+
+    switch (status) {
+        case EKAuthorizationStatusAuthorized:
+            return RNPStatusAuthorized;
+        case EKAuthorizationStatusDenied:
+            return RNPStatusDenied;
+        case EKAuthorizationStatusRestricted:
+            return RNPStatusRestricted;
+        default:
+            return RNPStatusUndetermined;
+    }
+}
+
++ (void)request:(NSString *)type completionHandler:(void (^)(NSString *))completionHandler
+{
+    EKEventStore *aStore = [[EKEventStore alloc] init];
+    [aStore requestAccessToEntityType:[self typeFromString:type] completion:^(BOOL granted, NSError *error) {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            completionHandler([self getStatus:type]);
+        });
+    }];
+}
+
++(EKEntityType)typeFromString:(NSString *)string {
+    if ([string isEqualToString:@"reminder"]) {
+        return EKEntityTypeReminder;
+    } else {
+        return EKEntityTypeEvent;
+    }
+}
+
+@end

+ 17 - 0
permissions/RNPLocation.h

@@ -0,0 +1,17 @@
+//
+//  RNPLocation.h
+//  ReactNativePermissions
+//
+//  Created by Yonah Forst on 11/07/16.
+//  Copyright © 2016 Yonah Forst. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "RCTConvert+RNPStatus.h"
+
+@interface RNPLocation : NSObject
+
++ (NSString *)getStatus;
+- (void)request:(NSString *)type completionHandler:(void (^)(NSString *))completionHandler;
+
+@end

+ 68 - 0
permissions/RNPLocation.m

@@ -0,0 +1,68 @@
+//
+//  RNPLocation.m
+//  ReactNativePermissions
+//
+//  Created by Yonah Forst on 11/07/16.
+//  Copyright © 2016 Yonah Forst. All rights reserved.
+//
+
+#import "RNPLocation.h"
+#import <CoreLocation/CoreLocation.h>
+
+
+@interface RNPLocation() <CLLocationManagerDelegate>
+@property (strong, nonatomic) CLLocationManager* locationManager;
+@property (copy) void (^completionHandler)(NSString *);
+@end
+
+@implementation RNPLocation
+
++ (NSString *)getStatus
+{
+    int status = [CLLocationManager authorizationStatus];
+    switch (status) {
+        case kCLAuthorizationStatusAuthorizedAlways:
+        case kCLAuthorizationStatusAuthorizedWhenInUse:
+            return RNPStatusAuthorized;
+        case kCLAuthorizationStatusDenied:
+            return RNPStatusDenied;
+        case kCLAuthorizationStatusRestricted:
+            return RNPStatusRestricted;
+        default:
+            return RNPStatusUndetermined;
+    }
+}
+
+- (void)request:(NSString*)type completionHandler:(void (^)(NSString *))completionHandler
+{
+    NSString *status = [RNPLocation getStatus];
+    if (status == RNPStatusUndetermined) {
+        self.completionHandler = completionHandler;
+        
+        self.locationManager = [[CLLocationManager alloc] init];
+        self.locationManager.delegate = self;
+        if ([type isEqualToString:@"always"]) {
+            [self.locationManager requestAlwaysAuthorization];
+        } else {
+            [self.locationManager requestWhenInUseAuthorization];
+        }
+    } else {
+        completionHandler(status);
+    }
+}
+
+-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
+    if (self.locationManager) {
+        self.locationManager.delegate = nil;
+        self.locationManager = nil;
+    }
+    
+    if (self.completionHandler) {
+        //for some reason, checking permission right away returns denied. need to wait a tiny bit
+        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
+            self.completionHandler([RNPLocation getStatus]);
+            self.completionHandler = nil;
+        });
+    }
+}
+@end

+ 17 - 0
permissions/RNPNotification.h

@@ -0,0 +1,17 @@
+//
+//  RNPNotification.h
+//  ReactNativePermissions
+//
+//  Created by Yonah Forst on 11/07/16.
+//  Copyright © 2016 Yonah Forst. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "RCTConvert+RNPStatus.h"
+
+@interface RNPNotification : NSObject
+
++ (NSString *)getStatus;
+- (void)request:(UIUserNotificationType)types completionHandler:(void (^)(NSString*))completionHandler;
+
+@end

+ 89 - 0
permissions/RNPNotification.m

@@ -0,0 +1,89 @@
+//
+//  RNPNotification.m
+//  ReactNativePermissions
+//
+//  Created by Yonah Forst on 11/07/16.
+//  Copyright © 2016 Yonah Forst. All rights reserved.
+//
+
+#import "RNPNotification.h"
+
+static NSString* RNPDidAskForNotification = @"RNPDidAskForNotification";
+
+@interface RNPNotification()
+@property (copy) void (^completionHandler)(NSString*);
+@end
+
+@implementation RNPNotification
+
++ (NSString *)getStatus
+{
+    BOOL didAskForPermission = [[NSUserDefaults standardUserDefaults] boolForKey:RNPDidAskForNotification];
+    
+    if (didAskForPermission) {
+        if ([[UIApplication sharedApplication] respondsToSelector:@selector(isRegisteredForRemoteNotifications)]) {
+            // iOS8+
+            BOOL isRegistered = [[UIApplication sharedApplication] isRegisteredForRemoteNotifications];
+            BOOL isEnabled = [[[UIApplication sharedApplication] currentUserNotificationSettings] types] != UIUserNotificationTypeNone;
+            if (isRegistered || isEnabled) {
+                return isEnabled ? RNPStatusAuthorized : RNPStatusDenied;
+            }
+            else {
+                return RNPStatusDenied;
+            }
+        } else {
+            if ([[UIApplication sharedApplication] enabledRemoteNotificationTypes] == UIRemoteNotificationTypeNone) {
+                return RNPStatusDenied;
+            }
+            else {
+                return RNPStatusAuthorized;
+            }
+        }
+    } else {
+        return RNPStatusUndetermined;
+    }
+}
+
+- (void)request:(UIUserNotificationType)types completionHandler:(void (^)(NSString*))completionHandler
+{
+    BOOL didAskForPermission = [[NSUserDefaults standardUserDefaults] boolForKey:RNPDidAskForNotification];
+    if (!didAskForPermission) {
+        self.completionHandler = completionHandler;
+        
+        [[NSNotificationCenter defaultCenter] addObserver:self
+                                                 selector:@selector(applicationDidBecomeActive)
+                                                     name:UIApplicationDidBecomeActiveNotification
+                                                   object:nil];
+        
+        if ([[UIApplication sharedApplication] respondsToSelector:@selector(isRegisteredForRemoteNotifications)]) {
+            // iOS8+
+            UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
+            [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
+            [[UIApplication sharedApplication] registerForRemoteNotifications];
+        } else {
+            [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationType)types];
+        }
+        
+        [[NSUserDefaults standardUserDefaults] setBool:YES forKey:RNPDidAskForNotification];
+        [[NSUserDefaults standardUserDefaults] synchronize];
+    } else {
+        completionHandler([self.class getStatus]);
+    }
+}
+
+- (void)applicationDidBecomeActive
+{
+    [[NSNotificationCenter defaultCenter] removeObserver:self
+                                                    name:UIApplicationDidBecomeActiveNotification
+                                                  object:nil];
+    
+    if (self.completionHandler) {
+        //for some reason, checking permission right away returns denied. need to wait a tiny bit
+        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
+            self.completionHandler([self.class getStatus]);
+            self.completionHandler = nil;
+        });
+    }
+}
+
+@end

+ 17 - 0
permissions/RNPPhoto.h

@@ -0,0 +1,17 @@
+//
+//  RNPPhoto.h
+//  ReactNativePermissions
+//
+//  Created by Yonah Forst on 11/07/16.
+//  Copyright © 2016 Yonah Forst. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "RCTConvert+RNPStatus.h"
+
+@interface RNPPhoto : NSObject
+
++ (NSString *)getStatus;
++ (void)request:(void (^)(NSString *))completionHandler;
+
+@end

+ 69 - 0
permissions/RNPPhoto.m

@@ -0,0 +1,69 @@
+//
+//  RNPPhoto.m
+//  ReactNativePermissions
+//
+//  Created by Yonah Forst on 11/07/16.
+//  Copyright © 2016 Yonah Forst. All rights reserved.
+//
+
+#import "RNPPhoto.h"
+#import <AssetsLibrary/AssetsLibrary.h>
+
+#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0
+@import Photos;
+#endif
+
+@implementation RNPPhoto
+
++ (NSString *)getStatus
+{
+#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0
+    int status = [PHPhotoLibrary authorizationStatus];
+    switch (status) {
+        case PHAuthorizationStatusAuthorized:
+            return RNPStatusAuthorized;
+        case PHAuthorizationStatusDenied:
+            return RNPStatusDenied;
+        case PHAuthorizationStatusRestricted:
+            return RNPStatusRestricted;
+        default:
+            return RNPStatusUndetermined;
+    }
+#else
+    int status = ABAddressBookGetAuthorizationStatus();
+    switch (status) {
+        case kABAuthorizationStatusAuthorized:
+            return RNPStatusAuthorized;
+        case kABAuthorizationStatusDenied:
+            return RNPStatusDenied;
+        case kABAuthorizationStatusRestricted:
+            return RNPStatusRestricted;
+        default:
+            return RNPStatusUndetermined;
+    }
+#endif
+}
+
++ (void)request:(void (^)(NSString *))completionHandler
+{
+    void (^handler)(void) =  ^(void) {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            completionHandler([self.class getStatus]);
+        });
+    };
+    
+#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0
+    [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
+        handler();
+    }];
+#else
+    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
+    [library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
+        handler()
+        *stop = YES;
+    } failureBlock:^(NSError *error) {
+        handler();
+    }];
+#endif
+}
+@end