浏览代码

Merge branch 'master' of git://github.com/yonahforst/react-native-permissions into motion-permission-request

Peter Lau 8 年之前
父节点
当前提交
ad1c633a6e
共有 95 个文件被更改,包括 1719 次插入805 次删除
  1. 9 0
      .flowconfig
  2. 74 0
      .github/CODE_OF_CONDUCT.md
  3. 26 0
      .github/ISSUE_TEMPLATE.md
  4. 15 10
      .gitignore
  5. 1 1
      .npmignore
  6. 3 0
      .prettierignore
  7. 5 0
      .prettierrc
  8. 0 46
      CODE_OF_CONDUCT.md
  9. 0 12
      Example/__tests__/index.android.js
  10. 0 12
      Example/__tests__/index.ios.js
  11. 0 14
      Example/index.android.js
  12. 0 14
      Example/index.ios.js
  13. 0 38
      Example/ios/Example/Images.xcassets/AppIcon.appiconset/Contents.json
  14. 0 23
      Example/package.json
  15. 239 167
      README.md
  16. 14 15
      ReactNativePermissions.podspec
  17. 0 7
      ReactNativePermissions.xcodeproj/project.xcworkspace/contents.xcworkspacedata
  18. 0 80
      ReactNativePermissions.xcodeproj/xcuserdata/Yonah.xcuserdatad/xcschemes/ReactNativePermissions.xcscheme
  19. 0 22
      ReactNativePermissions.xcodeproj/xcuserdata/Yonah.xcuserdatad/xcschemes/xcschememanagement.plist
  20. 0 0
      example/.babelrc
  21. 0 0
      example/.buckconfig
  22. 9 6
      example/.flowconfig
  23. 0 0
      example/.gitattributes
  24. 4 4
      example/.gitignore
  25. 0 0
      example/.watchmanconfig
  26. 51 52
      example/App.js
  27. 10 0
      example/__tests__/index.js
  28. 0 0
      example/android/app/BUCK
  29. 5 1
      example/android/app/build.gradle
  30. 0 0
      example/android/app/proguard-rules.pro
  31. 6 1
      example/android/app/src/main/AndroidManifest.xml
  32. 0 0
      example/android/app/src/main/java/com/example/MainActivity.java
  33. 5 0
      example/android/app/src/main/java/com/example/MainApplication.java
  34. 0 0
      example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
  35. 0 0
      example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
  36. 0 0
      example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
  37. 0 0
      example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
  38. 0 1
      example/android/app/src/main/res/values/strings.xml
  39. 0 0
      example/android/app/src/main/res/values/styles.xml
  40. 1 0
      example/android/build.gradle
  41. 0 0
      example/android/gradle.properties
  42. 0 0
      example/android/gradle/wrapper/gradle-wrapper.jar
  43. 1 2
      example/android/gradle/wrapper/gradle-wrapper.properties
  44. 0 0
      example/android/gradlew
  45. 0 0
      example/android/gradlew.bat
  46. 0 0
      example/android/keystores/BUCK
  47. 0 0
      example/android/keystores/debug.keystore.properties
  48. 0 0
      example/android/settings.gradle
  49. 4 0
      example/app.json
  50. 4 0
      example/index.js
  51. 0 0
      example/ios/Example-tvOS/Info.plist
  52. 0 0
      example/ios/Example-tvOSTests/Info.plist
  53. 217 34
      example/ios/Example.xcodeproj/project.pbxproj
  54. 0 0
      example/ios/Example.xcodeproj/xcshareddata/xcschemes/Example-tvOS.xcscheme
  55. 1 1
      example/ios/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme
  56. 0 0
      example/ios/Example/AppDelegate.h
  57. 1 1
      example/ios/Example/AppDelegate.m
  58. 0 0
      example/ios/Example/Base.lproj/LaunchScreen.xib
  59. 38 0
      example/ios/Example/Images.xcassets/AppIcon.appiconset/Contents.json
  60. 6 0
      example/ios/Example/Images.xcassets/Contents.json
  61. 5 1
      example/ios/Example/Info.plist
  62. 0 0
      example/ios/Example/main.m
  63. 0 0
      example/ios/ExampleTests/ExampleTests.m
  64. 0 0
      example/ios/ExampleTests/Info.plist
  65. 23 0
      example/package.json
  66. 0 91
      index.android.js
  67. 0 70
      index.ios.js
  68. 4 0
      index.js
  69. 0 0
      ios/Permissions/RNPAudioVideo.h
  70. 0 0
      ios/Permissions/RNPAudioVideo.m
  71. 0 0
      ios/Permissions/RNPBackgroundRefresh.h
  72. 0 0
      ios/Permissions/RNPBackgroundRefresh.m
  73. 0 0
      ios/Permissions/RNPBluetooth.h
  74. 0 0
      ios/Permissions/RNPBluetooth.m
  75. 0 0
      ios/Permissions/RNPContacts.h
  76. 0 0
      ios/Permissions/RNPContacts.m
  77. 0 0
      ios/Permissions/RNPEvent.h
  78. 0 0
      ios/Permissions/RNPEvent.m
  79. 0 0
      ios/Permissions/RNPLocation.h
  80. 0 0
      ios/Permissions/RNPLocation.m
  81. 0 0
      ios/Permissions/RNPNotification.h
  82. 0 0
      ios/Permissions/RNPNotification.m
  83. 0 0
      ios/Permissions/RNPPhoto.h
  84. 0 0
      ios/Permissions/RNPPhoto.m
  85. 0 0
      ios/Permissions/RNPSpeechRecognition.h
  86. 0 0
      ios/Permissions/RNPSpeechRecognition.m
  87. 0 0
      ios/RCTConvert+RNPStatus.h
  88. 0 1
      ios/RCTConvert+RNPStatus.m
  89. 0 1
      ios/ReactNativePermissions.h
  90. 5 1
      ios/ReactNativePermissions.m
  91. 74 64
      ios/ReactNativePermissions.xcodeproj/project.pbxproj
  92. 117 0
      lib/permissions.android.js
  93. 107 0
      lib/permissions.ios.js
  94. 21 12
      package.json
  95. 614 0
      yarn.lock

+ 9 - 0
.flowconfig

@@ -0,0 +1,9 @@
+[ignore]
+
+[include]
+
+[libs]
+
+[lints]
+
+[options]

+ 74 - 0
.github/CODE_OF_CONDUCT.md

@@ -0,0 +1,74 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, gender identity and expression, level of
+experience, nationality, personal appearance, race, religion, or sexual identity
+and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+  advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+  address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+  professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, or to ban temporarily or permanently any
+contributor for other behaviors that they deem inappropriate, threatening,
+offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project team at yonaforst@hotmail.com. The project
+team will review and investigate all complaints, and will respond in a way that
+it deems appropriate to the circumstances. The project team is obligated to
+maintain confidentiality with regard to the reporter of an incident. Further
+details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
+
+[homepage]: http://contributor-covenant.org
+[version]: http://contributor-covenant.org/version/1/4/

+ 26 - 0
.github/ISSUE_TEMPLATE.md

@@ -0,0 +1,26 @@
+Hello!
+
+Please read the following carefully before opening a new issue. Your issue may
+be closed if it doesn't provide the informations required.
+
+#### ⚠️ Delete everything above this line
+
+### Describe your environment
+
+* React-Native version
+* Platform: iOS, Android, both?
+* Device (which one?), simulator?
+* OS version
+* react-native-permissions version
+* Devtools: Xcode? Android Studio version?
+* (Android only: buildToolsVersion)
+
+### How to repeat issue and example
+
+Explain what you did, what you expected to happen, and what actually happens.
+Provide some code if needed.
+
+### Solution
+
+Do you know what needs to be done to address this issue? Ideally, provide a pull
+request with a fix.

+ 15 - 10
.gitignore

@@ -1,10 +1,15 @@
-android/react-native-permissions.iml
-android/build
-android/.idea
-npm-debug.log
-gradlew
-gradle-wrapper.properties
-gradle-wrapper.jar
-local.properties
-gradlew.bat
-android.iml
+*.xcworkspace
+xcuserdata
+
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+node_modules/
+
+*.DS_Store
+Thumbs.db
+Desktop.ini
+
+.vscode/
+
+android/build/

+ 1 - 1
.npmignore

@@ -1 +1 @@
-Example
+example/

+ 3 - 0
.prettierignore

@@ -0,0 +1,3 @@
+android/
+ios/
+example/node_modules/

+ 5 - 0
.prettierrc

@@ -0,0 +1,5 @@
+{
+  "singleQuote": true,
+  "trailingComma": "all",
+  "semi": false
+}

+ 0 - 46
CODE_OF_CONDUCT.md

@@ -1,46 +0,0 @@
-# Contributor Covenant Code of Conduct
-
-## Our Pledge
-
-In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
-
-## Our Standards
-
-Examples of behavior that contributes to creating a positive environment include:
-
-* Using welcoming and inclusive language
-* Being respectful of differing viewpoints and experiences
-* Gracefully accepting constructive criticism
-* Focusing on what is best for the community
-* Showing empathy towards other community members
-
-Examples of unacceptable behavior by participants include:
-
-* The use of sexualized language or imagery and unwelcome sexual attention or advances
-* Trolling, insulting/derogatory comments, and personal or political attacks
-* Public or private harassment
-* Publishing others' private information, such as a physical or electronic address, without explicit permission
-* Other conduct which could reasonably be considered inappropriate in a professional setting
-
-## Our Responsibilities
-
-Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
-
-Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
-
-## Scope
-
-This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
-
-## Enforcement
-
-Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at yonaforst@hotmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
-
-Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
-
-## Attribution
-
-This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
-
-[homepage]: http://contributor-covenant.org
-[version]: http://contributor-covenant.org/version/1/4/

+ 0 - 12
Example/__tests__/index.android.js

@@ -1,12 +0,0 @@
-import 'react-native';
-import React from 'react';
-import Index from '../index.android.js';
-
-// Note: test renderer must be required after react-native.
-import renderer from 'react-test-renderer';
-
-it('renders correctly', () => {
-  const tree = renderer.create(
-    <Index />
-  );
-});

+ 0 - 12
Example/__tests__/index.ios.js

@@ -1,12 +0,0 @@
-import 'react-native';
-import React from 'react';
-import Index from '../index.ios.js';
-
-// Note: test renderer must be required after react-native.
-import renderer from 'react-test-renderer';
-
-it('renders correctly', () => {
-  const tree = renderer.create(
-    <Index />
-  );
-});

+ 0 - 14
Example/index.android.js

@@ -1,14 +0,0 @@
-/**
- * Sample React Native App
- * https://github.com/facebook/react-native
- * @flow
- */
-
-import React, { Component } from 'react';
-import {
-  AppRegistry,
-} from 'react-native';
-
-import Example from './Example'
-
-AppRegistry.registerComponent('Example', () => Example);

+ 0 - 14
Example/index.ios.js

@@ -1,14 +0,0 @@
-/**
- * Sample React Native App
- * https://github.com/facebook/react-native
- * @flow
- */
-
-import React, { Component } from 'react';
-import {
-  AppRegistry,
-} from 'react-native';
-
-import Example from './Example'
-
-AppRegistry.registerComponent('Example', () => Example);

+ 0 - 38
Example/ios/Example/Images.xcassets/AppIcon.appiconset/Contents.json

@@ -1,38 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "iphone",
-      "size" : "29x29",
-      "scale" : "2x"
-    },
-    {
-      "idiom" : "iphone",
-      "size" : "29x29",
-      "scale" : "3x"
-    },
-    {
-      "idiom" : "iphone",
-      "size" : "40x40",
-      "scale" : "2x"
-    },
-    {
-      "idiom" : "iphone",
-      "size" : "40x40",
-      "scale" : "3x"
-    },
-    {
-      "idiom" : "iphone",
-      "size" : "60x60",
-      "scale" : "2x"
-    },
-    {
-      "idiom" : "iphone",
-      "size" : "60x60",
-      "scale" : "3x"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  }
-}

+ 0 - 23
Example/package.json

@@ -1,23 +0,0 @@
-{
-  "name": "Example",
-  "version": "0.0.1",
-  "private": true,
-  "scripts": {
-    "start": "react-native start",
-    "test": "jest"
-  },
-  "dependencies": {
-    "react": "^16.0.0-alpha.12",
-    "react-native": "^0.48.4",
-    "react-native-permissions": "../"
-  },
-  "devDependencies": {
-    "babel-jest": "18.0.0",
-    "babel-preset-react-native": "1.9.1",
-    "jest": "18.1.0",
-    "react-test-renderer": "15.4.2"
-  },
-  "jest": {
-    "preset": "react-native"
-  }
-}

+ 239 - 167
README.md

@@ -1,212 +1,230 @@
-# React Native Permissions
-Request user permissions from React Native, iOS + Android
+# ☝🏼 React Native Permissions
 
-The current supported permissions are:
-- Location
-- Camera
-- Microphone
-- Photos
-- Contacts
-- Events
-- Reminders *(iOS only)*
-- Bluetooth *(iOS only)*
-- Push Notifications *(iOS only)*
-- Background Refresh *(iOS only)*
-- Speech Recognition *(iOS only)*
-- Core Motion *(iOS only)*
-- Call Phone *(Android Only)*
-- Read/Receive SMS *(Android only)*
+[![npm version](https://badge.fury.io/js/react-native-permissions.svg)](https://badge.fury.io/js/react-native-permissions)
+[![npm](https://img.shields.io/npm/dt/react-native-permissions.svg)](https://www.npmjs.org/package/react-native-permissions)
+![Platform - Android and iOS](https://img.shields.io/badge/platform-Android%20%7C%20iOS-yellow.svg)
+![MIT](https://img.shields.io/dub/l/vibe-d.svg)
+[![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier)
 
+Request user permissions from React Native, iOS + Android
 
 | Version | React Native Support |
-|---|---|
-| 1.0.1 | 0.40.0 - 0.48.4 |
-| 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)*
-
-### Breaking changes in version 1.0.0
-  - Now using React Native's own JS PermissionsAndroid library on Android, which is great because now we no longer have to do any additional linking (on Android)
-  - Updated API to be closer to RN's PermissionsAndroid
-  - Removed `openSettings()` support on Android (to stay linking-free). There are several NPM modules available for this
-  - `restricted` status now supported on Android, although it means something different than iOS
-
-## General Usage
-```
+| ------- | -------------------- |
+| 1.0.6   | 0.40 - 0.51          |
+| 0.2.5   | 0.33 - 0.39          |
+
+_Complies with
+[react-native-version-support-table](https://github.com/dangnelson/react-native-version-support-table)_
+
+## ⚠️ Breaking changes in version 1.0.0
+
+* Now using React Native's own JS `PermissionsAndroid` module on Android, which
+  is great because we no longer have to do any additional linking on Android
+* Updated API to be closer to React Native's `PermissionsAndroid`
+* Removed `openSettings()` support on Android (to stay linking-free). There are
+  several NPM modules available for this
+* `restricted` status now supported on Android, although it means something
+  different than iOS
+
+## Setup
+
+```sh
 npm install --save react-native-permissions
-react-native link
+# --- or ---
+yarn add react-native-permissions
+```
+
+_📌 Don't forget to add permissions to `AndroidManifest.xml` for android and
+`Info.plist` for iOS (Xcode >= 8). See [iOS Notes](#ios-notes) or [Android Notes](#android-notes) for more details._
+
+### Additional iOS setup
+
+#### Using cocoaPods
+
+Update the following line with your path to `node_modules/` and add it to your
+podfile:
+
+```ruby
+pod 'ReactNativePermissions', :path => '../node_modules/react-native-permissions'
 ```
 
-Add permissions to manifest for android and info.plist for ios (xcode >=8). See notes below for more details.
+#### Using react-native link
+
+```sh
+react-native link react-native-permissions
+```
+
+#### Using manual linking
+
+1. In the XCode's "Project navigator", right click on your project's Libraries
+   folder ➜ `Add Files to <...>`
+2. Go to `node_modules` ➜ `react-native-permissions` ➜ select
+   `ReactNativePermissions.xcodeproj`
+3. Add `libReactNativePermissions.a` to `Build Phases` -> `Link Binary With
+   Libraries`
+
+## Using
 
 ```js
-const Permissions = require('react-native-permissions');
+import Permissions from 'react-native-permissions'
+// OR const Permissions = require('react-native-permissions').default
+// if you use CommonJS module system
 
 //...
-  //check the status of a single permission
+
+export default class extends React.Component {
+  //...
+
+  // Check the status of a single permission
   componentDidMount() {
-    Permissions.check('photo')
-      .then(response => {
-        //response is one of: 'authorized', 'denied', 'restricted', or 'undetermined'
-        this.setState({ photoPermission: response })
-      });
+    Permissions.check('photo').then(response => {
+      // Response is one of: 'authorized', 'denied', 'restricted', or 'undetermined'
+      this.setState({ photoPermission: response })
+    })
   }
 
-  //request permission to access photos
-  _requestPermission() {
-    Permissions.request('photo')
-      .then(response => {
-        //returns once the user has chosen to 'allow' or to 'not allow' access
-        //response is one of: 'authorized', 'denied', 'restricted', or 'undetermined'
-        this.setState({ photoPermission: response })
-      });
+  // Request permission to access photos
+  _requestPermission = () => {
+    Permissions.request('photo').then(response => {
+      // Returns once the user has chosen to 'allow' or to 'not allow' access
+      // Response is one of: 'authorized', 'denied', 'restricted', or 'undetermined'
+      this.setState({ photoPermission: response })
+    })
   }
 
-  //check the status of multiple permissions
-  _checkCameraAndPhotos() {
-    Permissions.checkMultiple(['camera', 'photo'])
-      .then(response => {
-        //response is an object mapping type to permission
-        this.setState({
-          cameraPermission: response.camera,
-          photoPermission: response.photo,
-        })
-      });
+  // Check the status of multiple permissions
+  _checkCameraAndPhotos = () => {
+    Permissions.checkMultiple(['camera', 'photo']).then(response => {
+      //response is an object mapping type to permission
+      this.setState({
+        cameraPermission: response.camera,
+        photoPermission: response.photo,
+      })
+    })
   }
 
-  // this is a common pattern when asking for permissions.
+  // This is a common pattern when asking for permissions.
   // iOS only gives you once chance to show the permission dialog,
   // after which the user needs to manually enable them from settings.
-  // the idea here is to explain why we need access and determine if
+  // The idea here is to explain why we need access and determine if
   // the user will say no, so that we don't blow our one chance.
-  // if the user already denied access, we can ask them to enable it from settings.
+  // If the user already denied access, we can ask them to enable it from settings.
   _alertForPhotosPermission() {
     Alert.alert(
       'Can we access your photos?',
       'We need access so you can set your profile pic',
       [
-        {text: 'No way', onPress: () => console.log('permission denied'), style: 'cancel'},
-        this.state.photoPermission == 'undetermined'?
-          {text: 'OK', onPress: this._requestPermission.bind(this)}
-          : {text: 'Open Settings', onPress: Permissions.openSettings}
-      ]
+        {
+          text: 'No way',
+          onPress: () => console.log('Permission denied'),
+          style: 'cancel',
+        },
+        this.state.photoPermission == 'undetermined'
+          ? { text: 'OK', onPress: this._requestPermission }
+          : { text: 'Open Settings', onPress: Permissions.openSettings },
+      ],
     )
   }
-//...
-```
-
-## API
-
-### Permission statuses
-Promises resolve into one of these statuses
-
-| Return value | Notes|
-|---|---|
-|`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** - 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
-
-| Name | iOS | Android |
-|---|---|---|
-|`location`| ✔️ | ✔ |
-|`camera`| ✔️ | ✔ |
-|`microphone`| ✔️ | ✔ |
-|`photo`| ✔️ | ✔ |
-|`contacts`| ✔️ | ✔ |
-|`event`| ✔️ | ✔ |
-|`bluetooth`| ✔️ | ❌ |
-|`reminder`| ✔️ | ❌ |
-|`notification`| ✔️ | ❌ |
-|`backgroundRefresh`| ✔️ | ❌ |
-|`speechRecognition`| ✔️ | ❌ |
-|`motion`| ✔️ | ❌ |
-|`storage`| ❌️ | ✔ |
-|`callPhone`| ❌️ | ✔ |
-|`readSms`| ❌️ | ✔ |
-|`receiveSms`| ❌️ | ✔ |
-
-### Methods
-| Method Name | Arguments | Notes
-|---|---|---|
-| `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 `location` accepts a second parameter for `request()` and `check()`;  the second parameter is a string, either `always` or `whenInUse`(default).
 
-- Permission type `notification` accepts a second parameter for `request()`. 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.check('location', 'always')
-      .then(response => {
-        this.setState({ locationPermission: response })
-      })
-
-    Permissions.request('location', 'always')
-      .then(response => {
-        this.setState({ locationPermission: response })
-      })
-
-    Permissions.request('notification', ['alert', 'badge'])
-      .then(response => {
-        this.setState({ notificationPermission: response })
-      })
+  //...
+}
 ```
 
-You cannot request microphone permissions on the simulator.
+## API
 
-With Xcode 8, you now need to add usage descriptions for each permission you will request. Open Xcode > Info.plist > Add a key (starting with "Privacy - ...") with your kit specific permission.
+### Permissions statuses
 
-Example:
-If you need Contacts permission you have to add the key "Privacy - Contacts Usage Description".
-<img width="338" alt="3cde3b44-7ffd-11e6-918b-63888e33f983" src="https://cloud.githubusercontent.com/assets/1440796/18713019/271be540-8011-11e6-87fb-c3828c172dfc.png">
+Promises resolve into one of these statuses:
 
-### Android Notes
+| Return value   | Notes                                                                                                                                                                                                                                                                  |
+| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `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 prompted multiple times until they select 'Never ask me again'                                                                          |
+| `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                                                                                                                                                                                                                |
 
-Requires RN >= 0.29.0
+### Supported permissions types
 
-Uses RN's own `PermissionsAndroid` JS api (http://facebook.github.io/react-native/releases/0.45/docs/permissionsandroid.html)
+The current supported permissions are:
 
-All required permissions also need to be included in the Manifest before they can be requested. Otherwise `request()` will immediately return `denied`.
+|                    | Type                | iOS | Android |
+| ------------------ | ------------------- | --- | ------- |
+| Location           | `location`          | ✔️  | ✔       |
+| Camera             | `camera`            | ✔️  | ✔       |
+| Microphone         | `microphone`        | ✔️  | ✔       |
+| Photos             | `photo`             | ✔️  | ✔       |
+| Contacts           | `contacts`          | ✔️  | ✔       |
+| Events             | `event`             | ✔️  | ✔       |
+| Bluetooth          | `bluetooth`         | ✔️  | ❌      |
+| Reminders          | `reminder`          | ✔️  | ❌      |
+| Push Notifications | `notification`      | ✔️  | ❌      |
+| Background Refresh | `backgroundRefresh` | ✔️  | ❌      |
+| Speech Recognition | `speechRecognition` | ✔️  | ❌      |
+| Motion Activity    | `motion`            | ✔️  | ❌      |
+| Storage            | `storage`           | ❌️ | ✔       |
+| Phone Call         | `callPhone`         | ❌️ | ✔       |
+| Read SMS           | `readSms`           | ❌️ | ✔       |
+| Receive SMS        | `receiveSms`        | ❌️ | ✔       |
 
-Permissions are automatically accepted for targetSdkVersion < 23 but you can still use `check()` to check if the user has disabled them from Settings.
+### Methods
 
-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
+| Method Name         | Arguments | Notes                                                                                                                                                                                                                                                                            |
+| ------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `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                                                                                                                                                                                |
 
-## Setup
+### iOS Notes
 
-````
-npm install --save react-native-permissions
-react-native link
-````
+* 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 `request()` and
+  `check()`; the second parameter is a string, either `always` or `whenInUse`
+  (default).
+* Permission type `notification` accepts a second parameter for `request()`. The
+  second parameter is an array with the desired alert types. Any combination of
+  `alert`, `badge` and `sound` (default requests all three).
 
-### Or manually linking
+```js
+// example
+Permissions.check('location', { type: 'always' }).then(response => {
+  this.setState({ locationPermission: response })
+})
+
+Permissions.request('location', { type: 'always' }).then(response => {
+  this.setState({ locationPermission: response })
+})
+
+Permissions.request('notification', { type: ['alert', 'badge'] }).then(
+  response => {
+    this.setState({ notificationPermission: response })
+  },
+)
+```
 
-#### iOS
-* Run open node_modules/react-native-permissions
-* Drag ReactNativePermissions.xcodeproj into the Libraries group of your app's Xcode project
-* Add libReactNativePermissions.a to `Build Phases -> Link Binary With Libraries.
+* You cannot request microphone permissions on the simulator.
+* With Xcode 8, you now need to add usage descriptions for each permission you
+  will request. Open Xcode ➜ `Info.plist` ➜ Add a key (starting with "Privacy -
+  ...") with your kit specific permission.
 
-#### Android
-  No additional linking required
+Example: If you need Contacts permission you have to add the key `Privacy -
+Contacts Usage Description`.
 
-## AppStore submission disclaimer
+<img width="338" alt="3cde3b44-7ffd-11e6-918b-63888e33f983" src="https://cloud.githubusercontent.com/assets/1440796/18713019/271be540-8011-11e6-87fb-c3828c172dfc.png">
 
-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**.
+#### App Store submission disclaimer
 
-So before submitting your app to the `AppStore`, make sure that in your `Info.plist` you have the following keys:
+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**.
 
-```
+So before submitting your app to the App Store, make sure that in your
+`Info.plist` you have the following keys:
 
+```xml
 <key>NSBluetoothPeripheralUsageDescription</key>
 <string>Some description</string>
 <key>NSCalendarsUsageDescription</key>
@@ -215,25 +233,79 @@ So before submitting your app to the `AppStore`, make sure that in your `Info.pl
 <string>Some description</string>
 <key>NSLocationWhenInUseUsageDescription</key>
 <string>Some description</string>
+<key>NSPhotoLibraryAddUsageDescription</key>
+<string>Some description</string>
 <key>NSPhotoLibraryUsageDescription</key>
 <string>Some description</string>
 <key>NSSpeechRecognitionUsageDescription</key>
 <string>Some description</string>
 <key>NSMotionUsageDescription</key>
 <string>Some description</string>
+```
+
+This is required because during the phase of processing in the App Store
+submission, the system detects that you app contains code to request the
+permission `X` but don't have the `UsageDescription` key and then it rejects the
+build.
+
+> Please note that it will only be shown to the users the usage descriptions of
+> the permissions you really require in your app.
+
+You can find more information about this issue in #46.
+
+### Android Notes
+
+* Uses React Native's own
+  [`PermissionsAndroid` JS API](http://facebook.github.io/react-native/docs/permissionsandroid.html).
+* All required permissions also need to be included in the `AndroidManifest.xml`
+  file before they can be requested. Otherwise `request()` will immediately
+  return `denied`.
+* You can request write access to any of these types by also including the
+  appropriate write permission in the `AndroidManifest.xml` file. Read more
+  [here](https://developer.android.com/guide/topics/security/permissions.html#normal-dangerous).
 
+* The optional rationale argument will show a dialog prompt.
+
+```js
+// example
+Permissions.request('camera', {
+  rationale: {
+    title: 'Cool Photo App Camera Permission',
+    message:
+      'Cool Photo App needs access to your camera ' +
+      'so you can take awesome pictures.',
+  },
+}).then(response => {
+  this.setState({ cameraPermission: response })
+})
 ```
 
-This is required because during the phase of `processing` in the `AppStore` submission, the system detects that you app contains code to request the permission `X` but don't have the `UsageDescription` key and rejects the build.
+* Permissions are automatically accepted for **targetSdkVersion < 23** but you
+  can still use `check()` to check if the user has disabled them from Settings.
 
-> Please note that it will only be shown to the users the usage descriptions of the permissions you really require in your app.
+You might need to elevate the **targetSdkVersion** version in your
+`build.gradle`:
 
-You can find more informations about this issue in #46.
+```groovy
+android {
+  compileSdkVersion 23 // ← set at least 23
+  buildToolsVersion "23.0.1"  // ← set at least 23.0.0
+
+  defaultConfig {
+    minSdkVersion 16
+    targetSdkVersion 23 // ← set at least 23
+    // ...
+```
 
 ## Troubleshooting
 
-#### 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.
+#### 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](https://github.com/jesperlndk)
+> for discovering this.
+
+#### Q: iOS - App crashes when I change permission from settings
 
-#### Q: iOS - app crashes when I change permissions from settings
-A: This is normal. iOS restarts your app when your privacy settings change. Just google "ios crash permission change"
+> A: This is normal. iOS restarts your app when your privacy settings change.
+> Just google "iOS crash permission change"

+ 14 - 15
ReactNativePermissions.podspec

@@ -3,21 +3,20 @@ require 'json'
 package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
 
 Pod::Spec.new do |s|
-  s.name                = 'ReactNativePermissions'
-  s.version             = package['version']
-  s.summary             = package['description']
-  s.description         = package['description']
-  s.homepage            = package['homepage']
-  s.license             = package['license']
-  s.author              = package['author']
-  s.source              = { :git => 'https://github.com/yonahforst/react-native-permissions.git', :tag => s.version }
+  s.name                   = 'ReactNativePermissions'
+  s.version                = package['version']
+  s.summary                = package['description']
+  s.description            = package['description']
+  s.homepage               = package['homepage']
+  s.license                = package['license']
+  s.author                 = package['author']
+  s.source                 = { :git => 'https://github.com/yonahforst/react-native-permissions.git', :tag => s.version }
 
-  s.platform              = :ios, '9.0'
-  s.ios.deployment_target = '8.0'
+  s.platform               = :ios, '9.0'
+  s.ios.deployment_target  = '8.0'
 
-  s.dependency 'React'
-
-  s.preserve_paths      = 'docs', 'CHANGELOG.md', 'LICENSE', 'package.json', 'ReactNativePermissions.ios.js'
-  s.source_files        = '**/*.{h,m}'
-  s.exclude_files       = 'Example/**/*'
+  s.preserve_paths         = 'LICENSE', 'package.json'
+  s.source_files           = '**/*.{h,m}'
+  s.exclude_files          = 'example/**/*'
+  s.dependency               'React'
 end

+ 0 - 7
ReactNativePermissions.xcodeproj/project.xcworkspace/contents.xcworkspacedata

@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Workspace
-   version = "1.0">
-   <FileRef
-      location = "self:ReactNativePermissions.xcodeproj">
-   </FileRef>
-</Workspace>

+ 0 - 80
ReactNativePermissions.xcodeproj/xcuserdata/Yonah.xcuserdatad/xcschemes/ReactNativePermissions.xcscheme

@@ -1,80 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "0710"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-      <BuildActionEntries>
-         <BuildActionEntry
-            buildForTesting = "YES"
-            buildForRunning = "YES"
-            buildForProfiling = "YES"
-            buildForArchiving = "YES"
-            buildForAnalyzing = "YES">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "9D23B34E1C767B80008B4819"
-               BuildableName = "libReactNativePermissions.a"
-               BlueprintName = "ReactNativePermissions"
-               ReferencedContainer = "container:ReactNativePermissions.xcodeproj">
-            </BuildableReference>
-         </BuildActionEntry>
-      </BuildActionEntries>
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES">
-      <Testables>
-      </Testables>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "9D23B34E1C767B80008B4819"
-            BuildableName = "libReactNativePermissions.a"
-            BlueprintName = "ReactNativePermissions"
-            ReferencedContainer = "container:ReactNativePermissions.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "9D23B34E1C767B80008B4819"
-            BuildableName = "libReactNativePermissions.a"
-            BlueprintName = "ReactNativePermissions"
-            ReferencedContainer = "container:ReactNativePermissions.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Debug">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>

+ 0 - 22
ReactNativePermissions.xcodeproj/xcuserdata/Yonah.xcuserdatad/xcschemes/xcschememanagement.plist

@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>SchemeUserState</key>
-	<dict>
-		<key>ReactNativePermissions.xcscheme</key>
-		<dict>
-			<key>orderHint</key>
-			<integer>0</integer>
-		</dict>
-	</dict>
-	<key>SuppressBuildableAutocreation</key>
-	<dict>
-		<key>9D23B34E1C767B80008B4819</key>
-		<dict>
-			<key>primary</key>
-			<true/>
-		</dict>
-	</dict>
-</dict>
-</plist>

+ 0 - 0
Example/.babelrc → example/.babelrc


+ 0 - 0
Example/.buckconfig → example/.buckconfig


+ 9 - 6
Example/.flowconfig → example/.flowconfig

@@ -12,14 +12,15 @@
 ; For RN Apps installed via npm, "Libraries" folder is inside
 ; "node_modules/react-native" but in the source repo it is in the root
 .*/Libraries/react-native/React.js
-.*/Libraries/react-native/ReactNative.js
+
+; Ignore polyfills
+.*/Libraries/polyfills/.*
 
 [include]
 
 [libs]
 node_modules/react-native/Libraries/react-native/react-native-interface.js
-node_modules/react-native/flow
-flow/
+node_modules/react-native/flow/
 
 [options]
 emoji=true
@@ -32,14 +33,16 @@ module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|we
 
 suppress_type=$FlowIssue
 suppress_type=$FlowFixMe
+suppress_type=$FlowFixMeProps
+suppress_type=$FlowFixMeState
 suppress_type=$FixMe
 
-suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(4[0-9]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
-suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(4[0-9]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
+suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(5[0-6]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
+suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(5[0-6]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
 suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
 suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
 
 unsafe.enable_getters_and_setters=true
 
 [version]
-^0.49.1
+^0.56.0

+ 0 - 0
Example/.gitattributes → example/.gitattributes


+ 4 - 4
Example/.gitignore → example/.gitignore

@@ -46,8 +46,8 @@ buck-out/
 # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
 # screenshots whenever they are needed.
 # For more information about the recommended setup visit:
-# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
+# https://docs.fastlane.tools/best-practices/source-control/
 
-fastlane/report.xml
-fastlane/Preview.html
-fastlane/screenshots
+*/fastlane/report.xml
+*/fastlane/Preview.html
+*/fastlane/screenshots

+ 0 - 0
Example/.watchmanconfig → example/.watchmanconfig


+ 51 - 52
Example/Example.js → example/App.js

@@ -1,10 +1,6 @@
-/**
- * Sample React Native App
- * https://github.com/facebook/react-native
- * @flow
- */
+// @flow
 
-import React, { Component } from 'react';
+import React, { Component } from 'react'
 import {
   StyleSheet,
   TouchableHighlight,
@@ -13,11 +9,11 @@ import {
   Alert,
   AppState,
   Platform,
-} from 'react-native';
+} from 'react-native'
 
 import Permissions from 'react-native-permissions'
 
-export default class Example extends Component {
+export default class App extends Component {
   state = {
     types: [],
     status: {},
@@ -29,38 +25,38 @@ export default class Example extends Component {
 
     this.setState({ types, canOpenSettings })
     this._updatePermissions(types)
-    AppState.addEventListener('change', this._handleAppStateChange.bind(this));
+    AppState.addEventListener('change', this._handleAppStateChange)
   }
 
   componentWillUnmount() {
-    AppState.removeEventListener('change', this._handleAppStateChange.bind(this));
+    AppState.removeEventListener('change', this._handleAppStateChange)
   }
 
   //update permissions when app comes back from settings
-  _handleAppStateChange(appState) {
+  _handleAppStateChange = appState => {
     if (appState == 'active') {
       this._updatePermissions(this.state.types)
     }
   }
 
-  _openSettings() {
-    return Permissions.openSettings()
-      .then(() => alert('back to app!!'))
-  }
+  _openSettings = () =>
+    Permissions.openSettings().then(() => alert('back to app!!'))
 
-  _updatePermissions(types) {
+  _updatePermissions = types => {
     Permissions.checkMultiple(types)
       .then(status => {
         if (this.state.isAlways) {
-          return Permissions.check('location', 'always')
-            .then(location => ({...status, location}))
+          return Permissions.check('location', 'always').then(location => ({
+            ...status,
+            location,
+          }))
         }
         return status
       })
       .then(status => this.setState({ status }))
   }
 
-  _requestPermission(permission) {
+  _requestPermission = permission => {
     var options
 
     if (permission == 'location') {
@@ -70,22 +66,27 @@ export default class Example extends Component {
     Permissions.request(permission, options)
       .then(res => {
         this.setState({
-          status: {...this.state.status, [permission]: res}
+          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) })
-          
+          if (this.state.canOpenSettings)
+            buttons.push({
+              text: 'Open Settings',
+              onPress: this._openSettings,
+            })
+
           Alert.alert(
             'Whoops!',
-            "There was a problem getting your permission. Please enable it from settings.",
-            buttons
+            'There was a problem getting your permission. Please enable it from settings.',
+            buttons,
           )
         }
-      }).catch(e => console.warn(e))
+      })
+      .catch(e => console.warn(e))
   }
 
-  _onLocationSwitchChange() {
+  _onLocationSwitchChange = () => {
     this.setState({ isAlways: !this.state.isAlways })
     this._updatePermissions(this.state.types)
   }
@@ -93,46 +94,44 @@ export default class Example extends Component {
   render() {
     return (
       <View style={styles.container}>
-
         {this.state.types.map(p => (
-          <TouchableHighlight 
+          <TouchableHighlight
             style={[styles.button, styles[this.state.status[p]]]}
             key={p}
-            onPress={this._requestPermission.bind(this, p)}>
+            onPress={() => this._requestPermission(p)}
+          >
             <View>
               <Text style={styles.text}>
-                {Platform.OS == 'ios' && p == 'location' ? `location ${this.state.isAlways ? 'always' : 'whenInUse'}` : p}
-              </Text>
-              <Text style={styles.subtext}>
-                {this.state.status[p]}
+                {Platform.OS == 'ios' && p == 'location'
+                  ? `location ${this.state.isAlways ? 'always' : 'whenInUse'}`
+                  : p}
               </Text>
+              <Text style={styles.subtext}>{this.state.status[p]}</Text>
             </View>
           </TouchableHighlight>
-          )
-        )}
+        ))}
         <View style={styles.footer}>
-          <TouchableHighlight 
-            style={styles['footer_'+Platform.OS]}
-            onPress={this._onLocationSwitchChange.bind(this)}>
+          <TouchableHighlight
+            style={styles['footer_' + Platform.OS]}
+            onPress={this._onLocationSwitchChange}
+          >
             <Text style={styles.text}>Toggle location type</Text>
           </TouchableHighlight>
-   
-          {
-            this.state.canOpenSettings &&
-            <TouchableHighlight 
-              onPress={this._openSettings.bind(this)}>
+
+          {this.state.canOpenSettings && (
+            <TouchableHighlight onPress={this._openSettings}>
               <Text style={styles.text}>Open settings</Text>
             </TouchableHighlight>
-          }
-
+          )}
         </View>
 
-
-        <Text style={styles['footer_'+Platform.OS]}>
-          Note: microphone permissions may not work on iOS simulator. Also, toggling permissions from the settings menu may cause the app to crash. This is normal on iOS. Google "ios crash permission change"
+        <Text style={styles['footer_' + Platform.OS]}>
+          Note: microphone permissions may not work on iOS simulator. Also,
+          toggling permissions from the settings menu may cause the app to
+          crash. This is normal on iOS. Google "ios crash permission change"
         </Text>
       </View>
-    );
+    )
   }
 }
 
@@ -169,7 +168,7 @@ const styles = StyleSheet.create({
     backgroundColor: '#ef9a9a',
   },
   restricted: {
-    backgroundColor: '#ef9a9a'
+    backgroundColor: '#ef9a9a',
   },
   footer: {
     padding: 10,
@@ -179,5 +178,5 @@ const styles = StyleSheet.create({
   footer_android: {
     height: 0,
     width: 0,
-  }
-})
+  },
+})

+ 10 - 0
example/__tests__/index.js

@@ -0,0 +1,10 @@
+import 'react-native'
+import React from 'react'
+import Index from '../index.js'
+
+// Note: test renderer must be required after react-native.
+import renderer from 'react-test-renderer'
+
+it('renders correctly', () => {
+  const tree = renderer.create(<Index />)
+})

+ 0 - 0
Example/android/app/BUCK → example/android/app/BUCK


+ 5 - 1
Example/android/app/build.gradle → example/android/app/build.gradle

@@ -72,6 +72,10 @@ import com.android.build.OutputFile
  * ]
  */
 
+project.ext.react = [
+    entryFile: "index.js"
+]
+
 apply from: "../../node_modules/react-native/react.gradle"
 
 /**
@@ -95,7 +99,7 @@ android {
 
     defaultConfig {
         applicationId "com.example"
-        minSdkVersion 21
+        minSdkVersion 16
         targetSdkVersion 23
         versionCode 1
         versionName "1.0"

+ 0 - 0
Example/android/app/proguard-rules.pro → example/android/app/proguard-rules.pro


+ 6 - 1
Example/android/app/src/main/AndroidManifest.xml → example/android/app/src/main/AndroidManifest.xml

@@ -8,6 +8,7 @@
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
     <uses-permission android:name="android.permission.CAMERA"/>
     <uses-permission android:name="android.permission.RECORD_AUDIO"/>
+    <uses-permission android:name="android.permission.CALL_PHONE"/>
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.READ_CONTACTS"/>
@@ -15,9 +16,13 @@
     <uses-permission android:name="android.permission.READ_SMS"/>
     <uses-permission android:name="android.permission.RECEIVE_SMS"/>
 
+    <uses-sdk
+        android:minSdkVersion="16"
+        android:targetSdkVersion="23" />
+
     <application
       android:name=".MainApplication"
-      android:allowBackup="true"
+      android:allowBackup="false"
       android:label="@string/app_name"
       android:icon="@mipmap/ic_launcher"
       android:theme="@style/AppTheme">

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


+ 5 - 0
Example/android/app/src/main/java/com/example/MainApplication.java → example/android/app/src/main/java/com/example/MainApplication.java

@@ -25,6 +25,11 @@ public class MainApplication extends Application implements ReactApplication {
           new MainReactPackage()
       );
     }
+
+    @Override
+    protected String getJSMainModuleName() {
+      return "index";
+    }
   };
 
   @Override

+ 0 - 0
Example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png → example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png


+ 0 - 0
Example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png → example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png


+ 0 - 0
Example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png → example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png


+ 0 - 0
Example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png → example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png


+ 0 - 1
Example/android/app/src/main/res/values/strings.xml → example/android/app/src/main/res/values/strings.xml

@@ -1,4 +1,3 @@
 <resources>
-
     <string name="app_name">Example</string>
 </resources>

+ 0 - 0
Example/android/app/src/main/res/values/styles.xml → example/android/app/src/main/res/values/styles.xml


+ 1 - 0
Example/android/build.gradle → example/android/build.gradle

@@ -6,6 +6,7 @@ buildscript {
     }
     dependencies {
         classpath 'com.android.tools.build:gradle:2.2.3'
+
         // NOTE: Do not place your application dependencies here; they belong
         // in the individual module build.gradle files
     }

+ 0 - 0
Example/android/gradle.properties → example/android/gradle.properties


+ 0 - 0
Example/android/gradle/wrapper/gradle-wrapper.jar → example/android/gradle/wrapper/gradle-wrapper.jar


+ 1 - 2
Example/android/gradle/wrapper/gradle-wrapper.properties → example/android/gradle/wrapper/gradle-wrapper.properties

@@ -1,6 +1,5 @@
-#Fri Feb 03 16:27:32 CET 2017
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip

+ 0 - 0
Example/android/gradlew → example/android/gradlew


+ 0 - 0
Example/android/gradlew.bat → example/android/gradlew.bat


+ 0 - 0
Example/android/keystores/BUCK → example/android/keystores/BUCK


+ 0 - 0
Example/android/keystores/debug.keystore.properties → example/android/keystores/debug.keystore.properties


+ 0 - 0
Example/android/settings.gradle → example/android/settings.gradle


+ 4 - 0
example/app.json

@@ -0,0 +1,4 @@
+{
+  "name": "Example",
+  "displayName": "Example"
+}

+ 4 - 0
example/index.js

@@ -0,0 +1,4 @@
+import { AppRegistry } from 'react-native'
+import App from './App'
+
+AppRegistry.registerComponent('Example', () => App)

+ 0 - 0
Example/ios/Example-tvOS/Info.plist → example/ios/Example-tvOS/Info.plist


+ 0 - 0
Example/ios/Example-tvOSTests/Info.plist → example/ios/Example-tvOSTests/Info.plist


+ 217 - 34
Example/ios/Example.xcodeproj/project.pbxproj → example/ios/Example.xcodeproj/project.pbxproj

@@ -25,7 +25,7 @@
 		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 */; };
-		2D02E4C21E0B4AEC006451C7 /* libRCTAnimation-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation-tvOS.a */; };
+		2D02E4C21E0B4AEC006451C7 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation.a */; };
 		2D02E4C31E0B4AEC006451C7 /* libRCTImage-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */; };
 		2D02E4C41E0B4AEC006451C7 /* libRCTLinking-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */; };
 		2D02E4C51E0B4AEC006451C7 /* libRCTNetwork-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */; };
@@ -35,7 +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 */; };
+		66AE23241FE44648000AEC3F /* libReactNativePermissions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 66AE23231FE44628000AEC3F /* libReactNativePermissions.a */; };
 		832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
 		ADBDB9381DFEBF1600ED6528 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */; };
 /* End PBXBuildFile section */
@@ -216,6 +216,76 @@
 			remoteGlobalIDString = 2D2A28201D9B03D100D4039D;
 			remoteInfo = "RCTAnimation-tvOS";
 		};
+		661E35331FD3107F00C328EA /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 139D7ECE1E25DB7D00323FB7;
+			remoteInfo = "third-party";
+		};
+		661E35351FD3107F00C328EA /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 3D383D3C1EBD27B6005632C8;
+			remoteInfo = "third-party-tvOS";
+		};
+		661E35371FD3107F00C328EA /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 139D7E881E25C6D100323FB7;
+			remoteInfo = "double-conversion";
+		};
+		661E35391FD3107F00C328EA /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 3D383D621EBD27B9005632C8;
+			remoteInfo = "double-conversion-tvOS";
+		};
+		661E353B1FD3107F00C328EA /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 9936F3131F5F2E4B0010BF04;
+			remoteInfo = privatedata;
+		};
+		661E353D1FD3107F00C328EA /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 9936F32F1F5F2E5B0010BF04;
+			remoteInfo = "privatedata-tvOS";
+		};
+		66AE23221FE44628000AEC3F /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 14B7951690F04106A4A8E60E /* ReactNativePermissions.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 9D23B34F1C767B80008B4819;
+			remoteInfo = ReactNativePermissions;
+		};
+		66F16BED1FC608A800E71FEB /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = ADD01A681E09402E00F6D226;
+			remoteInfo = "RCTBlob-tvOS";
+		};
+		66F16BFF1FC608A800E71FEB /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 3DBE0D001F3B181A0099AA32;
+			remoteInfo = fishhook;
+		};
+		66F16C011FC608A800E71FEB /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 3DBE0D0D1F3B181C0099AA32;
+			remoteInfo = "fishhook-tvOS";
+		};
 		78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */ = {
 			isa = PBXContainerItemProxy;
 			containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;
@@ -259,10 +329,9 @@
 		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>"; };
+		14B7951690F04106A4A8E60E /* ReactNativePermissions.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = ReactNativePermissions.xcodeproj; path = "../node_modules/react-native-permissions/ios/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>"; };
 		832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = "<group>"; };
@@ -295,7 +364,7 @@
 				832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */,
 				00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */,
 				139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */,
-				6D05A8F55CC4482AACFFC932 /* libReactNativePermissions.a in Frameworks */,
+				66AE23241FE44648000AEC3F /* libReactNativePermissions.a in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -304,7 +373,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				2D02E4C91E0B4AEC006451C7 /* libReact.a in Frameworks */,
-				2D02E4C21E0B4AEC006451C7 /* libRCTAnimation-tvOS.a in Frameworks */,
+				2D02E4C21E0B4AEC006451C7 /* libRCTAnimation.a in Frameworks */,
 				2D02E4C31E0B4AEC006451C7 /* libRCTImage-tvOS.a in Frameworks */,
 				2D02E4C41E0B4AEC006451C7 /* libRCTLinking-tvOS.a in Frameworks */,
 				2D02E4C51E0B4AEC006451C7 /* libRCTNetwork-tvOS.a in Frameworks */,
@@ -397,6 +466,8 @@
 			children = (
 				139FDEF41B06529B00C62182 /* libRCTWebSocket.a */,
 				3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */,
+				66F16C001FC608A800E71FEB /* libfishhook.a */,
+				66F16C021FC608A800E71FEB /* libfishhook-tvOS.a */,
 			);
 			name = Products;
 			sourceTree = "<group>";
@@ -426,7 +497,12 @@
 				3DAD3EAB1DF850E9000B6D8A /* libcxxreact.a */,
 				3DAD3EAD1DF850E9000B6D8A /* libjschelpers.a */,
 				3DAD3EAF1DF850E9000B6D8A /* libjschelpers.a */,
-				3DAD3EA31DF850E9000B6D8A /* libReact-tvOS.a */,
+				661E35341FD3107F00C328EA /* libthird-party.a */,
+				661E35361FD3107F00C328EA /* libthird-party.a */,
+				661E35381FD3107F00C328EA /* libdouble-conversion.a */,
+				661E353A1FD3107F00C328EA /* libdouble-conversion.a */,
+				661E353C1FD3107F00C328EA /* libprivatedata.a */,
+				661E353E1FD3107F00C328EA /* libprivatedata-tvOS.a */,
 			);
 			name = Products;
 			sourceTree = "<group>";
@@ -435,11 +511,26 @@
 			isa = PBXGroup;
 			children = (
 				5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */,
-				5E9157351DD0AC6500FF2AA8 /* libRCTAnimation-tvOS.a */,
+				5E9157351DD0AC6500FF2AA8 /* libRCTAnimation.a */,
 			);
 			name = Products;
 			sourceTree = "<group>";
 		};
+		66AE22FC1FE44628000AEC3F /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				66AE23231FE44628000AEC3F /* libReactNativePermissions.a */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		66F16C081FC608C600E71FEB /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
 		78C398B11ACF4ADC00677621 /* Products */ = {
 			isa = PBXGroup;
 			children = (
@@ -464,7 +555,7 @@
 				832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */,
 				00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */,
 				139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */,
-				1CB53DB705894AAA8CB22783 /* ReactNativePermissions.xcodeproj */,
+				14B7951690F04106A4A8E60E /* ReactNativePermissions.xcodeproj */,
 			);
 			name = Libraries;
 			sourceTree = "<group>";
@@ -485,6 +576,7 @@
 				832341AE1AAA6A7D00B99B32 /* Libraries */,
 				00E356EF1AD99517003FC87E /* ExampleTests */,
 				83CBBA001A601CBA00E9B192 /* Products */,
+				66F16C081FC608C600E71FEB /* Frameworks */,
 			);
 			indentWidth = 2;
 			sourceTree = "<group>";
@@ -506,6 +598,7 @@
 			isa = PBXGroup;
 			children = (
 				ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */,
+				66F16BEE1FC608A800E71FEB /* libRCTBlob-tvOS.a */,
 			);
 			name = Products;
 			sourceTree = "<group>";
@@ -591,16 +684,16 @@
 		83CBB9F71A601CBA00E9B192 /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 820;
+				LastUpgradeCheck = 610;
 				ORGANIZATIONNAME = Facebook;
 				TargetAttributes = {
 					00E356ED1AD99517003FC87E = {
 						CreatedOnToolsVersion = 6.2;
-						DevelopmentTeam = 66SW7BQ2SM;
+						DevelopmentTeam = 745449BDR9;
 						TestTargetID = 13B07F861A680F5B00A75B9A;
 					};
 					13B07F861A680F5B00A75B9A = {
-						DevelopmentTeam = 66SW7BQ2SM;
+						DevelopmentTeam = 745449BDR9;
 						SystemCapabilities = {
 							com.apple.BackgroundModes = {
 								enabled = 1;
@@ -679,8 +772,8 @@
 					ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */;
 				},
 				{
-					ProductGroup = 9D140C9F1F068EB400146F6C /* Products */;
-					ProjectRef = 1CB53DB705894AAA8CB22783 /* ReactNativePermissions.xcodeproj */;
+					ProductGroup = 66AE22FC1FE44628000AEC3F /* Products */;
+					ProjectRef = 14B7951690F04106A4A8E60E /* ReactNativePermissions.xcodeproj */;
 				},
 			);
 			projectRoot = "";
@@ -792,10 +885,10 @@
 			remoteRef = 3DAD3E981DF850E9000B6D8A /* PBXContainerItemProxy */;
 			sourceTree = BUILT_PRODUCTS_DIR;
 		};
-		3DAD3EA31DF850E9000B6D8A /* libReact-tvOS.a */ = {
+		3DAD3EA31DF850E9000B6D8A /* libReact.a */ = {
 			isa = PBXReferenceProxy;
 			fileType = archive.ar;
-			path = "libReact-tvOS.a";
+			path = libReact.a;
 			remoteRef = 3DAD3EA21DF850E9000B6D8A /* PBXContainerItemProxy */;
 			sourceTree = BUILT_PRODUCTS_DIR;
 		};
@@ -848,13 +941,83 @@
 			remoteRef = 5E9157321DD0AC6500FF2AA8 /* PBXContainerItemProxy */;
 			sourceTree = BUILT_PRODUCTS_DIR;
 		};
-		5E9157351DD0AC6500FF2AA8 /* libRCTAnimation-tvOS.a */ = {
+		5E9157351DD0AC6500FF2AA8 /* libRCTAnimation.a */ = {
 			isa = PBXReferenceProxy;
 			fileType = archive.ar;
-			path = "libRCTAnimation-tvOS.a";
+			path = libRCTAnimation.a;
 			remoteRef = 5E9157341DD0AC6500FF2AA8 /* PBXContainerItemProxy */;
 			sourceTree = BUILT_PRODUCTS_DIR;
 		};
+		661E35341FD3107F00C328EA /* libthird-party.a */ = {
+			isa = PBXReferenceProxy;
+			fileType = archive.ar;
+			path = "libthird-party.a";
+			remoteRef = 661E35331FD3107F00C328EA /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		661E35361FD3107F00C328EA /* libthird-party.a */ = {
+			isa = PBXReferenceProxy;
+			fileType = archive.ar;
+			path = "libthird-party.a";
+			remoteRef = 661E35351FD3107F00C328EA /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		661E35381FD3107F00C328EA /* libdouble-conversion.a */ = {
+			isa = PBXReferenceProxy;
+			fileType = archive.ar;
+			path = "libdouble-conversion.a";
+			remoteRef = 661E35371FD3107F00C328EA /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		661E353A1FD3107F00C328EA /* libdouble-conversion.a */ = {
+			isa = PBXReferenceProxy;
+			fileType = archive.ar;
+			path = "libdouble-conversion.a";
+			remoteRef = 661E35391FD3107F00C328EA /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		661E353C1FD3107F00C328EA /* libprivatedata.a */ = {
+			isa = PBXReferenceProxy;
+			fileType = archive.ar;
+			path = libprivatedata.a;
+			remoteRef = 661E353B1FD3107F00C328EA /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		661E353E1FD3107F00C328EA /* libprivatedata-tvOS.a */ = {
+			isa = PBXReferenceProxy;
+			fileType = archive.ar;
+			path = "libprivatedata-tvOS.a";
+			remoteRef = 661E353D1FD3107F00C328EA /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		66AE23231FE44628000AEC3F /* libReactNativePermissions.a */ = {
+			isa = PBXReferenceProxy;
+			fileType = archive.ar;
+			path = libReactNativePermissions.a;
+			remoteRef = 66AE23221FE44628000AEC3F /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		66F16BEE1FC608A800E71FEB /* libRCTBlob-tvOS.a */ = {
+			isa = PBXReferenceProxy;
+			fileType = archive.ar;
+			path = "libRCTBlob-tvOS.a";
+			remoteRef = 66F16BED1FC608A800E71FEB /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		66F16C001FC608A800E71FEB /* libfishhook.a */ = {
+			isa = PBXReferenceProxy;
+			fileType = archive.ar;
+			path = libfishhook.a;
+			remoteRef = 66F16BFF1FC608A800E71FEB /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		66F16C021FC608A800E71FEB /* libfishhook-tvOS.a */ = {
+			isa = PBXReferenceProxy;
+			fileType = archive.ar;
+			path = "libfishhook-tvOS.a";
+			remoteRef = 66F16C011FC608A800E71FEB /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
 		78C398B91ACF4ADC00677621 /* libRCTLinking.a */ = {
 			isa = PBXReferenceProxy;
 			fileType = archive.ar;
@@ -1010,19 +1173,22 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				BUNDLE_LOADER = "$(TEST_HOST)";
-				DEVELOPMENT_TEAM = 66SW7BQ2SM;
+				DEVELOPMENT_TEAM = 745449BDR9;
 				GCC_PREPROCESSOR_DEFINITIONS = (
 					"DEBUG=1",
 					"$(inherited)",
 				);
+				HEADER_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(SRCROOT)/../node_modules/react-native-permissions",
+					"$(SRCROOT)/../node_modules/react-native-permissions/ios/**",
+				);
 				INFOPLIST_FILE = ExampleTests/Info.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"\"$(SRCROOT)/$(TARGET_NAME)\"",
-					"\"$(SRCROOT)/$(TARGET_NAME)\"",
-					"\"$(SRCROOT)/$(TARGET_NAME)\"",
 				);
 				OTHER_LDFLAGS = (
 					"-ObjC",
@@ -1038,15 +1204,18 @@
 			buildSettings = {
 				BUNDLE_LOADER = "$(TEST_HOST)";
 				COPY_PHASE_STRIP = NO;
-				DEVELOPMENT_TEAM = 66SW7BQ2SM;
+				DEVELOPMENT_TEAM = 745449BDR9;
+				HEADER_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(SRCROOT)/../node_modules/react-native-permissions",
+					"$(SRCROOT)/../node_modules/react-native-permissions/ios/**",
+				);
 				INFOPLIST_FILE = ExampleTests/Info.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"\"$(SRCROOT)/$(TARGET_NAME)\"",
-					"\"$(SRCROOT)/$(TARGET_NAME)\"",
-					"\"$(SRCROOT)/$(TARGET_NAME)\"",
 				);
 				OTHER_LDFLAGS = (
 					"-ObjC",
@@ -1063,7 +1232,12 @@
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				CURRENT_PROJECT_VERSION = 1;
 				DEAD_CODE_STRIPPING = NO;
-				DEVELOPMENT_TEAM = 66SW7BQ2SM;
+				DEVELOPMENT_TEAM = 745449BDR9;
+				HEADER_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(SRCROOT)/../node_modules/react-native-permissions",
+					"$(SRCROOT)/../node_modules/react-native-permissions/ios/**",
+				);
 				INFOPLIST_FILE = Example/Info.plist;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
 				OTHER_LDFLAGS = (
@@ -1071,6 +1245,7 @@
 					"-ObjC",
 					"-lc++",
 				);
+				PRODUCT_BUNDLE_IDENTIFIER = com.react.permissions;
 				PRODUCT_NAME = Example;
 				VERSIONING_SYSTEM = "apple-generic";
 			};
@@ -1081,7 +1256,12 @@
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				CURRENT_PROJECT_VERSION = 1;
-				DEVELOPMENT_TEAM = 66SW7BQ2SM;
+				DEVELOPMENT_TEAM = 745449BDR9;
+				HEADER_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(SRCROOT)/../node_modules/react-native-permissions",
+					"$(SRCROOT)/../node_modules/react-native-permissions/ios/**",
+				);
 				INFOPLIST_FILE = Example/Info.plist;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
 				OTHER_LDFLAGS = (
@@ -1089,6 +1269,7 @@
 					"-ObjC",
 					"-lc++",
 				);
+				PRODUCT_BUNDLE_IDENTIFIER = com.react.permissions;
 				PRODUCT_NAME = Example;
 				VERSIONING_SYSTEM = "apple-generic";
 			};
@@ -1106,13 +1287,16 @@
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				ENABLE_TESTABILITY = YES;
 				GCC_NO_COMMON_BLOCKS = YES;
+				HEADER_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(SRCROOT)/../node_modules/react-native-permissions",
+					"$(SRCROOT)/../node_modules/react-native-permissions/ios/**",
+				);
 				INFOPLIST_FILE = "Example-tvOS/Info.plist";
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"\"$(SRCROOT)/$(TARGET_NAME)\"",
-					"\"$(SRCROOT)/$(TARGET_NAME)\"",
-					"\"$(SRCROOT)/$(TARGET_NAME)\"",
 				);
 				OTHER_LDFLAGS = (
 					"-ObjC",
@@ -1138,13 +1322,16 @@
 				COPY_PHASE_STRIP = NO;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				GCC_NO_COMMON_BLOCKS = YES;
+				HEADER_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(SRCROOT)/../node_modules/react-native-permissions",
+					"$(SRCROOT)/../node_modules/react-native-permissions/ios/**",
+				);
 				INFOPLIST_FILE = "Example-tvOS/Info.plist";
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"\"$(SRCROOT)/$(TARGET_NAME)\"",
-					"\"$(SRCROOT)/$(TARGET_NAME)\"",
-					"\"$(SRCROOT)/$(TARGET_NAME)\"",
 				);
 				OTHER_LDFLAGS = (
 					"-ObjC",
@@ -1174,8 +1361,6 @@
 				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)";
@@ -1201,8 +1386,6 @@
 				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)";

+ 0 - 0
Example/ios/Example.xcodeproj/xcshareddata/xcschemes/Example-tvOS.xcscheme → example/ios/Example.xcodeproj/xcshareddata/xcschemes/Example-tvOS.xcscheme


+ 1 - 1
Example/ios/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme → example/ios/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "0820"
+   LastUpgradeVersion = "0620"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "NO"

+ 0 - 0
Example/ios/Example/AppDelegate.h → example/ios/Example/AppDelegate.h


+ 1 - 1
Example/ios/Example/AppDelegate.m → example/ios/Example/AppDelegate.m

@@ -18,7 +18,7 @@
 {
   NSURL *jsCodeLocation;
 
-  jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
+  jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
 
   RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                       moduleName:@"Example"

+ 0 - 0
Example/ios/Example/Base.lproj/LaunchScreen.xib → example/ios/Example/Base.lproj/LaunchScreen.xib


+ 38 - 0
example/ios/Example/Images.xcassets/AppIcon.appiconset/Contents.json

@@ -0,0 +1,38 @@
+{
+  "images": [
+    {
+      "idiom": "iphone",
+      "size": "29x29",
+      "scale": "2x"
+    },
+    {
+      "idiom": "iphone",
+      "size": "29x29",
+      "scale": "3x"
+    },
+    {
+      "idiom": "iphone",
+      "size": "40x40",
+      "scale": "2x"
+    },
+    {
+      "idiom": "iphone",
+      "size": "40x40",
+      "scale": "3x"
+    },
+    {
+      "idiom": "iphone",
+      "size": "60x60",
+      "scale": "2x"
+    },
+    {
+      "idiom": "iphone",
+      "size": "60x60",
+      "scale": "3x"
+    }
+  ],
+  "info": {
+    "version": 1,
+    "author": "xcode"
+  }
+}

+ 6 - 0
example/ios/Example/Images.xcassets/Contents.json

@@ -0,0 +1,6 @@
+{
+  "info": {
+    "version": 1,
+    "author": "xcode"
+  }
+}

+ 5 - 1
Example/ios/Example/Info.plist → example/ios/Example/Info.plist

@@ -4,10 +4,14 @@
 <dict>
 	<key>CFBundleDevelopmentRegion</key>
 	<string>en</string>
+	<key>CFBundleDisplayName</key>
+	<string>Example</string>
 	<key>CFBundleExecutable</key>
 	<string>$(EXECUTABLE_NAME)</string>
 	<key>CFBundleIdentifier</key>
-	<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
 	<key>CFBundleName</key>
 	<string>$(PRODUCT_NAME)</string>
 	<key>CFBundlePackageType</key>

+ 0 - 0
Example/ios/Example/main.m → example/ios/Example/main.m


+ 0 - 0
Example/ios/ExampleTests/ExampleTests.m → example/ios/ExampleTests/ExampleTests.m


+ 0 - 0
Example/ios/ExampleTests/Info.plist → example/ios/ExampleTests/Info.plist


+ 23 - 0
example/package.json

@@ -0,0 +1,23 @@
+{
+  "name": "Example",
+  "version": "0.0.1",
+  "private": true,
+  "scripts": {
+    "start": "node node_modules/react-native/local-cli/cli.js start",
+    "test": "jest"
+  },
+  "dependencies": {
+    "react": "16.0.0",
+    "react-native": "0.50.3",
+    "react-native-permissions": "../"
+  },
+  "devDependencies": {
+    "babel-jest": "21.2.0",
+    "babel-preset-react-native": "4.0.0",
+    "jest": "21.2.1",
+    "react-test-renderer": "16.0.0"
+  },
+  "jest": {
+    "preset": "react-native"
+  }
+}

+ 0 - 91
index.android.js

@@ -1,91 +0,0 @@
-'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,
-	callPhone: RNPermissions.PERMISSIONS.CALL_PHONE,
-	readSms: RNPermissions.PERMISSIONS.READ_SMS,
-	receiveSms: RNPermissions.PERMISSIONS.RECEIVE_SMS,
-}
-
-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 => {
-				// RNPermissions.request() to native module resolves to boolean
-				// rather than string if running on OS version prior to Android M 
-				if (typeof res === 'boolean') return res ? 'authorized' : 'denied';
-				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()

+ 0 - 70
index.ios.js

@@ -1,70 +0,0 @@
-'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(permission => this.check(permission)))
-			.then(res => res.reduce((pre, cur, i) => {
-				var name = permissions[i]
-				pre[name] = cur
-				return pre
-			}, {}))
-	}
-}
-
-module.exports = new ReactNativePermissions()

+ 4 - 0
index.js

@@ -0,0 +1,4 @@
+// @flow
+
+import Permissions from './lib/permissions'
+export default Permissions

+ 0 - 0
permissions/RNPAudioVideo.h → ios/Permissions/RNPAudioVideo.h


+ 0 - 0
permissions/RNPAudioVideo.m → ios/Permissions/RNPAudioVideo.m


+ 0 - 0
permissions/RNPBackgroundRefresh.h → ios/Permissions/RNPBackgroundRefresh.h


+ 0 - 0
permissions/RNPBackgroundRefresh.m → ios/Permissions/RNPBackgroundRefresh.m


+ 0 - 0
permissions/RNPBluetooth.h → ios/Permissions/RNPBluetooth.h


+ 0 - 0
permissions/RNPBluetooth.m → ios/Permissions/RNPBluetooth.m


+ 0 - 0
permissions/RNPContacts.h → ios/Permissions/RNPContacts.h


+ 0 - 0
permissions/RNPContacts.m → ios/Permissions/RNPContacts.m


+ 0 - 0
permissions/RNPEvent.h → ios/Permissions/RNPEvent.h


+ 0 - 0
permissions/RNPEvent.m → ios/Permissions/RNPEvent.m


+ 0 - 0
permissions/RNPLocation.h → ios/Permissions/RNPLocation.h


+ 0 - 0
permissions/RNPLocation.m → ios/Permissions/RNPLocation.m


+ 0 - 0
permissions/RNPNotification.h → ios/Permissions/RNPNotification.h


+ 0 - 0
permissions/RNPNotification.m → ios/Permissions/RNPNotification.m


+ 0 - 0
permissions/RNPPhoto.h → ios/Permissions/RNPPhoto.h


+ 0 - 0
permissions/RNPPhoto.m → ios/Permissions/RNPPhoto.m


+ 0 - 0
permissions/RNPSpeechRecognition.h → ios/Permissions/RNPSpeechRecognition.h


+ 0 - 0
permissions/RNPSpeechRecognition.m → ios/Permissions/RNPSpeechRecognition.m


+ 0 - 0
RCTConvert+RNPStatus.h → ios/RCTConvert+RNPStatus.h


+ 0 - 1
RCTConvert+RNPStatus.m → ios/RCTConvert+RNPStatus.m

@@ -10,7 +10,6 @@
 
 @implementation RCTConvert (RNPStatus)
 
-
 RCT_ENUM_CONVERTER(RNPType, (@{ @"location" : @(RNPTypeLocation),
                                 @"camera" : @(RNPTypeCamera),
                                 @"microphone" : @(RNPTypeMicrophone),

+ 0 - 1
ReactNativePermissions.h → ios/ReactNativePermissions.h

@@ -16,5 +16,4 @@
 
 @interface ReactNativePermissions : NSObject <RCTBridgeModule>
 
-
 @end

+ 5 - 1
ReactNativePermissions.m → ios/ReactNativePermissions.m

@@ -18,7 +18,6 @@
   #import "RCTBridge.h"
 #endif
 
-
 #if __has_include(<React/RCTConvert.h>)
   #import <React/RCTConvert.h>
 #elif __has_include("React/RCTConvert.h")
@@ -58,6 +57,11 @@
 RCT_EXPORT_MODULE();
 @synthesize bridge = _bridge;
 
++ (BOOL)requiresMainQueueSetup
+{
+    return YES;
+}
+
 #pragma mark Initialization
 
 - (instancetype)init

+ 74 - 64
ReactNativePermissions.xcodeproj/project.pbxproj → ios/ReactNativePermissions.xcodeproj/project.pbxproj

@@ -7,18 +7,18 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
-		281CD5911E26B0C8003A72B2 /* RNPSpeechRecognition.m in Sources */ = {isa = PBXBuildFile; fileRef = 281CD5901E26B0C7003A72B2 /* RNPSpeechRecognition.m */; };
 		483383101FAB6115005D5777 /* RNPMotion.m in Sources */ = {isa = PBXBuildFile; fileRef = 4833830E1FAB6114005D5777 /* RNPMotion.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+RNPStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DE8D28A1CA31E95009CE8CC /* RCTConvert+RNPStatus.m */; };
+		669581F71FE4416B008596CD /* RCTConvert+RNPStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = 669581F41FE4416B008596CD /* RCTConvert+RNPStatus.m */; };
+		669581F81FE4416B008596CD /* ReactNativePermissions.m in Sources */ = {isa = PBXBuildFile; fileRef = 669581F51FE4416B008596CD /* ReactNativePermissions.m */; };
+		6695820D1FE441A8008596CD /* RNPSpeechRecognition.m in Sources */ = {isa = PBXBuildFile; fileRef = 669581FD1FE441A7008596CD /* RNPSpeechRecognition.m */; };
+		6695820E1FE441A8008596CD /* RNPLocation.m in Sources */ = {isa = PBXBuildFile; fileRef = 669581FE1FE441A7008596CD /* RNPLocation.m */; };
+		6695820F1FE441A8008596CD /* RNPBluetooth.m in Sources */ = {isa = PBXBuildFile; fileRef = 669581FF1FE441A7008596CD /* RNPBluetooth.m */; };
+		669582101FE441A8008596CD /* RNPBackgroundRefresh.m in Sources */ = {isa = PBXBuildFile; fileRef = 669582001FE441A7008596CD /* RNPBackgroundRefresh.m */; };
+		669582111FE441A8008596CD /* RNPNotification.m in Sources */ = {isa = PBXBuildFile; fileRef = 669582011FE441A7008596CD /* RNPNotification.m */; };
+		669582121FE441A8008596CD /* RNPPhoto.m in Sources */ = {isa = PBXBuildFile; fileRef = 669582031FE441A7008596CD /* RNPPhoto.m */; };
+		669582131FE441A8008596CD /* RNPAudioVideo.m in Sources */ = {isa = PBXBuildFile; fileRef = 669582071FE441A7008596CD /* RNPAudioVideo.m */; };
+		669582141FE441A8008596CD /* RNPContacts.m in Sources */ = {isa = PBXBuildFile; fileRef = 669582081FE441A8008596CD /* RNPContacts.m */; };
+		669582151FE441A8008596CD /* RNPEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 6695820A1FE441A8008596CD /* RNPEvent.m */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXCopyFilesBuildPhase section */
@@ -34,31 +34,31 @@
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
-		281CD5901E26B0C7003A72B2 /* RNPSpeechRecognition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNPSpeechRecognition.m; path = permissions/RNPSpeechRecognition.m; sourceTree = SOURCE_ROOT; };
-		281CD5921E26B266003A72B2 /* RNPSpeechRecognition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNPSpeechRecognition.h; path = permissions/RNPSpeechRecognition.h; sourceTree = SOURCE_ROOT; };
 		4833830E1FAB6114005D5777 /* RNPMotion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNPMotion.m; path = permissions/RNPMotion.m; sourceTree = SOURCE_ROOT; };
 		4833830F1FAB6115005D5777 /* RNPMotion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNPMotion.h; path = permissions/RNPMotion.h; sourceTree = SOURCE_ROOT; };
+		669581F31FE4416B008596CD /* ReactNativePermissions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReactNativePermissions.h; sourceTree = "<group>"; };
+		669581F41FE4416B008596CD /* RCTConvert+RNPStatus.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RCTConvert+RNPStatus.m"; sourceTree = "<group>"; };
+		669581F51FE4416B008596CD /* ReactNativePermissions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReactNativePermissions.m; sourceTree = "<group>"; };
+		669581F61FE4416B008596CD /* RCTConvert+RNPStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RCTConvert+RNPStatus.h"; sourceTree = "<group>"; };
+		669581FB1FE441A7008596CD /* RNPContacts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNPContacts.h; sourceTree = "<group>"; };
+		669581FC1FE441A7008596CD /* RNPPhoto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNPPhoto.h; sourceTree = "<group>"; };
+		669581FD1FE441A7008596CD /* RNPSpeechRecognition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNPSpeechRecognition.m; sourceTree = "<group>"; };
+		669581FE1FE441A7008596CD /* RNPLocation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNPLocation.m; sourceTree = "<group>"; };
+		669581FF1FE441A7008596CD /* RNPBluetooth.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNPBluetooth.m; sourceTree = "<group>"; };
+		669582001FE441A7008596CD /* RNPBackgroundRefresh.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNPBackgroundRefresh.m; sourceTree = "<group>"; };
+		669582011FE441A7008596CD /* RNPNotification.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNPNotification.m; sourceTree = "<group>"; };
+		669582021FE441A7008596CD /* RNPLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNPLocation.h; sourceTree = "<group>"; };
+		669582031FE441A7008596CD /* RNPPhoto.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNPPhoto.m; sourceTree = "<group>"; };
+		669582041FE441A7008596CD /* RNPAudioVideo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNPAudioVideo.h; sourceTree = "<group>"; };
+		669582051FE441A7008596CD /* RNPBackgroundRefresh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNPBackgroundRefresh.h; sourceTree = "<group>"; };
+		669582061FE441A7008596CD /* RNPEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNPEvent.h; sourceTree = "<group>"; };
+		669582071FE441A7008596CD /* RNPAudioVideo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNPAudioVideo.m; sourceTree = "<group>"; };
+		669582081FE441A8008596CD /* RNPContacts.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNPContacts.m; sourceTree = "<group>"; };
+		669582091FE441A8008596CD /* RNPBluetooth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNPBluetooth.h; sourceTree = "<group>"; };
+		6695820A1FE441A8008596CD /* RNPEvent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNPEvent.m; sourceTree = "<group>"; };
+		6695820B1FE441A8008596CD /* RNPSpeechRecognition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNPSpeechRecognition.h; sourceTree = "<group>"; };
+		6695820C1FE441A8008596CD /* RNPNotification.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNPNotification.h; sourceTree = "<group>"; };
 		9D23B34F1C767B80008B4819 /* libReactNativePermissions.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libReactNativePermissions.a; sourceTree = BUILT_PRODUCTS_DIR; };
-		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; 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 */
@@ -72,35 +72,44 @@
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
-		9D23B3461C767B80008B4819 = {
+		669581FA1FE44191008596CD /* Permissions */ = {
 			isa = PBXGroup;
 			children = (
-				9D23B3511C767B80008B4819 /* ReactNativePermissions */,
-				9D23B3501C767B80008B4819 /* Products */,
+				669582041FE441A7008596CD /* RNPAudioVideo.h */,
+				669582071FE441A7008596CD /* RNPAudioVideo.m */,
+				669582051FE441A7008596CD /* RNPBackgroundRefresh.h */,
+				669582001FE441A7008596CD /* RNPBackgroundRefresh.m */,
+				669582091FE441A8008596CD /* RNPBluetooth.h */,
+				669581FF1FE441A7008596CD /* RNPBluetooth.m */,
+				669581FB1FE441A7008596CD /* RNPContacts.h */,
+				669582081FE441A8008596CD /* RNPContacts.m */,
+				669582061FE441A7008596CD /* RNPEvent.h */,
+				6695820A1FE441A8008596CD /* RNPEvent.m */,
+				669582021FE441A7008596CD /* RNPLocation.h */,
+				669581FE1FE441A7008596CD /* RNPLocation.m */,
+				6695820C1FE441A8008596CD /* RNPNotification.h */,
+				669582011FE441A7008596CD /* RNPNotification.m */,
+				669581FC1FE441A7008596CD /* RNPPhoto.h */,
+				669582031FE441A7008596CD /* RNPPhoto.m */,
+				6695820B1FE441A8008596CD /* RNPSpeechRecognition.h */,
+				669581FD1FE441A7008596CD /* RNPSpeechRecognition.m */,
 			);
+			path = Permissions;
 			sourceTree = "<group>";
 		};
-		9D23B3501C767B80008B4819 /* Products */ = {
-			isa = PBXGroup;
-			children = (
-				9D23B34F1C767B80008B4819 /* libReactNativePermissions.a */,
-			);
-			name = Products;
-			sourceTree = "<group>";
-		};
-		9D23B3511C767B80008B4819 /* ReactNativePermissions */ = {
+		9D23B3461C767B80008B4819 = {
 			isa = PBXGroup;
 			children = (
-				9D4628091D33C1EC00346A5B /* permissions */,
-				9DE8D2891CA31E95009CE8CC /* RCTConvert+RNPStatus.h */,
-				9DE8D28A1CA31E95009CE8CC /* RCTConvert+RNPStatus.m */,
-				9DE8D2801CA31888009CE8CC /* ReactNativePermissions.h */,
-				9DE8D2811CA3188D009CE8CC /* ReactNativePermissions.m */,
+				669581FA1FE44191008596CD /* Permissions */,
+				669581F61FE4416B008596CD /* RCTConvert+RNPStatus.h */,
+				669581F41FE4416B008596CD /* RCTConvert+RNPStatus.m */,
+				669581F31FE4416B008596CD /* ReactNativePermissions.h */,
+				669581F51FE4416B008596CD /* ReactNativePermissions.m */,
+				9D23B3501C767B80008B4819 /* Products */,
 			);
-			path = ReactNativePermissions;
 			sourceTree = "<group>";
 		};
-		9D4628091D33C1EC00346A5B /* permissions */ = {
+		9D23B3501C767B80008B4819 /* Products */ = {
 			isa = PBXGroup;
 			children = (
 				4833830F1FAB6115005D5777 /* RNPMotion.h */,
@@ -123,8 +132,9 @@
 				9D46283D1D34719100346A5B /* RNPPhoto.m */,
 				281CD5921E26B266003A72B2 /* RNPSpeechRecognition.h */,
 				281CD5901E26B0C7003A72B2 /* RNPSpeechRecognition.m */,
+				9D23B34F1C767B80008B4819 /* libReactNativePermissions.a */,
 			);
-			name = permissions;
+			name = Products;
 			sourceTree = "<group>";
 		};
 /* End PBXGroup section */
@@ -183,18 +193,18 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				9D46283F1D34719100346A5B /* RNPBackgroundRefresh.m in Sources */,
-				9D4628451D34719100346A5B /* RNPPhoto.m in Sources */,
-				281CD5911E26B0C8003A72B2 /* RNPSpeechRecognition.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 */,
 				483383101FAB6115005D5777 /* RNPMotion.m in Sources */,
-				9DE8D2821CA3188D009CE8CC /* ReactNativePermissions.m in Sources */,
-				9D4628411D34719100346A5B /* RNPContacts.m in Sources */,
-				9D4628441D34719100346A5B /* RNPNotification.m in Sources */,
+				669582111FE441A8008596CD /* RNPNotification.m in Sources */,
+				669582151FE441A8008596CD /* RNPEvent.m in Sources */,
+				669582101FE441A8008596CD /* RNPBackgroundRefresh.m in Sources */,
+				669581F71FE4416B008596CD /* RCTConvert+RNPStatus.m in Sources */,
+				6695820E1FE441A8008596CD /* RNPLocation.m in Sources */,
+				6695820F1FE441A8008596CD /* RNPBluetooth.m in Sources */,
+				669582141FE441A8008596CD /* RNPContacts.m in Sources */,
+				6695820D1FE441A8008596CD /* RNPSpeechRecognition.m in Sources */,
+				669582131FE441A8008596CD /* RNPAudioVideo.m in Sources */,
+				669581F81FE4416B008596CD /* ReactNativePermissions.m in Sources */,
+				669582121FE441A8008596CD /* RNPPhoto.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

+ 117 - 0
lib/permissions.android.js

@@ -0,0 +1,117 @@
+// @flow
+
+import { AsyncStorage, NativeModules, PermissionsAndroid } from 'react-native'
+
+type Status = 'authorized' | 'denied' | 'restricted' | 'undetermined'
+type Rationale = { title: string, message: string }
+type CheckOptions = string | { type: string }
+type RequestOptions = string | { type: string, rationale?: Rationale }
+
+const permissionTypes = {
+  location: PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
+  camera: PermissionsAndroid.PERMISSIONS.CAMERA,
+  microphone: PermissionsAndroid.PERMISSIONS.RECORD_AUDIO,
+  contacts: PermissionsAndroid.PERMISSIONS.READ_CONTACTS,
+  event: PermissionsAndroid.PERMISSIONS.READ_CALENDAR,
+  storage: PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
+  photo: PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
+  callPhone: PermissionsAndroid.PERMISSIONS.CALL_PHONE,
+  readSms: PermissionsAndroid.PERMISSIONS.READ_SMS,
+  receiveSms: PermissionsAndroid.PERMISSIONS.RECEIVE_SMS,
+}
+
+const RESULTS = {
+  [PermissionsAndroid.RESULTS.GRANTED]: 'authorized',
+  [PermissionsAndroid.RESULTS.DENIED]: 'denied',
+  [PermissionsAndroid.RESULTS.NEVER_ASK_AGAIN]: 'restricted',
+}
+
+const STORAGE_KEY = '@RNPermissions:didAskPermission:'
+
+const setDidAskOnce = (permission: string) =>
+  AsyncStorage.setItem(STORAGE_KEY + permission, 'true')
+
+const getDidAskOnce = (permission: string) =>
+  AsyncStorage.getItem(STORAGE_KEY + permission).then(item => !!item)
+
+class ReactNativePermissions {
+  canOpenSettings: () => Promise<boolean> = () => Promise.resolve(false)
+
+  openSettings: () => Promise<*> = () =>
+    Promise.reject(new Error("'openSettings' is deprecated on android"))
+
+  getTypes: () => Array<string> = () => Object.keys(permissionTypes)
+
+  check = (permission: string, options?: CheckOptions): Promise<Status> => {
+    if (!permissionTypes[permission]) {
+      const error = new Error(
+        `ReactNativePermissions: ${
+          permission
+        } is not a valid permission type on Android`,
+      )
+
+      return Promise.reject(error)
+    }
+
+    return PermissionsAndroid.check(permissionTypes[permission]).then(
+      isAuthorized => {
+        if (isAuthorized) {
+          return 'authorized'
+        }
+
+        return getDidAskOnce(permission).then(didAsk => {
+          if (didAsk) {
+            return NativeModules.PermissionsAndroid.shouldShowRequestPermissionRationale(
+              permissionTypes[permission],
+            ).then(shouldShow => (shouldShow ? 'denied' : 'restricted'))
+          }
+
+          return 'undetermined'
+        })
+      },
+    )
+  }
+
+  request = (permission: string, options?: RequestOptions): Promise<Status> => {
+    if (!permissionTypes[permission]) {
+      const error = new Error(
+        `ReactNativePermissions: ${
+          permission
+        } is not a valid permission type on Android`,
+      )
+
+      return Promise.reject(error)
+    }
+
+    let rationale
+
+    if (options && options.rationale) {
+      rationale = options.rationale
+    }
+
+    return PermissionsAndroid.request(
+      permissionTypes[permission],
+      rationale,
+    ).then(result => {
+      // PermissionsAndroid.request() to native module resolves to boolean
+      // rather than string if running on OS version prior to Android M
+      if (typeof result === 'boolean') {
+        return result ? 'authorized' : 'denied'
+      }
+
+      return setDidAskOnce(permission).then(() => RESULTS[result])
+    })
+  }
+
+  checkMultiple = (permissions: Array<string>): Promise<{ [string]: string }> =>
+    Promise.all(permissions.map(permission => this.check(permission))).then(
+      result =>
+        result.reduce((acc, value, index) => {
+          const name = permissions[index]
+          acc[name] = value
+          return acc
+        }, {}),
+    )
+}
+
+export default new ReactNativePermissions()

+ 107 - 0
lib/permissions.ios.js

@@ -0,0 +1,107 @@
+// @flow
+
+import { NativeModules } from 'react-native'
+const PermissionsIOS = NativeModules.ReactNativePermissions
+
+type Status = 'authorized' | 'denied' | 'restricted' | 'undetermined'
+type Rationale = { title: string, message: string }
+type CheckOptions = string | { type: string }
+type RequestOptions = string | { type: string, rationale?: Rationale }
+
+const permissionTypes = [
+  'location',
+  'camera',
+  'microphone',
+  'photo',
+  'contacts',
+  'event',
+  'reminder',
+  'bluetooth',
+  'notification',
+  'backgroundRefresh',
+  'speechRecognition',
+]
+
+const DEFAULTS = {
+  location: 'whenInUse',
+  notification: ['alert', 'badge', 'sound'],
+}
+
+class ReactNativePermissions {
+  canOpenSettings: () => Promise<boolean> = () =>
+    PermissionsIOS.canOpenSettings()
+
+  openSettings: () => Promise<*> = () => PermissionsIOS.openSettings()
+
+  getTypes: () => Array<string> = () => permissionTypes
+
+  check = (permission: string, options?: CheckOptions): Promise<Status> => {
+    if (!permissionTypes.includes(permission)) {
+      const error = new Error(
+        `ReactNativePermissions: ${
+          permission
+        } is not a valid permission type on iOS`,
+      )
+
+      return Promise.reject(error)
+    }
+
+    let type
+
+    if (typeof options === 'string') {
+      type = options
+    } else if (options && options.type) {
+      type = options.type
+    }
+
+    return PermissionsIOS.getPermissionStatus(
+      permission,
+      type || DEFAULTS[permission],
+    )
+  }
+
+  request = (permission: string, options?: RequestOptions): Promise<Status> => {
+    if (!permissionTypes.includes(permission)) {
+      const error = new Error(
+        `ReactNativePermissions: ${
+          permission
+        } is not a valid permission type on iOS`,
+      )
+
+      return Promise.reject(error)
+    }
+
+    if (permission == 'backgroundRefresh') {
+      const error = new Error(
+        'ReactNativePermissions: You cannot request backgroundRefresh',
+      )
+
+      return Promise.reject(error)
+    }
+
+    let type
+
+    if (typeof options === 'string') {
+      type = options
+    } else if (options && options.type) {
+      type = options.type
+    }
+
+    return PermissionsIOS.requestPermission(
+      permission,
+      type || DEFAULTS[permission],
+    )
+  }
+
+  checkMultiple = (permissions: Array<string>): Promise<{ [string]: string }> =>
+    Promise.all(permissions.map(permission => this.check(permission))).then(
+      result =>
+        result.reduce((acc, value, index) => {
+          const name = permissions[index]
+          acc[name] = value
+          return acc
+        }, {}),
+    )
+}
+
+export default new ReactNativePermissions()

+ 21 - 12
package.json

@@ -1,18 +1,27 @@
 {
   "name": "react-native-permissions",
-  "version": "1.0.1",
+  "version": "1.0.6",
+  "description": "Check user permissions in React Native",
+  "author": "Yonah Forst <yonaforst@hotmail.com>",
+  "homepage": "https://github.com/yonahforst/react-native-permissions",
+  "keywords": ["react-native", "react-permissions", "permissions"],
+  "main": "index.js",
+  "license": "MIT",
   "repository": {
     "type": "git",
-    "url": "https://github.com/joshblour/react-native-permissions.git"
+    "url": "https://github.com/yonahforst/react-native-permissions.git"
   },
-  "main": "index",
-  "license": "MIT",
-  "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"
+  "scripts": {
+    "precommit": "lint-staged",
+    "prettier": "prettier --write '**/*.{js,json,md}'"
+  },
+  "lint-staged": {
+    "**/*.{js,json,md}": ["prettier --write", "git add"]
+  },
+  "devDependencies": {
+    "flow-bin": "^0.57.3",
+    "husky": "^0.14.3",
+    "lint-staged": "^6.0.0",
+    "prettier": "^1.9.2"
+  }
 }

+ 614 - 0
yarn.lock

@@ -0,0 +1,614 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+ansi-escapes@^1.0.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
+
+ansi-regex@^2.0.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+
+ansi-regex@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
+
+ansi-styles@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
+
+ansi-styles@^3.1.0, ansi-styles@^3.2.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88"
+  dependencies:
+    color-convert "^1.9.0"
+
+any-observable@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.2.0.tgz#c67870058003579009083f54ac0abafb5c33d242"
+
+app-root-path@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.0.1.tgz#cd62dcf8e4fd5a417efc664d2e5b10653c651b46"
+
+argparse@^1.0.7:
+  version "1.0.9"
+  resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86"
+  dependencies:
+    sprintf-js "~1.0.2"
+
+balanced-match@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
+
+brace-expansion@^1.1.7:
+  version "1.1.8"
+  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292"
+  dependencies:
+    balanced-match "^1.0.0"
+    concat-map "0.0.1"
+
+chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
+  dependencies:
+    ansi-styles "^2.2.1"
+    escape-string-regexp "^1.0.2"
+    has-ansi "^2.0.0"
+    strip-ansi "^3.0.0"
+    supports-color "^2.0.0"
+
+chalk@^2.0.1, chalk@^2.1.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba"
+  dependencies:
+    ansi-styles "^3.1.0"
+    escape-string-regexp "^1.0.5"
+    supports-color "^4.0.0"
+
+ci-info@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.2.tgz#03561259db48d0474c8bdc90f5b47b068b6bbfb4"
+
+cli-cursor@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987"
+  dependencies:
+    restore-cursor "^1.0.1"
+
+cli-spinners@^0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c"
+
+cli-truncate@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574"
+  dependencies:
+    slice-ansi "0.0.4"
+    string-width "^1.0.1"
+
+code-point-at@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
+
+color-convert@^1.9.0:
+  version "1.9.1"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed"
+  dependencies:
+    color-name "^1.1.1"
+
+color-name@^1.1.1:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+
+commander@^2.11.0, commander@^2.9.0:
+  version "2.12.2"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555"
+
+concat-map@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+
+cosmiconfig@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-3.1.0.tgz#640a94bf9847f321800403cd273af60665c73397"
+  dependencies:
+    is-directory "^0.3.1"
+    js-yaml "^3.9.0"
+    parse-json "^3.0.0"
+    require-from-string "^2.0.1"
+
+cross-spawn@^5.0.1:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
+  dependencies:
+    lru-cache "^4.0.1"
+    shebang-command "^1.2.0"
+    which "^1.2.9"
+
+date-fns@^1.27.2:
+  version "1.29.0"
+  resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.29.0.tgz#12e609cdcb935127311d04d33334e2960a2a54e6"
+
+dedent@^0.7.0:
+  version "0.7.0"
+  resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c"
+
+elegant-spinner@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e"
+
+error-ex@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc"
+  dependencies:
+    is-arrayish "^0.2.1"
+
+escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+
+esprima@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804"
+
+execa@^0.8.0:
+  version "0.8.0"
+  resolved "https://registry.yarnpkg.com/execa/-/execa-0.8.0.tgz#d8d76bbc1b55217ed190fd6dd49d3c774ecfc8da"
+  dependencies:
+    cross-spawn "^5.0.1"
+    get-stream "^3.0.0"
+    is-stream "^1.1.0"
+    npm-run-path "^2.0.0"
+    p-finally "^1.0.0"
+    signal-exit "^3.0.0"
+    strip-eof "^1.0.0"
+
+exit-hook@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8"
+
+figures@^1.7.0:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e"
+  dependencies:
+    escape-string-regexp "^1.0.5"
+    object-assign "^4.1.0"
+
+find-parent-dir@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/find-parent-dir/-/find-parent-dir-0.3.0.tgz#33c44b429ab2b2f0646299c5f9f718f376ff8d54"
+
+flow-bin@^0.57.3:
+  version "0.57.3"
+  resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.57.3.tgz#843fb80a821b6d0c5847f7bb3f42365ffe53b27b"
+
+get-own-enumerable-property-symbols@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-2.0.1.tgz#5c4ad87f2834c4b9b4e84549dc1e0650fb38c24b"
+
+get-stream@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
+
+has-ansi@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
+  dependencies:
+    ansi-regex "^2.0.0"
+
+has-flag@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51"
+
+husky@^0.14.3:
+  version "0.14.3"
+  resolved "https://registry.yarnpkg.com/husky/-/husky-0.14.3.tgz#c69ed74e2d2779769a17ba8399b54ce0b63c12c3"
+  dependencies:
+    is-ci "^1.0.10"
+    normalize-path "^1.0.0"
+    strip-indent "^2.0.0"
+
+indent-string@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80"
+  dependencies:
+    repeating "^2.0.0"
+
+indent-string@^3.0.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289"
+
+is-arrayish@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+
+is-ci@^1.0.10:
+  version "1.0.10"
+  resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.0.10.tgz#f739336b2632365061a9d48270cd56ae3369318e"
+  dependencies:
+    ci-info "^1.0.0"
+
+is-directory@^0.3.1:
+  version "0.3.1"
+  resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1"
+
+is-extglob@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+
+is-finite@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
+  dependencies:
+    number-is-nan "^1.0.0"
+
+is-fullwidth-code-point@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
+  dependencies:
+    number-is-nan "^1.0.0"
+
+is-glob@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0"
+  dependencies:
+    is-extglob "^2.1.1"
+
+is-obj@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
+
+is-observable@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/is-observable/-/is-observable-0.2.0.tgz#b361311d83c6e5d726cabf5e250b0237106f5ae2"
+  dependencies:
+    symbol-observable "^0.2.2"
+
+is-promise@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa"
+
+is-regexp@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069"
+
+is-stream@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
+
+isexe@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+
+jest-get-type@^21.2.0:
+  version "21.2.0"
+  resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-21.2.0.tgz#f6376ab9db4b60d81e39f30749c6c466f40d4a23"
+
+jest-validate@^21.1.0:
+  version "21.2.1"
+  resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-21.2.1.tgz#cc0cbca653cd54937ba4f2a111796774530dd3c7"
+  dependencies:
+    chalk "^2.0.1"
+    jest-get-type "^21.2.0"
+    leven "^2.1.0"
+    pretty-format "^21.2.1"
+
+js-yaml@^3.9.0:
+  version "3.10.0"
+  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc"
+  dependencies:
+    argparse "^1.0.7"
+    esprima "^4.0.0"
+
+leven@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580"
+
+lint-staged@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-5.0.0.tgz#f1c670e03e2fdf3f3d0eb81f72d3bcf658770e54"
+  dependencies:
+    app-root-path "^2.0.0"
+    chalk "^2.1.0"
+    commander "^2.11.0"
+    cosmiconfig "^3.1.0"
+    dedent "^0.7.0"
+    execa "^0.8.0"
+    find-parent-dir "^0.3.0"
+    is-glob "^4.0.0"
+    jest-validate "^21.1.0"
+    listr "^0.13.0"
+    lodash "^4.17.4"
+    log-symbols "^2.0.0"
+    minimatch "^3.0.0"
+    npm-which "^3.0.1"
+    p-map "^1.1.1"
+    path-is-inside "^1.0.2"
+    pify "^3.0.0"
+    staged-git-files "0.0.4"
+    stringify-object "^3.2.0"
+
+listr-silent-renderer@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz#924b5a3757153770bf1a8e3fbf74b8bbf3f9242e"
+
+listr-update-renderer@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/listr-update-renderer/-/listr-update-renderer-0.4.0.tgz#344d980da2ca2e8b145ba305908f32ae3f4cc8a7"
+  dependencies:
+    chalk "^1.1.3"
+    cli-truncate "^0.2.1"
+    elegant-spinner "^1.0.1"
+    figures "^1.7.0"
+    indent-string "^3.0.0"
+    log-symbols "^1.0.2"
+    log-update "^1.0.2"
+    strip-ansi "^3.0.1"
+
+listr-verbose-renderer@^0.4.0:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz#8206f4cf6d52ddc5827e5fd14989e0e965933a35"
+  dependencies:
+    chalk "^1.1.3"
+    cli-cursor "^1.0.2"
+    date-fns "^1.27.2"
+    figures "^1.7.0"
+
+listr@^0.13.0:
+  version "0.13.0"
+  resolved "https://registry.yarnpkg.com/listr/-/listr-0.13.0.tgz#20bb0ba30bae660ee84cc0503df4be3d5623887d"
+  dependencies:
+    chalk "^1.1.3"
+    cli-truncate "^0.2.1"
+    figures "^1.7.0"
+    indent-string "^2.1.0"
+    is-observable "^0.2.0"
+    is-promise "^2.1.0"
+    is-stream "^1.1.0"
+    listr-silent-renderer "^1.1.1"
+    listr-update-renderer "^0.4.0"
+    listr-verbose-renderer "^0.4.0"
+    log-symbols "^1.0.2"
+    log-update "^1.0.2"
+    ora "^0.2.3"
+    p-map "^1.1.1"
+    rxjs "^5.4.2"
+    stream-to-observable "^0.2.0"
+    strip-ansi "^3.0.1"
+
+lodash@^4.17.4:
+  version "4.17.4"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
+
+log-symbols@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18"
+  dependencies:
+    chalk "^1.0.0"
+
+log-symbols@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.1.0.tgz#f35fa60e278832b538dc4dddcbb478a45d3e3be6"
+  dependencies:
+    chalk "^2.0.1"
+
+log-update@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/log-update/-/log-update-1.0.2.tgz#19929f64c4093d2d2e7075a1dad8af59c296b8d1"
+  dependencies:
+    ansi-escapes "^1.0.0"
+    cli-cursor "^1.0.2"
+
+lru-cache@^4.0.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55"
+  dependencies:
+    pseudomap "^1.0.2"
+    yallist "^2.1.2"
+
+minimatch@^3.0.0:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
+  dependencies:
+    brace-expansion "^1.1.7"
+
+normalize-path@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-1.0.0.tgz#32d0e472f91ff345701c15a8311018d3b0a90379"
+
+npm-path@^2.0.2:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/npm-path/-/npm-path-2.0.3.tgz#15cff4e1c89a38da77f56f6055b24f975dfb2bbe"
+  dependencies:
+    which "^1.2.10"
+
+npm-run-path@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
+  dependencies:
+    path-key "^2.0.0"
+
+npm-which@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/npm-which/-/npm-which-3.0.1.tgz#9225f26ec3a285c209cae67c3b11a6b4ab7140aa"
+  dependencies:
+    commander "^2.9.0"
+    npm-path "^2.0.2"
+    which "^1.2.10"
+
+number-is-nan@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
+
+object-assign@^4.0.1, object-assign@^4.1.0:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+
+onetime@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789"
+
+ora@^0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/ora/-/ora-0.2.3.tgz#37527d220adcd53c39b73571d754156d5db657a4"
+  dependencies:
+    chalk "^1.1.1"
+    cli-cursor "^1.0.2"
+    cli-spinners "^0.1.2"
+    object-assign "^4.0.1"
+
+p-finally@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
+
+p-map@^1.1.1:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b"
+
+parse-json@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-3.0.0.tgz#fa6f47b18e23826ead32f263e744d0e1e847fb13"
+  dependencies:
+    error-ex "^1.3.1"
+
+path-is-inside@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
+
+path-key@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
+
+pify@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
+
+prettier@^1.8.2:
+  version "1.8.2"
+  resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.8.2.tgz#bff83e7fd573933c607875e5ba3abbdffb96aeb8"
+
+pretty-format@^21.2.1:
+  version "21.2.1"
+  resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-21.2.1.tgz#ae5407f3cf21066cd011aa1ba5fce7b6a2eddb36"
+  dependencies:
+    ansi-regex "^3.0.0"
+    ansi-styles "^3.2.0"
+
+pseudomap@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
+
+repeating@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
+  dependencies:
+    is-finite "^1.0.0"
+
+require-from-string@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.1.tgz#c545233e9d7da6616e9d59adfb39fc9f588676ff"
+
+restore-cursor@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541"
+  dependencies:
+    exit-hook "^1.0.0"
+    onetime "^1.0.0"
+
+rxjs@^5.4.2:
+  version "5.5.3"
+  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.3.tgz#b62227e74b84f4e77bdf440e50b5ee01a1bc7dcd"
+  dependencies:
+    symbol-observable "^1.0.1"
+
+shebang-command@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
+  dependencies:
+    shebang-regex "^1.0.0"
+
+shebang-regex@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
+
+signal-exit@^3.0.0:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
+
+slice-ansi@0.0.4:
+  version "0.0.4"
+  resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"
+
+sprintf-js@~1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+
+staged-git-files@0.0.4:
+  version "0.0.4"
+  resolved "https://registry.yarnpkg.com/staged-git-files/-/staged-git-files-0.0.4.tgz#d797e1b551ca7a639dec0237dc6eb4bb9be17d35"
+
+stream-to-observable@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/stream-to-observable/-/stream-to-observable-0.2.0.tgz#59d6ea393d87c2c0ddac10aa0d561bc6ba6f0e10"
+  dependencies:
+    any-observable "^0.2.0"
+
+string-width@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
+  dependencies:
+    code-point-at "^1.0.0"
+    is-fullwidth-code-point "^1.0.0"
+    strip-ansi "^3.0.0"
+
+stringify-object@^3.2.0:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.2.1.tgz#2720c2eff940854c819f6ee252aaeb581f30624d"
+  dependencies:
+    get-own-enumerable-property-symbols "^2.0.1"
+    is-obj "^1.0.1"
+    is-regexp "^1.0.0"
+
+strip-ansi@^3.0.0, strip-ansi@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+  dependencies:
+    ansi-regex "^2.0.0"
+
+strip-eof@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
+
+strip-indent@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68"
+
+supports-color@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
+
+supports-color@^4.0.0:
+  version "4.5.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b"
+  dependencies:
+    has-flag "^2.0.0"
+
+symbol-observable@^0.2.2:
+  version "0.2.4"
+  resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-0.2.4.tgz#95a83db26186d6af7e7a18dbd9760a2f86d08f40"
+
+symbol-observable@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.1.0.tgz#5c68fd8d54115d9dfb72a84720549222e8db9b32"
+
+which@^1.2.10, which@^1.2.9:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a"
+  dependencies:
+    isexe "^2.0.0"
+
+yallist@^2.1.2:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"