Browse Source

breaking changes - use RN's own JS PermissionsAndroid.

Yonah Forst 8 years ago
parent
commit
306e6928c1

+ 20 - 14
Example/Example.js

@@ -24,8 +24,10 @@ export default class Example extends Component {
   }
 
   componentDidMount() {
-    let types = Permissions.getPermissionTypes()
-    this.setState({ types })
+    let types = Permissions.getTypes()
+    let canOpenSettings = Permissions.canOpenSettings()
+
+    this.setState({ types, canOpenSettings })
     this._updatePermissions(types)
     AppState.addEventListener('change', this._handleAppStateChange.bind(this));
   }
@@ -47,10 +49,10 @@ export default class Example extends Component {
   }
 
   _updatePermissions(types) {
-    Permissions.checkMultiplePermissions(types)
+    Permissions.checkMultiple(types)
       .then(status => {
         if (this.state.isAlways) {
-          return Permissions.getPermissionStatus('location', 'always')
+          return Permissions.check('location', 'always')
             .then(location => ({...status, location}))
         }
         return status
@@ -65,19 +67,19 @@ export default class Example extends Component {
       options = this.state.isAlways ? 'always' : 'whenInUse'
     }
 
-    Permissions.requestPermission(permission, options)
+    Permissions.request(permission, options)
       .then(res => {
         this.setState({
           status: {...this.state.status, [permission]: res}
         })
         if (res != 'authorized') {
+          var buttons = [{ text: 'Cancel', style: 'cancel' }]
+          if (this.state.canOpenSettings) buttons.push({ text: 'Open Settings', onPress: this._openSettings.bind(this) })
+          
           Alert.alert(
             'Whoops!',
             "There was a problem getting your permission. Please enable it from settings.",
-            [
-              {text: 'Cancel', style: 'cancel'},
-              {text: 'Open Settings', onPress: this._openSettings.bind(this) },
-            ]
+            buttons
           )
         }
       }).catch(e => console.warn(e))
@@ -114,11 +116,15 @@ export default class Example extends Component {
             onPress={this._onLocationSwitchChange.bind(this)}>
             <Text style={styles.text}>Toggle location type</Text>
           </TouchableHighlight>
+   
+          {
+            this.state.canOpenSettings &&
+            <TouchableHighlight 
+              onPress={this._openSettings.bind(this)}>
+              <Text style={styles.text}>Open settings</Text>
+            </TouchableHighlight>
+          }
 
-          <TouchableHighlight 
-            onPress={this._openSettings.bind(this)}>
-            <Text style={styles.text}>Open settings</Text>
-          </TouchableHighlight>
         </View>
 
 
@@ -163,7 +169,7 @@ const styles = StyleSheet.create({
     backgroundColor: '#ef9a9a',
   },
   restricted: {
-    backgroundColor: '#FFAB91'
+    backgroundColor: '#ef9a9a'
   },
   footer: {
     padding: 10,

+ 0 - 1
Example/android/app/build.gradle

@@ -126,7 +126,6 @@ android {
 }
 
 dependencies {
-    compile project(':react-native-permissions')
     compile fileTree(dir: "libs", include: ["*.jar"])
     compile "com.android.support:appcompat-v7:23.0.1"
     compile "com.facebook.react:react-native:+"  // From node_modules

+ 0 - 1
Example/android/app/src/main/java/com/example/MainActivity.java

@@ -1,7 +1,6 @@
 package com.example;
 
 import com.facebook.react.ReactActivity;
-import com.joshblour.reactnativepermissions.ReactNativePermissionsPackage;
 
 public class MainActivity extends ReactActivity {
 

+ 1 - 3
Example/android/app/src/main/java/com/example/MainApplication.java

@@ -8,7 +8,6 @@ import com.facebook.react.ReactInstanceManager;
 import com.facebook.react.ReactNativeHost;
 import com.facebook.react.ReactPackage;
 import com.facebook.react.shell.MainReactPackage;
-import com.joshblour.reactnativepermissions.ReactNativePermissionsPackage;
 import com.facebook.soloader.SoLoader;
 
 import java.util.Arrays;
@@ -25,8 +24,7 @@ public class MainApplication extends Application implements ReactApplication {
     @Override
     protected List<ReactPackage> getPackages() {
       return Arrays.<ReactPackage>asList(
-          new MainReactPackage(),
-          new ReactNativePermissionsPackage()
+          new MainReactPackage()
       );
     }
   };

+ 0 - 2
Example/android/settings.gradle

@@ -1,5 +1,3 @@
 rootProject.name = 'Example'
 
 include ':app'
-include ':react-native-permissions'
-project(':react-native-permissions').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-permissions/android')

+ 26 - 14
Example/ios/Example.xcodeproj/project.pbxproj

@@ -22,7 +22,6 @@
 		13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
 		140ED2AC1D01E1AD002B40FF /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
 		146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
-		14902CDAB1064113A6B4C970 /* libReactNativePermissions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B27CA08432F04FFCB0256EA1 /* libReactNativePermissions.a */; };
 		2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
 		2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
 		2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
@@ -36,6 +35,7 @@
 		2D02E4C91E0B4AEC006451C7 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3EA31DF850E9000B6D8A /* libReact.a */; };
 		2DCD954D1E0B4F2C00145EB5 /* ExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* ExampleTests.m */; };
 		5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */; };
+		6D05A8F55CC4482AACFFC932 /* libReactNativePermissions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DF4131A2930454297EF564B /* libReactNativePermissions.a */; };
 		832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
 /* End PBXBuildFile section */
 
@@ -229,9 +229,9 @@
 			remoteGlobalIDString = 58B5119B1A9E6C1200147676;
 			remoteInfo = RCTText;
 		};
-		9D8131C41E44834800F4B1D3 /* PBXContainerItemProxy */ = {
+		9D140CBB1F068EB400146F6C /* PBXContainerItemProxy */ = {
 			isa = PBXContainerItemProxy;
-			containerPortal = 8068EB7451414340B0AC0D03 /* ReactNativePermissions.xcodeproj */;
+			containerPortal = 1CB53DB705894AAA8CB22783 /* ReactNativePermissions.xcodeproj */;
 			proxyType = 2;
 			remoteGlobalIDString = 9D23B34F1C767B80008B4819;
 			remoteInfo = ReactNativePermissions;
@@ -258,13 +258,13 @@
 		13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Example/Info.plist; sourceTree = "<group>"; };
 		13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = Example/main.m; sourceTree = "<group>"; };
 		146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = "<group>"; };
+		1CB53DB705894AAA8CB22783 /* ReactNativePermissions.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = ReactNativePermissions.xcodeproj; path = "../node_modules/react-native-permissions/ReactNativePermissions.xcodeproj"; sourceTree = "<group>"; };
 		2D02E47B1E0B4A5D006451C7 /* Example-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Example-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
 		2D02E4901E0B4A5D006451C7 /* Example-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Example-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
+		5DF4131A2930454297EF564B /* libReactNativePermissions.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libReactNativePermissions.a; sourceTree = "<group>"; };
 		5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = "<group>"; };
 		78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = "<group>"; };
-		8068EB7451414340B0AC0D03 /* ReactNativePermissions.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = ReactNativePermissions.xcodeproj; path = "../node_modules/react-native-permissions/ReactNativePermissions.xcodeproj"; sourceTree = "<group>"; };
 		832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = "<group>"; };
-		B27CA08432F04FFCB0256EA1 /* libReactNativePermissions.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libReactNativePermissions.a; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -291,7 +291,7 @@
 				832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */,
 				00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */,
 				139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */,
-				14902CDAB1064113A6B4C970 /* libReactNativePermissions.a in Frameworks */,
+				6D05A8F55CC4482AACFFC932 /* libReactNativePermissions.a in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -458,7 +458,7 @@
 				832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */,
 				00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */,
 				139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */,
-				8068EB7451414340B0AC0D03 /* ReactNativePermissions.xcodeproj */,
+				1CB53DB705894AAA8CB22783 /* ReactNativePermissions.xcodeproj */,
 			);
 			name = Libraries;
 			sourceTree = "<group>";
@@ -495,10 +495,10 @@
 			name = Products;
 			sourceTree = "<group>";
 		};
-		9D8131A81E44834700F4B1D3 /* Products */ = {
+		9D140C9F1F068EB400146F6C /* Products */ = {
 			isa = PBXGroup;
 			children = (
-				9D8131C51E44834800F4B1D3 /* libReactNativePermissions.a */,
+				9D140CBC1F068EB400146F6C /* libReactNativePermissions.a */,
 			);
 			name = Products;
 			sourceTree = "<group>";
@@ -584,7 +584,7 @@
 		83CBB9F71A601CBA00E9B192 /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 0820;
+				LastUpgradeCheck = 820;
 				ORGANIZATIONNAME = Facebook;
 				TargetAttributes = {
 					00E356ED1AD99517003FC87E = {
@@ -666,8 +666,8 @@
 					ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */;
 				},
 				{
-					ProductGroup = 9D8131A81E44834700F4B1D3 /* Products */;
-					ProjectRef = 8068EB7451414340B0AC0D03 /* ReactNativePermissions.xcodeproj */;
+					ProductGroup = 9D140C9F1F068EB400146F6C /* Products */;
+					ProjectRef = 1CB53DB705894AAA8CB22783 /* ReactNativePermissions.xcodeproj */;
 				},
 			);
 			projectRoot = "";
@@ -856,11 +856,11 @@
 			remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */;
 			sourceTree = BUILT_PRODUCTS_DIR;
 		};
-		9D8131C51E44834800F4B1D3 /* libReactNativePermissions.a */ = {
+		9D140CBC1F068EB400146F6C /* libReactNativePermissions.a */ = {
 			isa = PBXReferenceProxy;
 			fileType = archive.ar;
 			path = libReactNativePermissions.a;
-			remoteRef = 9D8131C41E44834800F4B1D3 /* PBXContainerItemProxy */;
+			remoteRef = 9D140CBB1F068EB400146F6C /* PBXContainerItemProxy */;
 			sourceTree = BUILT_PRODUCTS_DIR;
 		};
 /* End PBXReferenceProxy section */
@@ -1007,6 +1007,8 @@
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"\"$(SRCROOT)/$(TARGET_NAME)\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
 				);
 				OTHER_LDFLAGS = (
 					"-ObjC",
@@ -1028,6 +1030,8 @@
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"\"$(SRCROOT)/$(TARGET_NAME)\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
 				);
 				OTHER_LDFLAGS = (
 					"-ObjC",
@@ -1090,6 +1094,8 @@
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"\"$(SRCROOT)/$(TARGET_NAME)\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
 				);
 				OTHER_LDFLAGS = (
 					"-ObjC",
@@ -1120,6 +1126,8 @@
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"\"$(SRCROOT)/$(TARGET_NAME)\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
 				);
 				OTHER_LDFLAGS = (
 					"-ObjC",
@@ -1149,6 +1157,8 @@
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"\"$(SRCROOT)/$(TARGET_NAME)\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
 				);
 				PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.Example-tvOSTests";
 				PRODUCT_NAME = "$(TARGET_NAME)";
@@ -1174,6 +1184,8 @@
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"\"$(SRCROOT)/$(TARGET_NAME)\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
 				);
 				PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.Example-tvOSTests";
 				PRODUCT_NAME = "$(TARGET_NAME)";

+ 2 - 0
Example/ios/Example/Info.plist

@@ -51,6 +51,8 @@
 	<string>test</string>
 	<key>NSRemindersUsageDescription</key>
 	<string>test</string>
+	<key>NSSpeechRecognitionUsageDescription</key>
+	<string>test</string>
 	<key>UIBackgroundModes</key>
 	<array>
 		<string>bluetooth-peripheral</string>

+ 17 - 66
README.md

@@ -17,6 +17,7 @@ The current supported permissions are:
 
 | Version | React Native Support |
 |---|---|
+| 1.0.0 | 0.40.0 - 0.45.0 |
 | 0.2.7 | 0.40.0 - 0.41.0 |
 | 0.2.5 | 0.33.0 - 0.39.0 |
 *Complies with [react-native-version-support-table](https://github.com/dangnelson/react-native-version-support-table)*
@@ -94,7 +95,7 @@ Promises resolve into one of these statuses
 |---|---|
 |`authorized`| user has authorized this permission |
 |`denied`| user has denied this permission at least once. On iOS this means that the user will not be prompted again. Android users can be promted multiple times until they select 'Never ask me again'|
-|`restricted`| *(iOS only)* user is not able to grant this permission, either because it's not supported by the device or because it has been blocked by parental controls. |
+|`restricted`| **iOS** - this means user is not able to grant this permission, either because it's not supported by the device or because it has been blocked by parental controls. **Android** - this means that the user has selected 'Never ask me again' while denying permission |
 |`undetermined`| user has not yet been prompted with a permission dialog |
 
 ### Supported permission types
@@ -117,33 +118,32 @@ Promises resolve into one of these statuses
 ### Methods
 | Method Name | Arguments | Notes
 |---|---|---|
-| `getPermissionStatus` | `type` | - Returns a promise with the permission status. See iOS Notes for special cases |
-| `requestPermission` | `type` | - Accepts any permission type except `backgroundRefresh`. If the current status is `undetermined`, shows the permission dialog and returns a promise with the resulting status. Otherwise, immediately return a promise with the current status. See iOS Notes for special cases|
-| `checkMultiplePermissions` | `[types]` | - Accepts an array of permission types and returns a promise with an object mapping permission types to statuses |
-| `getPermissionTypes` | *none* | - Returns an array of valid permission types  |
-| `openSettings` | *none* | - Switches the user to the settings page of your app (iOS 8.0 and later)  |
-| `canOpenSettings` | *none* | - Returns a boolean indicating if the device supports switching to the settings page |
+| `check` | `type` | - Returns a promise with the permission status. See iOS Notes for special cases |
+| `request` | `type` | - Accepts any permission type except `backgroundRefresh`. If the current status is `undetermined`, shows the permission dialog and returns a promise with the resulting status. Otherwise, immediately return a promise with the current status. See iOS Notes for special cases|
+| `checkMultiple` | `[types]` | - Accepts an array of permission types and returns a promise with an object mapping permission types to statuses |
+| `getTypes` | *none* | - Returns an array of valid permission types  |
+| `openSettings` | *none* | - *(iOS only - 8.0 and later)* Switches the user to the settings page of your app |
+| `canOpenSettings` | *none* | - *(iOS only)* Returns a boolean indicating if the device supports switching to the settings page |
 
 ### iOS Notes
-Permission type `bluetooth` represents the status of the `CBPeripheralManager`. Don't use this if only need `CBCentralManager`
+- Permission type `bluetooth` represents the status of the `CBPeripheralManager`. Don't use this if only need `CBCentralManager`
+- Permission type `location` accepts a second parameter for `requestPermission` and `getPermissionStatus`;  the second parameter is a string, either `always` or `whenInUse`(default).
 
-Permission type `location` accepts a second parameter for `requestPermission` and `getPermissionStatus`;  the second parameter is a string, either `always` or `whenInUse`(default).
-
-Permission type `notification` accepts a second parameter for `requestPermission`. The second parameter is an array with the desired alert types. Any combination of `alert`, `badge` and `sound` (default requests all three)
+- Permission type `notification` accepts a second parameter for `requestPermission`. The second parameter is an array with the desired alert types. Any combination of `alert`, `badge` and `sound` (default requests all three)
 
 ```js
 ///example
-    Permissions.getPermissionStatus('location', 'always')
+    Permissions.check('location', 'always')
       .then(response => {
         this.setState({ locationPermission: response })
       })
 
-    Permissions.requestPermission('location', 'always')
+    Permissions.request('location', 'always')
       .then(response => {
         this.setState({ locationPermission: response })
       })
 
-    Permissions.requestPermission('notification', ['alert', 'badge'])
+    Permissions.request('notification', ['alert', 'badge'])
       .then(response => {
         this.setState({ notificationPermission: response })
       })
@@ -161,20 +161,12 @@ If you need Contacts permission you have to add the key "Privacy - Contacts Usag
 
 Requires RN >= 0.29.0
 
+Uses RN's own `PermissionsAndroid` JS api (http://facebook.github.io/react-native/releases/0.45/docs/permissionsandroid.html)
+
 All required permissions also need to be included in the Manifest before they can be requested. Otherwise `requestPermission` will immediately return `denied`.
 
 Permissions are automatically accepted for targetSdkVersion < 23 but you can still use `getPermissionStatus` to check if the user has disabled them from Settings.
 
-Here's a map of types to Android system permissions names:
-`location` -> `android.permission.ACCESS_FINE_LOCATION`
-`camera` -> `android.permission.CAMERA`
-`microphone` -> `android.permission.RECORD_AUDIO`
-`photo` -> `android.permission.READ_EXTERNAL_STORAGE`
-`storage` -> `android.permission.READ_EXTERNAL_STORAGE`
-`contacts` -> `android.permission.READ_CONTACTS`
-`event` -> `android.permission.READ_CALENDAR`
-
-
 You can request write access to any of these types by also including the appropriate write permission in the Manifest. Read more here: https://developer.android.com/guide/topics/security/permissions.html#normal-dangerous
 
 ## Setup
@@ -192,46 +184,8 @@ rnpm link
 * Add libReactNativePermissions.a to `Build Phases -> Link Binary With Libraries.
 
 #### Android
-##### Step 1 - Update Gradle Settings
-
-```
-// file: android/settings.gradle
-...
-
-include ':react-native-permissions'
-project(':react-native-permissions').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-permissions/android')
-```
-##### Step 2 - Update Gradle Build
-
-```
-// file: android/app/build.gradle
-...
-
-dependencies {
-    ...
-    compile project(':react-native-permissions')
-}
-```
-##### Step 3 - Register React Package
-```
-...
-import com.joshblour.reactnativepermissions.ReactNativePermissionsPackage; // <--- import
-
-public class MainApplication extends Application implements ReactApplication {
+  No additional linking required
 
-    ...
-
-    @Override
-    protected List<ReactPackage> getPackages() {
-        return Arrays.<ReactPackage>asList(
-            new MainReactPackage(),
-            new ReactNativePermissionsPackage() // <------ add the package
-        );
-    }
-
-    ...
-}
-```
 ## AppStore submission disclaimer
 
 If you need to submit you application to the AppStore, you need to add to your `Info.plist` all `*UsageDescription` keys with a string value explaining to the user how the app uses this data. **Even if you don't use them**.
@@ -261,9 +215,6 @@ You can find more informations about this issue in #46.
 
 ## Troubleshooting
 
-#### Q: Android - `undefined is not a object (evaluating 'RNPermissions.requestPermissions')`
-A: `rnpm` may not have linked correctly. Follow the manual linking steps and make sure the library is linked
-
 #### Q: iOS - app crashes as soon as I request permission
 A: starting with xcode 8, you need to add permission descriptions. see iOS notes for more details. Thanks to @jesperlndk for discovering this.
 

+ 0 - 116
ReactNativePermissions.js

@@ -1,116 +0,0 @@
-'use strict';
-
-var ReactNative = require('react-native')
-var Platform = ReactNative.Platform
-var RNPermissions = ReactNative.NativeModules.ReactNativePermissions;
-
-const RNPTypes = {
-	ios: [
-		'location',
-		'camera',
-		'microphone',
-		'photo',
-		'contacts',
-		'event',
-		'reminder',
-		'bluetooth',
-		'notification',
-		'backgroundRefresh',
-		'speechRecognition',
-	],
-	android: [
-		'location',
-		'camera',
-		'microphone',
-		'contacts',
-		'event',
-		'photo',
-		'storage',
-		'notification',
-	]
-}
-
-class ReactNativePermissions {
-	constructor() {
-		//legacy support
-		this.StatusUndetermined = 'undetermined'
-		this.StatusDenied = 'denied'
-		this.StatusAuthorized = 'authorized'
-		this.StatusRestricted = 'restricted'
-
-		this.getPermissionTypes().forEach(type => {
-			let methodName = `${type}PermissionStatus`
-			this[methodName] = p => {
-				console.warn(`ReactNativePermissions: ${methodName} is depricated. Use getPermissionStatus('${type}') instead.`)
-				return this.getPermissionStatus(p == 'reminder' ? p : type)
-			}
-		})
-	}
-
-	canOpenSettings() {
-		return RNPermissions.canOpenSettings()
-	}
-
-	openSettings() {
-		return RNPermissions.openSettings()
-	}
-
-	getPermissionTypes() {
-		return RNPTypes[Platform.OS];
-	}
-
-
-	getPermissionStatus(permission, type) {
-  	if (this.getPermissionTypes().indexOf(permission) >= 0) {
-			return RNPermissions.getPermissionStatus(permission, type)
-		} else {
-			return Promise.reject(`ReactNativePermissions: ${permission} is not a valid permission type on ${Platform.OS}`)
-		}
-	}
-
-	requestPermission(permission, type) {
-		let options;
-
-		if (this.getPermissionTypes().indexOf(permission) === -1) {
-			return Promise.reject(`ReactNativePermissions: ${permission} is not a valid permission type on ${Platform.OS}`)
-		} else if (permission == 'backgroundRefresh'){
-			return Promise.reject('ReactNativePermissions: You cannot request backgroundRefresh')
-		} else if (permission == 'location') {
-			options = type || 'whenInUse'
-		} else if (permission == 'notification') {
-			if (Platform.OS === 'android') {
-				return Promise.reject(`ReactNativePermissions: notification cannot be requested on Android`)
-			}
-			options = type || ['alert', 'badge', 'sound']
-		}
-
-		return RNPermissions.requestPermission(permission, options)
-	}
-
-	//recursive funciton to chain a promises for a list of permissions
-	checkMultiplePermissions(permissions) {
-		let i = permissions.length
-		let that = this
-		const obj = {}
-		function processNext() {
-			i--
-			let p = permissions[i]
-
-			if (!p) {
-				return Promise.resolve(obj)
-			}
-
-			return that.getPermissionStatus(p)
-				.then(res => {
-					obj[p] = res
-					return processNext()
-				}).catch(e => {
-					console.warn(e)
-					return processNext()
-				})
-		}
-		return processNext()
-	}
-}
-
-module.exports = new ReactNativePermissions()

+ 0 - 34
android/build.gradle

@@ -1,34 +0,0 @@
-buildscript {
-    repositories {
-        jcenter()
-    }
-
-    dependencies {
-        classpath 'com.android.tools.build:gradle:2.1.+'
-    }
-}
-
-apply plugin: 'com.android.library'
-
-android {
-    compileSdkVersion 24
-    buildToolsVersion "25.0.2"
-
-    defaultConfig {
-        minSdkVersion 16
-        targetSdkVersion 24
-        versionCode 1
-        versionName "1.0"
-    }
-    lintOptions {
-        abortOnError false
-    }
-}
-
-repositories {
-    jcenter()
-}
-
-dependencies {
-    compile 'com.facebook.react:react-native:+'
-}

+ 0 - 3
android/src/main/AndroidManifest.xml

@@ -1,3 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.joshblour.reactnativepermissions">
-</manifest>

+ 0 - 154
android/src/main/java/com/joshblour/reactnativepermissions/ReactNativePermissionsModule.java

@@ -1,154 +0,0 @@
-package com.joshblour.reactnativepermissions;
-
-import android.Manifest;
-import android.content.Intent;
-import android.net.Uri;
-import android.provider.Settings;
-import android.support.v4.app.ActivityCompat;
-import android.support.v4.app.NotificationManagerCompat;
-import android.support.v4.content.ContextCompat;
-import android.support.v4.content.PermissionChecker;
-
-import com.facebook.react.bridge.Callback;
-import com.facebook.react.bridge.Promise;
-import com.facebook.react.bridge.PromiseImpl;
-import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.ReactContextBaseJavaModule;
-import com.facebook.react.bridge.ReactMethod;
-import com.facebook.react.bridge.ReadableMap;
-import com.facebook.react.bridge.ReadableArray;
-import com.facebook.react.modules.permissions.PermissionsModule;
-
-import java.util.Locale;
-
-public class ReactNativePermissionsModule extends ReactContextBaseJavaModule {
-  private final ReactApplicationContext reactContext;
-  private final PermissionsModule mPermissionsModule;
-  private final NotificationManagerCompat mNotificationManagerCompat;
-
-  public enum RNType {
-    LOCATION,
-    NOTIFICATION,
-    CAMERA,
-    MICROPHONE,
-    CONTACTS,
-    EVENT,
-    STORAGE,
-    PHOTO;
-  }
-
-  public ReactNativePermissionsModule(ReactApplicationContext reactContext) {
-    super(reactContext);
-    this.reactContext = reactContext;
-    mPermissionsModule = new PermissionsModule(this.reactContext);
-    mNotificationManagerCompat = NotificationManagerCompat.from(this.reactContext);
-  }
-
-  @Override
-  public String getName() {
-    return "ReactNativePermissions";
-  }
-
-  @ReactMethod
-  public void getPermissionStatus(String permissionString, String nullForiOSCompat, Promise promise) {
-    String permission = permissionForString(permissionString);
-
-    // check if permission is valid
-    if (permission == null) {
-      promise.reject("unknown-permission", "ReactNativePermissions: unknown permission type - " + permissionString);
-      return;
-    }
-
-    if(permission.equals("notification")) {
-      if (mNotificationManagerCompat.areNotificationsEnabled()) {
-        promise.resolve("authorized");
-      } else {
-        promise.resolve("denied");
-      }
-      return;
-    }
-
-    int result = PermissionChecker.checkSelfPermission(this.reactContext, permission);
-    switch (result) {
-      case PermissionChecker.PERMISSION_DENIED:
-        // PermissionDenied could also mean that we've never asked for permission yet.
-        // Use shouldShowRequestPermissionRationale to determined which on it is.
-        if (getCurrentActivity() != null) {
-          boolean deniedOnce = ActivityCompat.shouldShowRequestPermissionRationale(getCurrentActivity(), permission);
-          promise.resolve(deniedOnce ? "denied" : "undetermined");
-        } else {
-          promise.resolve("denied");
-        }
-        break;
-      case PermissionChecker.PERMISSION_DENIED_APP_OP:
-        promise.resolve("denied");
-        break;
-      case PermissionChecker.PERMISSION_GRANTED:
-        promise.resolve("authorized");
-        break;
-      default:
-        promise.resolve("undetermined");
-        break;
-    }
-  }
-
-  @ReactMethod
-  public void requestPermission(final String permissionString, String nullForiOSCompat, final Promise promise) {
-    String permission = permissionForString(permissionString);
-    Callback resolve = new Callback() {
-      @Override
-      public void invoke(Object... args) {
-        getPermissionStatus(permissionString, "", promise);
-      }
-    };
-    Callback reject = new Callback() {
-      @Override
-      public void invoke(Object... args) {
-        // NOOP
-      }
-    };
-
-    mPermissionsModule.requestPermission(permission, new PromiseImpl(resolve, reject));
-  }
-
-
-  @ReactMethod
-  public void canOpenSettings(Promise promise) {
-    promise.resolve(true);
-  }
-
-  @ReactMethod
-  public void openSettings() {
-    final Intent i = new Intent();
-    i.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
-    i.addCategory(Intent.CATEGORY_DEFAULT);
-    i.setData(Uri.parse("package:" + this.reactContext.getPackageName()));
-    i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-    i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
-    i.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-    this.reactContext.startActivity(i);
-  }
-
-  private String permissionForString(String permission) {
-    switch (RNType.valueOf(permission.toUpperCase(Locale.ENGLISH))) {
-      case LOCATION:
-        return Manifest.permission.ACCESS_FINE_LOCATION;
-      case CAMERA:
-        return Manifest.permission.CAMERA;
-      case MICROPHONE:
-        return Manifest.permission.RECORD_AUDIO;
-      case CONTACTS:
-        return Manifest.permission.READ_CONTACTS;
-      case EVENT:
-        return Manifest.permission.READ_CALENDAR;
-      case STORAGE:
-      case PHOTO:
-        return Manifest.permission.READ_EXTERNAL_STORAGE;
-      case NOTIFICATION:
-        return permission;
-      default:
-        return null;
-    }
-  }
-
-}

+ 0 - 28
android/src/main/java/com/joshblour/reactnativepermissions/ReactNativePermissionsPackage.java

@@ -1,28 +0,0 @@
-package com.joshblour.reactnativepermissions;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import com.facebook.react.ReactPackage;
-import com.facebook.react.bridge.NativeModule;
-import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.uimanager.ViewManager;
-import com.facebook.react.bridge.JavaScriptModule;
-
-public class ReactNativePermissionsPackage implements ReactPackage {
-    @Override
-    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
-      return Arrays.<NativeModule>asList(new ReactNativePermissionsModule(reactContext));
-    }
-
-    @Override
-    public List<Class<? extends JavaScriptModule>> createJSModules() {
-      return Collections.emptyList();
-    }
-
-    @Override
-    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
-      return Collections.emptyList();
-    }
-}

+ 85 - 0
index.android.js

@@ -0,0 +1,85 @@
+'use strict';
+
+const ReactNative = require('react-native')
+const RNPermissions = ReactNative.PermissionsAndroid;
+const AsyncStorage = ReactNative.AsyncStorage
+
+const RNPTypes = {
+	location: RNPermissions.PERMISSIONS.ACCESS_FINE_LOCATION,
+	camera: RNPermissions.PERMISSIONS.CAMERA,
+	microphone: RNPermissions.PERMISSIONS.RECORD_AUDIO,
+	contacts: RNPermissions.PERMISSIONS.READ_CONTACTS,
+	event: RNPermissions.PERMISSIONS.READ_CALENDAR,
+	storage: RNPermissions.PERMISSIONS.READ_EXTERNAL_STORAGE,
+	photo: RNPermissions.PERMISSIONS.READ_EXTERNAL_STORAGE,
+}
+
+const RESULTS = {
+	[ RNPermissions.RESULTS.GRANTED ]: 'authorized',
+	[ RNPermissions.RESULTS.DENIED ]: 'denied',
+	[ RNPermissions.RESULTS.NEVER_ASK_AGAIN ]: 'restricted',
+}
+
+const STORAGE_KEY = '@RNPermissions:didAskPermission:'
+
+const setDidAskOnce = p => AsyncStorage.setItem(STORAGE_KEY + p, 'true')
+const getDidAskOnce = p =>  AsyncStorage.getItem(STORAGE_KEY + p).then(res => !!res)
+
+class ReactNativePermissions {
+	canOpenSettings() {
+		return false
+	}
+
+	openSettings() {
+		return Promise.reject('\'openSettings\' is Depricated on android')
+	}
+
+	getTypes() {
+		return Object.keys(RNPTypes);
+	}
+
+	check(permission) {
+		const androidPermission = RNPTypes[permission]
+  	if (!androidPermission) return Promise.reject(`ReactNativePermissions: ${permission} is not a valid permission type on Android`);
+		
+		const shouldShowRationale = ReactNative.NativeModules.PermissionsAndroid.shouldShowRequestPermissionRationale;
+
+		return RNPermissions.check(androidPermission)
+			.then(isAuthorized => {
+				if (isAuthorized) return 'authorized'
+
+				return getDidAskOnce(permission)
+					.then(didAsk => {
+						if (didAsk) {
+							return shouldShowRationale(androidPermission)
+								.then(shouldShow => shouldShow ? 'denied' : 'restricted')
+						}
+						return 'undetermined'
+					})
+			})
+	}
+
+
+	request(permission) {
+		const androidPermission = RNPTypes[permission]
+  	if (!androidPermission) return Promise.reject(`ReactNativePermissions: ${permission} is not a valid permission type on Android`);
+
+
+		return RNPermissions.request(androidPermission)
+			.then(res => {
+				return setDidAskOnce(permission)
+					.then(() => RESULTS[res])
+			});
+	}
+
+	checkMultiple(permissions) {
+		return Promise.all(permissions.map(this.check.bind(this)))
+			.then(res => res.reduce((pre, cur, i) => {
+				var name = permissions[i]
+				pre[name] = cur
+				return pre
+			}, {}))
+	}
+}
+
+module.exports = new ReactNativePermissions()

+ 70 - 0
index.ios.js

@@ -0,0 +1,70 @@
+'use strict';
+
+const ReactNative = require('react-native');
+const RNPermissions = ReactNative.NativeModules.ReactNativePermissions;
+
+const RNPTypes = [
+	'location',
+	'camera',
+	'microphone',
+	'photo',
+	'contacts',
+	'event',
+	'reminder',
+	'bluetooth',
+	'notification',
+	'backgroundRefresh',
+	'speechRecognition',
+]
+
+const DEFAULTS = {
+	'location' : 'whenInUse',
+	'notification': ['alert', 'badge', 'sound'],
+}
+
+class ReactNativePermissions {
+	canOpenSettings() {
+		return RNPermissions.canOpenSettings()
+	}
+
+	openSettings() {
+		return RNPermissions.openSettings()
+	}
+
+	getTypes() {
+		return RNPTypes;
+	}
+
+	check(permission, type) {
+  	if (!RNPTypes.includes(permission)) {
+			return Promise.reject(`ReactNativePermissions: ${permission} is not a valid permission type on iOS`);
+		}
+		
+		return RNPermissions.getPermissionStatus(permission, type);
+	}
+
+	request(permission, type) {
+		if (!RNPTypes.includes(permission)) {
+			return Promise.reject(`ReactNativePermissions: ${permission} is not a valid permission type on iOS`);
+		}
+
+		if (permission == 'backgroundRefresh') {
+			return Promise.reject('ReactNativePermissions: You cannot request backgroundRefresh')
+		}
+
+		type = type || DEFAULTS[permission]
+
+		return RNPermissions.requestPermission(permission, type)
+	}
+
+	checkMultiple(permissions) {
+		return Promise.all(permissions.map(this.check.bind(this)))
+			.then(res => res.reduce((pre, cur, i) => {
+				var name = permissions[i]
+				pre[name] = cur
+				return pre
+			}, {}))
+	}
+}
+
+module.exports = new ReactNativePermissions()

+ 7 - 3
package.json

@@ -1,13 +1,17 @@
 {
   "name": "react-native-permissions",
-  "version": "0.3.0",
+  "version": "1.0.0",
   "repository": {
     "type": "git",
     "url": "https://github.com/joshblour/react-native-permissions.git"
   },
+  "main": "index",
   "license": "MIT",
-  "keywords": ["react-native", "react-permissions", "permissions" ],
-  "main": "ReactNativePermissions",
+  "keywords": [
+    "react-native",
+    "react-permissions",
+    "permissions"
+  ],
   "author": "Yonah Forst <yonaforst@hotmail.com>",
   "homepage": "https://github.com/joshblour/react-native-permissions",
   "description": "Check user permissions in React Native"