Browse Source

merged in upstream

Jason Gaare 7 years ago
parent
commit
9e5cd12b2f
42 changed files with 1241 additions and 216 deletions
  1. 8
    0
      .gitignore
  2. 1
    0
      .npmignore
  3. 3
    0
      Example/.babelrc
  4. 16
    13
      Example/.flowconfig
  5. 1
    0
      Example/.gitattributes
  6. 16
    3
      Example/.gitignore
  7. 51
    11
      Example/Example.js
  8. 12
    0
      Example/__tests__/index.android.js
  9. 12
    0
      Example/__tests__/index.ios.js
  10. 3
    3
      Example/android/app/build.gradle
  11. 1
    3
      Example/android/app/src/main/AndroidManifest.xml
  12. 9
    2
      Example/android/app/src/main/java/com/example/MainApplication.java
  13. 1
    1
      Example/android/build.gradle
  14. 2
    1
      Example/android/gradle/wrapper/gradle-wrapper.properties
  15. 54
    0
      Example/ios/Example-tvOS/Info.plist
  16. 24
    0
      Example/ios/Example-tvOSTests/Info.plist
  17. 541
    44
      Example/ios/Example.xcodeproj/project.pbxproj
  18. 129
    0
      Example/ios/Example.xcodeproj/xcshareddata/xcschemes/Example-tvOS.xcscheme
  19. 23
    6
      Example/ios/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme
  20. 2
    2
      Example/ios/Example/AppDelegate.m
  21. 20
    4
      Example/ios/Example/Info.plist
  22. 1
    1
      Example/ios/Example/main.m
  23. 2
    2
      Example/ios/ExampleTests/ExampleTests.m
  24. 21
    11
      Example/package.json
  25. 7
    2
      RCTConvert+RNPStatus.h
  26. 2
    1
      RCTConvert+RNPStatus.m
  27. 104
    36
      README.md
  28. 5
    2
      ReactNativePermissions.h
  29. 9
    4
      ReactNativePermissions.js
  30. 41
    8
      ReactNativePermissions.m
  31. 1
    0
      ReactNativePermissions.podspec
  32. 7
    1
      ReactNativePermissions.xcodeproj/project.pbxproj
  33. 0
    0
      ReactNativePermissions.xcodeproj/xcuserdata/Yonah.xcuserdatad/xcschemes/ReactNativePermissions.xcscheme
  34. 4
    4
      android/build.gradle
  35. 19
    8
      android/src/main/java/com/joshblour/reactnativepermissions/ReactNativePermissionsModule.java
  36. 1
    1
      package.json
  37. 1
    1
      permissions/RNPLocation.h
  38. 14
    9
      permissions/RNPLocation.m
  39. 12
    31
      permissions/RNPNotification.m
  40. 0
    1
      permissions/RNPPhoto.m
  41. 17
    0
      permissions/RNPSpeechRecognition.h
  42. 44
    0
      permissions/RNPSpeechRecognition.m

+ 8
- 0
.gitignore View File

@@ -1,2 +1,10 @@
1 1
 android/react-native-permissions.iml
2 2
 android/build
3
+android/.idea
4
+npm-debug.log
5
+gradlew
6
+gradle-wrapper.properties
7
+gradle-wrapper.jar
8
+local.properties
9
+gradlew.bat
10
+android.iml

+ 1
- 0
.npmignore View File

@@ -0,0 +1 @@
1
+Example

+ 3
- 0
Example/.babelrc View File

@@ -0,0 +1,3 @@
1
+{
2
+"presets": ["react-native"]
3
+}

+ 16
- 13
Example/.flowconfig View File

@@ -1,13 +1,18 @@
1 1
 [ignore]
2
+; We fork some components by platform
3
+.*/*[.]android.js
2 4
 
3
-# We fork some components by platform.
4
-.*/*.android.js
5
+; Ignore "BUCK" generated dirs
6
+<PROJECT_ROOT>/\.buckd/
5 7
 
6
-# Ignore templates with `@flow` in header
7
-.*/local-cli/generator.*
8
+; Ignore unexpected extra "@providesModule"
9
+.*/node_modules/.*/node_modules/fbjs/.*
8 10
 
9
-# Ignore malformed json
10
-.*/node_modules/y18n/test/.*\.json
11
+; Ignore duplicate module providers
12
+; For RN Apps installed via npm, "Libraries" folder is inside
13
+; "node_modules/react-native" but in the source repo it is in the root
14
+.*/Libraries/react-native/React.js
15
+.*/Libraries/react-native/ReactNative.js
11 16
 
12 17
 [include]
13 18
 
@@ -19,23 +24,21 @@ flow/
19 24
 [options]
20 25
 module.system=haste
21 26
 
22
-esproposal.class_static_fields=enable
23
-esproposal.class_instance_fields=enable
24
-
25 27
 experimental.strict_type_args=true
26 28
 
27 29
 munge_underscores=true
28 30
 
29
-module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub'
30 31
 module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
31 32
 
32 33
 suppress_type=$FlowIssue
33 34
 suppress_type=$FlowFixMe
34 35
 suppress_type=$FixMe
35 36
 
36
-suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(2[0-7]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
37
-suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(2[0-7]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
37
+suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(3[0-7]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
38
+suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(3[0-7]\\|1[0-9]\\|[1-2][0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
38 39
 suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
39 40
 
41
+unsafe.enable_getters_and_setters=true
42
+
40 43
 [version]
41
-^0.27.0
44
+^0.37.0

+ 1
- 0
Example/.gitattributes View File

@@ -0,0 +1 @@
1
+*.pbxproj -text

+ 16
- 3
Example/.gitignore View File

@@ -22,20 +22,33 @@ DerivedData
22 22
 *.xcuserstate
23 23
 project.xcworkspace
24 24
 
25
-# Android/IJ
25
+# Android/IntelliJ
26 26
 #
27
-*.iml
27
+build/
28 28
 .idea
29 29
 .gradle
30 30
 local.properties
31
+*.iml
31 32
 
32 33
 # node.js
33 34
 #
34 35
 node_modules/
35 36
 npm-debug.log
37
+yarn-error.log
36 38
 
37 39
 # BUCK
38 40
 buck-out/
39 41
 \.buckd/
40 42
 android/app/libs
41
-android/keystores/debug.keystore
43
+*.keystore
44
+
45
+# fastlane
46
+#
47
+# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
48
+# screenshots whenever they are needed.
49
+# For more information about the recommended setup visit:
50
+# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
51
+
52
+fastlane/report.xml
53
+fastlane/Preview.html
54
+fastlane/screenshots

+ 51
- 11
Example/Example.js View File

@@ -12,6 +12,7 @@ import {
12 12
   View,
13 13
   Alert,
14 14
   AppState,
15
+  Platform,
15 16
 } from 'react-native';
16 17
 
17 18
 import Permissions from 'react-native-permissions'
@@ -40,13 +41,31 @@ export default class Example extends Component {
40 41
     }
41 42
   }
42 43
 
44
+  _openSettings() {
45
+    return Permissions.openSettings()
46
+      .then(() => alert('back to app!!'))
47
+  }
48
+
43 49
   _updatePermissions(types) {
44 50
     Permissions.checkMultiplePermissions(types)
51
+      .then(status => {
52
+        if (this.state.isAlways) {
53
+          return Permissions.getPermissionStatus('location', 'always')
54
+            .then(location => ({...status, location}))
55
+        }
56
+        return status
57
+      })
45 58
       .then(status => this.setState({ status }))
46 59
   }
47 60
 
48 61
   _requestPermission(permission) {
49
-    Permissions.requestPermission(permission)
62
+    var options
63
+
64
+    if (permission == 'location') {
65
+      options = this.state.isAlways ? 'always' : 'whenInUse'
66
+    }
67
+
68
+    Permissions.requestPermission(permission, options)
50 69
       .then(res => {
51 70
         this.setState({
52 71
           status: {...this.state.status, [permission]: res}
@@ -57,16 +76,22 @@ export default class Example extends Component {
57 76
             "There was a problem getting your permission. Please enable it from settings.",
58 77
             [
59 78
               {text: 'Cancel', style: 'cancel'},
60
-              {text: 'Open Settings', onPress: Permissions.openSettings },
79
+              {text: 'Open Settings', onPress: this._openSettings.bind(this) },
61 80
             ]
62 81
           )
63 82
         }
64 83
       }).catch(e => console.warn(e))
65 84
   }
66 85
 
86
+  _onLocationSwitchChange() {
87
+    this.setState({ isAlways: !this.state.isAlways })
88
+    this._updatePermissions(this.state.types)
89
+  }
90
+
67 91
   render() {
68 92
     return (
69 93
       <View style={styles.container}>
94
+
70 95
         {this.state.types.map(p => (
71 96
           <TouchableHighlight 
72 97
             style={[styles.button, styles[this.state.status[p]]]}
@@ -74,7 +99,7 @@ export default class Example extends Component {
74 99
             onPress={this._requestPermission.bind(this, p)}>
75 100
             <View>
76 101
               <Text style={styles.text}>
77
-                {p}
102
+                {Platform.OS == 'ios' && p == 'location' ? `location ${this.state.isAlways ? 'always' : 'whenInUse'}` : p}
78 103
               </Text>
79 104
               <Text style={styles.subtext}>
80 105
                 {this.state.status[p]}
@@ -83,13 +108,23 @@ export default class Example extends Component {
83 108
           </TouchableHighlight>
84 109
           )
85 110
         )}
86
-        <TouchableHighlight 
87
-          style={styles.openSettings}
88
-          onPress={Permissions.openSettings}>
89
-          <Text style={styles.text}>Open settings</Text>
90
-        </TouchableHighlight>
111
+        <View style={styles.footer}>
112
+          <TouchableHighlight 
113
+            style={styles['footer_'+Platform.OS]}
114
+            onPress={this._onLocationSwitchChange.bind(this)}>
115
+            <Text style={styles.text}>Toggle location type</Text>
116
+          </TouchableHighlight>
117
+
118
+          <TouchableHighlight 
119
+            onPress={this._openSettings.bind(this)}>
120
+            <Text style={styles.text}>Open settings</Text>
121
+          </TouchableHighlight>
122
+        </View>
91 123
 
92
-        <Text>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>
124
+
125
+        <Text style={styles['footer_'+Platform.OS]}>
126
+          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"
127
+        </Text>
93 128
       </View>
94 129
     );
95 130
   }
@@ -130,8 +165,13 @@ const styles = StyleSheet.create({
130 165
   restricted: {
131 166
     backgroundColor: '#FFAB91'
132 167
   },
133
-  openSettings: {
168
+  footer: {
134 169
     padding: 10,
135
-    alignSelf: 'flex-end',
170
+    flexDirection: 'row',
171
+    justifyContent: 'space-between',
172
+  },
173
+  footer_android: {
174
+    height: 0,
175
+    width: 0,
136 176
   }
137 177
 })

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

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

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

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

+ 3
- 3
Example/android/app/build.gradle View File

@@ -88,7 +88,7 @@ android {
88 88
 
89 89
     defaultConfig {
90 90
         applicationId "com.example"
91
-        minSdkVersion 22
91
+        minSdkVersion 21
92 92
         targetSdkVersion 23
93 93
         versionCode 1
94 94
         versionName "1.0"
@@ -135,6 +135,6 @@ dependencies {
135 135
 // Run this once to be able to run the application with BUCK
136 136
 // puts all compile dependencies into folder libs for BUCK to use
137 137
 task copyDownloadableDepsToLibs(type: Copy) {
138
-  from configurations.compile
139
-  into 'libs'
138
+    from configurations.compile
139
+    into 'libs'
140 140
 }

+ 1
- 3
Example/android/app/src/main/AndroidManifest.xml View File

@@ -9,12 +9,10 @@
9 9
     <uses-permission android:name="android.permission.CAMERA"/>
10 10
     <uses-permission android:name="android.permission.RECORD_AUDIO"/>
11 11
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
12
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
12 13
     <uses-permission android:name="android.permission.READ_CONTACTS"/>
13 14
     <uses-permission android:name="android.permission.READ_CALENDAR"/>
14 15
 
15
-    <uses-sdk
16
-        android:minSdkVersion="18"
17
-        android:targetSdkVersion="23" />
18 16
 
19 17
     <application
20 18
       android:name=".MainApplication"

+ 9
- 2
Example/android/app/src/main/java/com/example/MainApplication.java View File

@@ -9,6 +9,7 @@ import com.facebook.react.ReactNativeHost;
9 9
 import com.facebook.react.ReactPackage;
10 10
 import com.facebook.react.shell.MainReactPackage;
11 11
 import com.joshblour.reactnativepermissions.ReactNativePermissionsPackage;
12
+import com.facebook.soloader.SoLoader;
12 13
 
13 14
 import java.util.Arrays;
14 15
 import java.util.List;
@@ -17,7 +18,7 @@ public class MainApplication extends Application implements ReactApplication {
17 18
 
18 19
   private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
19 20
     @Override
20
-    protected boolean getUseDeveloperSupport() {
21
+    public boolean getUseDeveloperSupport() {
21 22
       return BuildConfig.DEBUG;
22 23
     }
23 24
 
@@ -32,6 +33,12 @@ public class MainApplication extends Application implements ReactApplication {
32 33
 
33 34
   @Override
34 35
   public ReactNativeHost getReactNativeHost() {
35
-      return mReactNativeHost;
36
+    return mReactNativeHost;
37
+  }
38
+
39
+  @Override
40
+  public void onCreate() {
41
+    super.onCreate();
42
+    SoLoader.init(this, /* native exopackage */ false);
36 43
   }
37 44
 }

+ 1
- 1
Example/android/build.gradle View File

@@ -5,7 +5,7 @@ buildscript {
5 5
         jcenter()
6 6
     }
7 7
     dependencies {
8
-        classpath 'com.android.tools.build:gradle:1.3.1'
8
+        classpath 'com.android.tools.build:gradle:2.1.2'
9 9
 
10 10
         // NOTE: Do not place your application dependencies here; they belong
11 11
         // in the individual module build.gradle files

+ 2
- 1
Example/android/gradle/wrapper/gradle-wrapper.properties View File

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

+ 54
- 0
Example/ios/Example-tvOS/Info.plist View File

@@ -0,0 +1,54 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+<plist version="1.0">
4
+<dict>
5
+	<key>CFBundleDevelopmentRegion</key>
6
+	<string>en</string>
7
+	<key>CFBundleExecutable</key>
8
+	<string>$(EXECUTABLE_NAME)</string>
9
+	<key>CFBundleIdentifier</key>
10
+	<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string>
11
+	<key>CFBundleInfoDictionaryVersion</key>
12
+	<string>6.0</string>
13
+	<key>CFBundleName</key>
14
+	<string>$(PRODUCT_NAME)</string>
15
+	<key>CFBundlePackageType</key>
16
+	<string>APPL</string>
17
+	<key>CFBundleShortVersionString</key>
18
+	<string>1.0</string>
19
+	<key>CFBundleSignature</key>
20
+	<string>????</string>
21
+	<key>CFBundleVersion</key>
22
+	<string>1</string>
23
+	<key>LSRequiresIPhoneOS</key>
24
+	<true/>
25
+	<key>UILaunchStoryboardName</key>
26
+	<string>LaunchScreen</string>
27
+	<key>UIRequiredDeviceCapabilities</key>
28
+	<array>
29
+		<string>armv7</string>
30
+	</array>
31
+	<key>UISupportedInterfaceOrientations</key>
32
+	<array>
33
+		<string>UIInterfaceOrientationPortrait</string>
34
+		<string>UIInterfaceOrientationLandscapeLeft</string>
35
+		<string>UIInterfaceOrientationLandscapeRight</string>
36
+	</array>
37
+	<key>UIViewControllerBasedStatusBarAppearance</key>
38
+	<false/>
39
+	<key>NSLocationWhenInUseUsageDescription</key>
40
+	<string></string>
41
+	<key>NSAppTransportSecurity</key>
42
+	<!--See http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/ -->
43
+	<dict>
44
+		<key>NSExceptionDomains</key>
45
+		<dict>
46
+			<key>localhost</key>
47
+			<dict>
48
+				<key>NSExceptionAllowsInsecureHTTPLoads</key>
49
+				<true/>
50
+			</dict>
51
+		</dict>
52
+	</dict>
53
+</dict>
54
+</plist>

+ 24
- 0
Example/ios/Example-tvOSTests/Info.plist View File

@@ -0,0 +1,24 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+<plist version="1.0">
4
+<dict>
5
+	<key>CFBundleDevelopmentRegion</key>
6
+	<string>en</string>
7
+	<key>CFBundleExecutable</key>
8
+	<string>$(EXECUTABLE_NAME)</string>
9
+	<key>CFBundleIdentifier</key>
10
+	<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string>
11
+	<key>CFBundleInfoDictionaryVersion</key>
12
+	<string>6.0</string>
13
+	<key>CFBundleName</key>
14
+	<string>$(PRODUCT_NAME)</string>
15
+	<key>CFBundlePackageType</key>
16
+	<string>BNDL</string>
17
+	<key>CFBundleShortVersionString</key>
18
+	<string>1.0</string>
19
+	<key>CFBundleSignature</key>
20
+	<string>????</string>
21
+	<key>CFBundleVersion</key>
22
+	<string>1</string>
23
+</dict>
24
+</plist>

+ 541
- 44
Example/ios/Example.xcodeproj/project.pbxproj View File

@@ -22,7 +22,20 @@
22 22
 		13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
23 23
 		140ED2AC1D01E1AD002B40FF /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
24 24
 		146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
25
-		50F9604CB69B4BA6A44EA44F /* libReactNativePermissions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D9820CCF930F4ED1BE137DA6 /* libReactNativePermissions.a */; };
25
+		14902CDAB1064113A6B4C970 /* libReactNativePermissions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B27CA08432F04FFCB0256EA1 /* libReactNativePermissions.a */; };
26
+		2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
27
+		2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
28
+		2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
29
+		2D02E4C21E0B4AEC006451C7 /* libRCTAnimation-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation-tvOS.a */; };
30
+		2D02E4C31E0B4AEC006451C7 /* libRCTImage-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */; };
31
+		2D02E4C41E0B4AEC006451C7 /* libRCTLinking-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */; };
32
+		2D02E4C51E0B4AEC006451C7 /* libRCTNetwork-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */; };
33
+		2D02E4C61E0B4AEC006451C7 /* libRCTSettings-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E901DF850E9000B6D8A /* libRCTSettings-tvOS.a */; };
34
+		2D02E4C71E0B4AEC006451C7 /* libRCTText-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */; };
35
+		2D02E4C81E0B4AEC006451C7 /* libRCTWebSocket-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */; };
36
+		2D02E4C91E0B4AEC006451C7 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3EA31DF850E9000B6D8A /* libReact.a */; };
37
+		2DCD954D1E0B4F2C00145EB5 /* ExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* ExampleTests.m */; };
38
+		5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */; };
26 39
 		832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
27 40
 /* End PBXBuildFile section */
28 41
 
@@ -90,6 +103,118 @@
90 103
 			remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192;
91 104
 			remoteInfo = React;
92 105
 		};
106
+		2D02E4911E0B4A5D006451C7 /* PBXContainerItemProxy */ = {
107
+			isa = PBXContainerItemProxy;
108
+			containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
109
+			proxyType = 1;
110
+			remoteGlobalIDString = 2D02E47A1E0B4A5D006451C7;
111
+			remoteInfo = "Example-tvOS";
112
+		};
113
+		3DAD3E831DF850E9000B6D8A /* PBXContainerItemProxy */ = {
114
+			isa = PBXContainerItemProxy;
115
+			containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
116
+			proxyType = 2;
117
+			remoteGlobalIDString = 2D2A283A1D9B042B00D4039D;
118
+			remoteInfo = "RCTImage-tvOS";
119
+		};
120
+		3DAD3E871DF850E9000B6D8A /* PBXContainerItemProxy */ = {
121
+			isa = PBXContainerItemProxy;
122
+			containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;
123
+			proxyType = 2;
124
+			remoteGlobalIDString = 2D2A28471D9B043800D4039D;
125
+			remoteInfo = "RCTLinking-tvOS";
126
+		};
127
+		3DAD3E8B1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
128
+			isa = PBXContainerItemProxy;
129
+			containerPortal = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */;
130
+			proxyType = 2;
131
+			remoteGlobalIDString = 2D2A28541D9B044C00D4039D;
132
+			remoteInfo = "RCTNetwork-tvOS";
133
+		};
134
+		3DAD3E8F1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
135
+			isa = PBXContainerItemProxy;
136
+			containerPortal = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */;
137
+			proxyType = 2;
138
+			remoteGlobalIDString = 2D2A28611D9B046600D4039D;
139
+			remoteInfo = "RCTSettings-tvOS";
140
+		};
141
+		3DAD3E931DF850E9000B6D8A /* PBXContainerItemProxy */ = {
142
+			isa = PBXContainerItemProxy;
143
+			containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
144
+			proxyType = 2;
145
+			remoteGlobalIDString = 2D2A287B1D9B048500D4039D;
146
+			remoteInfo = "RCTText-tvOS";
147
+		};
148
+		3DAD3E981DF850E9000B6D8A /* PBXContainerItemProxy */ = {
149
+			isa = PBXContainerItemProxy;
150
+			containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
151
+			proxyType = 2;
152
+			remoteGlobalIDString = 2D2A28881D9B049200D4039D;
153
+			remoteInfo = "RCTWebSocket-tvOS";
154
+		};
155
+		3DAD3EA21DF850E9000B6D8A /* PBXContainerItemProxy */ = {
156
+			isa = PBXContainerItemProxy;
157
+			containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
158
+			proxyType = 2;
159
+			remoteGlobalIDString = 2D2A28131D9B038B00D4039D;
160
+			remoteInfo = "React-tvOS";
161
+		};
162
+		3DAD3EA41DF850E9000B6D8A /* PBXContainerItemProxy */ = {
163
+			isa = PBXContainerItemProxy;
164
+			containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
165
+			proxyType = 2;
166
+			remoteGlobalIDString = 3D3C059A1DE3340900C268FA;
167
+			remoteInfo = yoga;
168
+		};
169
+		3DAD3EA61DF850E9000B6D8A /* PBXContainerItemProxy */ = {
170
+			isa = PBXContainerItemProxy;
171
+			containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
172
+			proxyType = 2;
173
+			remoteGlobalIDString = 3D3C06751DE3340C00C268FA;
174
+			remoteInfo = "yoga-tvOS";
175
+		};
176
+		3DAD3EA81DF850E9000B6D8A /* PBXContainerItemProxy */ = {
177
+			isa = PBXContainerItemProxy;
178
+			containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
179
+			proxyType = 2;
180
+			remoteGlobalIDString = 3D3CD9251DE5FBEC00167DC4;
181
+			remoteInfo = cxxreact;
182
+		};
183
+		3DAD3EAA1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
184
+			isa = PBXContainerItemProxy;
185
+			containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
186
+			proxyType = 2;
187
+			remoteGlobalIDString = 3D3CD9321DE5FBEE00167DC4;
188
+			remoteInfo = "cxxreact-tvOS";
189
+		};
190
+		3DAD3EAC1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
191
+			isa = PBXContainerItemProxy;
192
+			containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
193
+			proxyType = 2;
194
+			remoteGlobalIDString = 3D3CD90B1DE5FBD600167DC4;
195
+			remoteInfo = jschelpers;
196
+		};
197
+		3DAD3EAE1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
198
+			isa = PBXContainerItemProxy;
199
+			containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
200
+			proxyType = 2;
201
+			remoteGlobalIDString = 3D3CD9181DE5FBD800167DC4;
202
+			remoteInfo = "jschelpers-tvOS";
203
+		};
204
+		5E9157321DD0AC6500FF2AA8 /* PBXContainerItemProxy */ = {
205
+			isa = PBXContainerItemProxy;
206
+			containerPortal = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */;
207
+			proxyType = 2;
208
+			remoteGlobalIDString = 134814201AA4EA6300B7C361;
209
+			remoteInfo = RCTAnimation;
210
+		};
211
+		5E9157341DD0AC6500FF2AA8 /* PBXContainerItemProxy */ = {
212
+			isa = PBXContainerItemProxy;
213
+			containerPortal = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */;
214
+			proxyType = 2;
215
+			remoteGlobalIDString = 2D2A28201D9B03D100D4039D;
216
+			remoteInfo = "RCTAnimation-tvOS";
217
+		};
93 218
 		78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */ = {
94 219
 			isa = PBXContainerItemProxy;
95 220
 			containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;
@@ -104,9 +229,9 @@
104 229
 			remoteGlobalIDString = 58B5119B1A9E6C1200147676;
105 230
 			remoteInfo = RCTText;
106 231
 		};
107
-		9D1B45CC1D49EE8400459C66 /* PBXContainerItemProxy */ = {
232
+		9D8131C41E44834800F4B1D3 /* PBXContainerItemProxy */ = {
108 233
 			isa = PBXContainerItemProxy;
109
-			containerPortal = 783F116470084EEB95DCA092 /* ReactNativePermissions.xcodeproj */;
234
+			containerPortal = 8068EB7451414340B0AC0D03 /* ReactNativePermissions.xcodeproj */;
110 235
 			proxyType = 2;
111 236
 			remoteGlobalIDString = 9D23B34F1C767B80008B4819;
112 237
 			remoteInfo = ReactNativePermissions;
@@ -133,10 +258,13 @@
133 258
 		13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Example/Info.plist; sourceTree = "<group>"; };
134 259
 		13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = Example/main.m; sourceTree = "<group>"; };
135 260
 		146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = "<group>"; };
136
-		783F116470084EEB95DCA092 /* 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>"; };
261
+		2D02E47B1E0B4A5D006451C7 /* Example-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Example-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
262
+		2D02E4901E0B4A5D006451C7 /* Example-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Example-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
263
+		5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = "<group>"; };
137 264
 		78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = "<group>"; };
265
+		8068EB7451414340B0AC0D03 /* ReactNativePermissions.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = ReactNativePermissions.xcodeproj; path = "../node_modules/react-native-permissions/ReactNativePermissions.xcodeproj"; sourceTree = "<group>"; };
138 266
 		832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = "<group>"; };
139
-		D9820CCF930F4ED1BE137DA6 /* libReactNativePermissions.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libReactNativePermissions.a; sourceTree = "<group>"; };
267
+		B27CA08432F04FFCB0256EA1 /* libReactNativePermissions.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libReactNativePermissions.a; sourceTree = "<group>"; };
140 268
 /* End PBXFileReference section */
141 269
 
142 270
 /* Begin PBXFrameworksBuildPhase section */
@@ -153,6 +281,7 @@
153 281
 			buildActionMask = 2147483647;
154 282
 			files = (
155 283
 				146834051AC3E58100842450 /* libReact.a in Frameworks */,
284
+				5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */,
156 285
 				00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */,
157 286
 				00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */,
158 287
 				00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */,
@@ -162,7 +291,29 @@
162 291
 				832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */,
163 292
 				00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */,
164 293
 				139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */,
165
-				50F9604CB69B4BA6A44EA44F /* libReactNativePermissions.a in Frameworks */,
294
+				14902CDAB1064113A6B4C970 /* libReactNativePermissions.a in Frameworks */,
295
+			);
296
+			runOnlyForDeploymentPostprocessing = 0;
297
+		};
298
+		2D02E4781E0B4A5D006451C7 /* Frameworks */ = {
299
+			isa = PBXFrameworksBuildPhase;
300
+			buildActionMask = 2147483647;
301
+			files = (
302
+				2D02E4C91E0B4AEC006451C7 /* libReact.a in Frameworks */,
303
+				2D02E4C21E0B4AEC006451C7 /* libRCTAnimation-tvOS.a in Frameworks */,
304
+				2D02E4C31E0B4AEC006451C7 /* libRCTImage-tvOS.a in Frameworks */,
305
+				2D02E4C41E0B4AEC006451C7 /* libRCTLinking-tvOS.a in Frameworks */,
306
+				2D02E4C51E0B4AEC006451C7 /* libRCTNetwork-tvOS.a in Frameworks */,
307
+				2D02E4C61E0B4AEC006451C7 /* libRCTSettings-tvOS.a in Frameworks */,
308
+				2D02E4C71E0B4AEC006451C7 /* libRCTText-tvOS.a in Frameworks */,
309
+				2D02E4C81E0B4AEC006451C7 /* libRCTWebSocket-tvOS.a in Frameworks */,
310
+			);
311
+			runOnlyForDeploymentPostprocessing = 0;
312
+		};
313
+		2D02E48D1E0B4A5D006451C7 /* Frameworks */ = {
314
+			isa = PBXFrameworksBuildPhase;
315
+			buildActionMask = 2147483647;
316
+			files = (
166 317
 			);
167 318
 			runOnlyForDeploymentPostprocessing = 0;
168 319
 		};
@@ -189,6 +340,7 @@
189 340
 			isa = PBXGroup;
190 341
 			children = (
191 342
 				00C302C01ABCB91800DB3ED1 /* libRCTImage.a */,
343
+				3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */,
192 344
 			);
193 345
 			name = Products;
194 346
 			sourceTree = "<group>";
@@ -197,6 +349,7 @@
197 349
 			isa = PBXGroup;
198 350
 			children = (
199 351
 				00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */,
352
+				3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */,
200 353
 			);
201 354
 			name = Products;
202 355
 			sourceTree = "<group>";
@@ -230,6 +383,7 @@
230 383
 			isa = PBXGroup;
231 384
 			children = (
232 385
 				139105C11AF99BAD00B5F7CC /* libRCTSettings.a */,
386
+				3DAD3E901DF850E9000B6D8A /* libRCTSettings-tvOS.a */,
233 387
 			);
234 388
 			name = Products;
235 389
 			sourceTree = "<group>";
@@ -238,6 +392,7 @@
238 392
 			isa = PBXGroup;
239 393
 			children = (
240 394
 				139FDEF41B06529B00C62182 /* libRCTWebSocket.a */,
395
+				3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */,
241 396
 			);
242 397
 			name = Products;
243 398
 			sourceTree = "<group>";
@@ -260,6 +415,22 @@
260 415
 			isa = PBXGroup;
261 416
 			children = (
262 417
 				146834041AC3E56700842450 /* libReact.a */,
418
+				3DAD3EA31DF850E9000B6D8A /* libReact.a */,
419
+				3DAD3EA51DF850E9000B6D8A /* libyoga.a */,
420
+				3DAD3EA71DF850E9000B6D8A /* libyoga.a */,
421
+				3DAD3EA91DF850E9000B6D8A /* libcxxreact.a */,
422
+				3DAD3EAB1DF850E9000B6D8A /* libcxxreact.a */,
423
+				3DAD3EAD1DF850E9000B6D8A /* libjschelpers.a */,
424
+				3DAD3EAF1DF850E9000B6D8A /* libjschelpers.a */,
425
+			);
426
+			name = Products;
427
+			sourceTree = "<group>";
428
+		};
429
+		5E91572E1DD0AC6500FF2AA8 /* Products */ = {
430
+			isa = PBXGroup;
431
+			children = (
432
+				5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */,
433
+				5E9157351DD0AC6500FF2AA8 /* libRCTAnimation-tvOS.a */,
263 434
 			);
264 435
 			name = Products;
265 436
 			sourceTree = "<group>";
@@ -268,6 +439,7 @@
268 439
 			isa = PBXGroup;
269 440
 			children = (
270 441
 				78C398B91ACF4ADC00677621 /* libRCTLinking.a */,
442
+				3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */,
271 443
 			);
272 444
 			name = Products;
273 445
 			sourceTree = "<group>";
@@ -275,6 +447,7 @@
275 447
 		832341AE1AAA6A7D00B99B32 /* Libraries */ = {
276 448
 			isa = PBXGroup;
277 449
 			children = (
450
+				5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */,
278 451
 				146833FF1AC3E56700842450 /* React.xcodeproj */,
279 452
 				00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */,
280 453
 				00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */,
@@ -285,7 +458,7 @@
285 458
 				832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */,
286 459
 				00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */,
287 460
 				139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */,
288
-				783F116470084EEB95DCA092 /* ReactNativePermissions.xcodeproj */,
461
+				8068EB7451414340B0AC0D03 /* ReactNativePermissions.xcodeproj */,
289 462
 			);
290 463
 			name = Libraries;
291 464
 			sourceTree = "<group>";
@@ -294,6 +467,7 @@
294 467
 			isa = PBXGroup;
295 468
 			children = (
296 469
 				832341B51AAA6A8300B99B32 /* libRCTText.a */,
470
+				3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */,
297 471
 			);
298 472
 			name = Products;
299 473
 			sourceTree = "<group>";
@@ -315,14 +489,16 @@
315 489
 			children = (
316 490
 				13B07F961A680F5B00A75B9A /* Example.app */,
317 491
 				00E356EE1AD99517003FC87E /* ExampleTests.xctest */,
492
+				2D02E47B1E0B4A5D006451C7 /* Example-tvOS.app */,
493
+				2D02E4901E0B4A5D006451C7 /* Example-tvOSTests.xctest */,
318 494
 			);
319 495
 			name = Products;
320 496
 			sourceTree = "<group>";
321 497
 		};
322
-		9D1B45BF1D49EE8300459C66 /* Products */ = {
498
+		9D8131A81E44834700F4B1D3 /* Products */ = {
323 499
 			isa = PBXGroup;
324 500
 			children = (
325
-				9D1B45CD1D49EE8400459C66 /* libReactNativePermissions.a */,
501
+				9D8131C51E44834800F4B1D3 /* libReactNativePermissions.a */,
326 502
 			);
327 503
 			name = Products;
328 504
 			sourceTree = "<group>";
@@ -366,13 +542,49 @@
366 542
 			productReference = 13B07F961A680F5B00A75B9A /* Example.app */;
367 543
 			productType = "com.apple.product-type.application";
368 544
 		};
545
+		2D02E47A1E0B4A5D006451C7 /* Example-tvOS */ = {
546
+			isa = PBXNativeTarget;
547
+			buildConfigurationList = 2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "Example-tvOS" */;
548
+			buildPhases = (
549
+				2D02E4771E0B4A5D006451C7 /* Sources */,
550
+				2D02E4781E0B4A5D006451C7 /* Frameworks */,
551
+				2D02E4791E0B4A5D006451C7 /* Resources */,
552
+				2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */,
553
+			);
554
+			buildRules = (
555
+			);
556
+			dependencies = (
557
+			);
558
+			name = "Example-tvOS";
559
+			productName = "Example-tvOS";
560
+			productReference = 2D02E47B1E0B4A5D006451C7 /* Example-tvOS.app */;
561
+			productType = "com.apple.product-type.application";
562
+		};
563
+		2D02E48F1E0B4A5D006451C7 /* Example-tvOSTests */ = {
564
+			isa = PBXNativeTarget;
565
+			buildConfigurationList = 2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "Example-tvOSTests" */;
566
+			buildPhases = (
567
+				2D02E48C1E0B4A5D006451C7 /* Sources */,
568
+				2D02E48D1E0B4A5D006451C7 /* Frameworks */,
569
+				2D02E48E1E0B4A5D006451C7 /* Resources */,
570
+			);
571
+			buildRules = (
572
+			);
573
+			dependencies = (
574
+				2D02E4921E0B4A5D006451C7 /* PBXTargetDependency */,
575
+			);
576
+			name = "Example-tvOSTests";
577
+			productName = "Example-tvOSTests";
578
+			productReference = 2D02E4901E0B4A5D006451C7 /* Example-tvOSTests.xctest */;
579
+			productType = "com.apple.product-type.bundle.unit-test";
580
+		};
369 581
 /* End PBXNativeTarget section */
370 582
 
371 583
 /* Begin PBXProject section */
372 584
 		83CBB9F71A601CBA00E9B192 /* Project object */ = {
373 585
 			isa = PBXProject;
374 586
 			attributes = {
375
-				LastUpgradeCheck = 610;
587
+				LastUpgradeCheck = 0820;
376 588
 				ORGANIZATIONNAME = Facebook;
377 589
 				TargetAttributes = {
378 590
 					00E356ED1AD99517003FC87E = {
@@ -386,6 +598,15 @@
386 598
 							};
387 599
 						};
388 600
 					};
601
+					2D02E47A1E0B4A5D006451C7 = {
602
+						CreatedOnToolsVersion = 8.2.1;
603
+						ProvisioningStyle = Automatic;
604
+					};
605
+					2D02E48F1E0B4A5D006451C7 = {
606
+						CreatedOnToolsVersion = 8.2.1;
607
+						ProvisioningStyle = Automatic;
608
+						TestTargetID = 2D02E47A1E0B4A5D006451C7;
609
+					};
389 610
 				};
390 611
 			};
391 612
 			buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Example" */;
@@ -404,6 +625,10 @@
404 625
 					ProductGroup = 00C302A81ABCB8CE00DB3ED1 /* Products */;
405 626
 					ProjectRef = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */;
406 627
 				},
628
+				{
629
+					ProductGroup = 5E91572E1DD0AC6500FF2AA8 /* Products */;
630
+					ProjectRef = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */;
631
+				},
407 632
 				{
408 633
 					ProductGroup = 00C302B61ABCB90400DB3ED1 /* Products */;
409 634
 					ProjectRef = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */;
@@ -441,14 +666,16 @@
441 666
 					ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */;
442 667
 				},
443 668
 				{
444
-					ProductGroup = 9D1B45BF1D49EE8300459C66 /* Products */;
445
-					ProjectRef = 783F116470084EEB95DCA092 /* ReactNativePermissions.xcodeproj */;
669
+					ProductGroup = 9D8131A81E44834700F4B1D3 /* Products */;
670
+					ProjectRef = 8068EB7451414340B0AC0D03 /* ReactNativePermissions.xcodeproj */;
446 671
 				},
447 672
 			);
448 673
 			projectRoot = "";
449 674
 			targets = (
450 675
 				13B07F861A680F5B00A75B9A /* Example */,
451 676
 				00E356ED1AD99517003FC87E /* ExampleTests */,
677
+				2D02E47A1E0B4A5D006451C7 /* Example-tvOS */,
678
+				2D02E48F1E0B4A5D006451C7 /* Example-tvOSTests */,
452 679
 			);
453 680
 		};
454 681
 /* End PBXProject section */
@@ -510,6 +737,111 @@
510 737
 			remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */;
511 738
 			sourceTree = BUILT_PRODUCTS_DIR;
512 739
 		};
740
+		3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */ = {
741
+			isa = PBXReferenceProxy;
742
+			fileType = archive.ar;
743
+			path = "libRCTImage-tvOS.a";
744
+			remoteRef = 3DAD3E831DF850E9000B6D8A /* PBXContainerItemProxy */;
745
+			sourceTree = BUILT_PRODUCTS_DIR;
746
+		};
747
+		3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */ = {
748
+			isa = PBXReferenceProxy;
749
+			fileType = archive.ar;
750
+			path = "libRCTLinking-tvOS.a";
751
+			remoteRef = 3DAD3E871DF850E9000B6D8A /* PBXContainerItemProxy */;
752
+			sourceTree = BUILT_PRODUCTS_DIR;
753
+		};
754
+		3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */ = {
755
+			isa = PBXReferenceProxy;
756
+			fileType = archive.ar;
757
+			path = "libRCTNetwork-tvOS.a";
758
+			remoteRef = 3DAD3E8B1DF850E9000B6D8A /* PBXContainerItemProxy */;
759
+			sourceTree = BUILT_PRODUCTS_DIR;
760
+		};
761
+		3DAD3E901DF850E9000B6D8A /* libRCTSettings-tvOS.a */ = {
762
+			isa = PBXReferenceProxy;
763
+			fileType = archive.ar;
764
+			path = "libRCTSettings-tvOS.a";
765
+			remoteRef = 3DAD3E8F1DF850E9000B6D8A /* PBXContainerItemProxy */;
766
+			sourceTree = BUILT_PRODUCTS_DIR;
767
+		};
768
+		3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */ = {
769
+			isa = PBXReferenceProxy;
770
+			fileType = archive.ar;
771
+			path = "libRCTText-tvOS.a";
772
+			remoteRef = 3DAD3E931DF850E9000B6D8A /* PBXContainerItemProxy */;
773
+			sourceTree = BUILT_PRODUCTS_DIR;
774
+		};
775
+		3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */ = {
776
+			isa = PBXReferenceProxy;
777
+			fileType = archive.ar;
778
+			path = "libRCTWebSocket-tvOS.a";
779
+			remoteRef = 3DAD3E981DF850E9000B6D8A /* PBXContainerItemProxy */;
780
+			sourceTree = BUILT_PRODUCTS_DIR;
781
+		};
782
+		3DAD3EA31DF850E9000B6D8A /* libReact.a */ = {
783
+			isa = PBXReferenceProxy;
784
+			fileType = archive.ar;
785
+			path = libReact.a;
786
+			remoteRef = 3DAD3EA21DF850E9000B6D8A /* PBXContainerItemProxy */;
787
+			sourceTree = BUILT_PRODUCTS_DIR;
788
+		};
789
+		3DAD3EA51DF850E9000B6D8A /* libyoga.a */ = {
790
+			isa = PBXReferenceProxy;
791
+			fileType = archive.ar;
792
+			path = libyoga.a;
793
+			remoteRef = 3DAD3EA41DF850E9000B6D8A /* PBXContainerItemProxy */;
794
+			sourceTree = BUILT_PRODUCTS_DIR;
795
+		};
796
+		3DAD3EA71DF850E9000B6D8A /* libyoga.a */ = {
797
+			isa = PBXReferenceProxy;
798
+			fileType = archive.ar;
799
+			path = libyoga.a;
800
+			remoteRef = 3DAD3EA61DF850E9000B6D8A /* PBXContainerItemProxy */;
801
+			sourceTree = BUILT_PRODUCTS_DIR;
802
+		};
803
+		3DAD3EA91DF850E9000B6D8A /* libcxxreact.a */ = {
804
+			isa = PBXReferenceProxy;
805
+			fileType = archive.ar;
806
+			path = libcxxreact.a;
807
+			remoteRef = 3DAD3EA81DF850E9000B6D8A /* PBXContainerItemProxy */;
808
+			sourceTree = BUILT_PRODUCTS_DIR;
809
+		};
810
+		3DAD3EAB1DF850E9000B6D8A /* libcxxreact.a */ = {
811
+			isa = PBXReferenceProxy;
812
+			fileType = archive.ar;
813
+			path = libcxxreact.a;
814
+			remoteRef = 3DAD3EAA1DF850E9000B6D8A /* PBXContainerItemProxy */;
815
+			sourceTree = BUILT_PRODUCTS_DIR;
816
+		};
817
+		3DAD3EAD1DF850E9000B6D8A /* libjschelpers.a */ = {
818
+			isa = PBXReferenceProxy;
819
+			fileType = archive.ar;
820
+			path = libjschelpers.a;
821
+			remoteRef = 3DAD3EAC1DF850E9000B6D8A /* PBXContainerItemProxy */;
822
+			sourceTree = BUILT_PRODUCTS_DIR;
823
+		};
824
+		3DAD3EAF1DF850E9000B6D8A /* libjschelpers.a */ = {
825
+			isa = PBXReferenceProxy;
826
+			fileType = archive.ar;
827
+			path = libjschelpers.a;
828
+			remoteRef = 3DAD3EAE1DF850E9000B6D8A /* PBXContainerItemProxy */;
829
+			sourceTree = BUILT_PRODUCTS_DIR;
830
+		};
831
+		5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */ = {
832
+			isa = PBXReferenceProxy;
833
+			fileType = archive.ar;
834
+			path = libRCTAnimation.a;
835
+			remoteRef = 5E9157321DD0AC6500FF2AA8 /* PBXContainerItemProxy */;
836
+			sourceTree = BUILT_PRODUCTS_DIR;
837
+		};
838
+		5E9157351DD0AC6500FF2AA8 /* libRCTAnimation-tvOS.a */ = {
839
+			isa = PBXReferenceProxy;
840
+			fileType = archive.ar;
841
+			path = "libRCTAnimation-tvOS.a";
842
+			remoteRef = 5E9157341DD0AC6500FF2AA8 /* PBXContainerItemProxy */;
843
+			sourceTree = BUILT_PRODUCTS_DIR;
844
+		};
513 845
 		78C398B91ACF4ADC00677621 /* libRCTLinking.a */ = {
514 846
 			isa = PBXReferenceProxy;
515 847
 			fileType = archive.ar;
@@ -524,11 +856,11 @@
524 856
 			remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */;
525 857
 			sourceTree = BUILT_PRODUCTS_DIR;
526 858
 		};
527
-		9D1B45CD1D49EE8400459C66 /* libReactNativePermissions.a */ = {
859
+		9D8131C51E44834800F4B1D3 /* libReactNativePermissions.a */ = {
528 860
 			isa = PBXReferenceProxy;
529 861
 			fileType = archive.ar;
530 862
 			path = libReactNativePermissions.a;
531
-			remoteRef = 9D1B45CC1D49EE8400459C66 /* PBXContainerItemProxy */;
863
+			remoteRef = 9D8131C41E44834800F4B1D3 /* PBXContainerItemProxy */;
532 864
 			sourceTree = BUILT_PRODUCTS_DIR;
533 865
 		};
534 866
 /* End PBXReferenceProxy section */
@@ -550,6 +882,21 @@
550 882
 			);
551 883
 			runOnlyForDeploymentPostprocessing = 0;
552 884
 		};
885
+		2D02E4791E0B4A5D006451C7 /* Resources */ = {
886
+			isa = PBXResourcesBuildPhase;
887
+			buildActionMask = 2147483647;
888
+			files = (
889
+				2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */,
890
+			);
891
+			runOnlyForDeploymentPostprocessing = 0;
892
+		};
893
+		2D02E48E1E0B4A5D006451C7 /* Resources */ = {
894
+			isa = PBXResourcesBuildPhase;
895
+			buildActionMask = 2147483647;
896
+			files = (
897
+			);
898
+			runOnlyForDeploymentPostprocessing = 0;
899
+		};
553 900
 /* End PBXResourcesBuildPhase section */
554 901
 
555 902
 /* Begin PBXShellScriptBuildPhase section */
@@ -567,6 +914,20 @@
567 914
 			shellPath = /bin/sh;
568 915
 			shellScript = "export NODE_BINARY=node\n../node_modules/react-native/packager/react-native-xcode.sh";
569 916
 		};
917
+		2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */ = {
918
+			isa = PBXShellScriptBuildPhase;
919
+			buildActionMask = 2147483647;
920
+			files = (
921
+			);
922
+			inputPaths = (
923
+			);
924
+			name = "Bundle React Native Code And Images";
925
+			outputPaths = (
926
+			);
927
+			runOnlyForDeploymentPostprocessing = 0;
928
+			shellPath = /bin/sh;
929
+			shellScript = "export NODE_BINARY=node\n../node_modules/react-native/packager/react-native-xcode.sh";
930
+		};
570 931
 /* End PBXShellScriptBuildPhase section */
571 932
 
572 933
 /* Begin PBXSourcesBuildPhase section */
@@ -587,6 +948,23 @@
587 948
 			);
588 949
 			runOnlyForDeploymentPostprocessing = 0;
589 950
 		};
951
+		2D02E4771E0B4A5D006451C7 /* Sources */ = {
952
+			isa = PBXSourcesBuildPhase;
953
+			buildActionMask = 2147483647;
954
+			files = (
955
+				2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */,
956
+				2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */,
957
+			);
958
+			runOnlyForDeploymentPostprocessing = 0;
959
+		};
960
+		2D02E48C1E0B4A5D006451C7 /* Sources */ = {
961
+			isa = PBXSourcesBuildPhase;
962
+			buildActionMask = 2147483647;
963
+			files = (
964
+				2DCD954D1E0B4F2C00145EB5 /* ExampleTests.m in Sources */,
965
+			);
966
+			runOnlyForDeploymentPostprocessing = 0;
967
+		};
590 968
 /* End PBXSourcesBuildPhase section */
591 969
 
592 970
 /* Begin PBXTargetDependency section */
@@ -595,6 +973,11 @@
595 973
 			target = 13B07F861A680F5B00A75B9A /* Example */;
596 974
 			targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */;
597 975
 		};
976
+		2D02E4921E0B4A5D006451C7 /* PBXTargetDependency */ = {
977
+			isa = PBXTargetDependency;
978
+			target = 2D02E47A1E0B4A5D006451C7 /* Example-tvOS */;
979
+			targetProxy = 2D02E4911E0B4A5D006451C7 /* PBXContainerItemProxy */;
980
+		};
598 981
 /* End PBXTargetDependency section */
599 982
 
600 983
 /* Begin PBXVariantGroup section */
@@ -619,12 +1002,16 @@
619 1002
 					"$(inherited)",
620 1003
 				);
621 1004
 				INFOPLIST_FILE = ExampleTests/Info.plist;
622
-				IPHONEOS_DEPLOYMENT_TARGET = 8.2;
1005
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
623 1006
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
624 1007
 				LIBRARY_SEARCH_PATHS = (
625 1008
 					"$(inherited)",
626 1009
 					"\"$(SRCROOT)/$(TARGET_NAME)\"",
627 1010
 				);
1011
+				OTHER_LDFLAGS = (
1012
+					"-ObjC",
1013
+					"-lc++",
1014
+				);
628 1015
 				PRODUCT_NAME = "$(TARGET_NAME)";
629 1016
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Example.app/Example";
630 1017
 			};
@@ -636,12 +1023,16 @@
636 1023
 				BUNDLE_LOADER = "$(TEST_HOST)";
637 1024
 				COPY_PHASE_STRIP = NO;
638 1025
 				INFOPLIST_FILE = ExampleTests/Info.plist;
639
-				IPHONEOS_DEPLOYMENT_TARGET = 8.2;
1026
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
640 1027
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
641 1028
 				LIBRARY_SEARCH_PATHS = (
642 1029
 					"$(inherited)",
643 1030
 					"\"$(SRCROOT)/$(TARGET_NAME)\"",
644 1031
 				);
1032
+				OTHER_LDFLAGS = (
1033
+					"-ObjC",
1034
+					"-lc++",
1035
+				);
645 1036
 				PRODUCT_NAME = "$(TARGET_NAME)";
646 1037
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Example.app/Example";
647 1038
 			};
@@ -651,15 +1042,9 @@
651 1042
 			isa = XCBuildConfiguration;
652 1043
 			buildSettings = {
653 1044
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
1045
+				CURRENT_PROJECT_VERSION = 1;
654 1046
 				DEAD_CODE_STRIPPING = NO;
655
-				HEADER_SEARCH_PATHS = (
656
-					"$(inherited)",
657
-					/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
658
-					"$(SRCROOT)/../node_modules/react-native/React/**",
659
-					"$(SRCROOT)/../node_modules/react-native-permissions/**",
660
-				);
661 1047
 				INFOPLIST_FILE = Example/Info.plist;
662
-				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
663 1048
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
664 1049
 				OTHER_LDFLAGS = (
665 1050
 					"$(inherited)",
@@ -667,6 +1052,7 @@
667 1052
 					"-lc++",
668 1053
 				);
669 1054
 				PRODUCT_NAME = Example;
1055
+				VERSIONING_SYSTEM = "apple-generic";
670 1056
 			};
671 1057
 			name = Debug;
672 1058
 		};
@@ -674,14 +1060,8 @@
674 1060
 			isa = XCBuildConfiguration;
675 1061
 			buildSettings = {
676 1062
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
677
-				HEADER_SEARCH_PATHS = (
678
-					"$(inherited)",
679
-					/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
680
-					"$(SRCROOT)/../node_modules/react-native/React/**",
681
-					"$(SRCROOT)/../node_modules/react-native-permissions/**",
682
-				);
1063
+				CURRENT_PROJECT_VERSION = 1;
683 1064
 				INFOPLIST_FILE = Example/Info.plist;
684
-				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
685 1065
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
686 1066
 				OTHER_LDFLAGS = (
687 1067
 					"$(inherited)",
@@ -689,6 +1069,117 @@
689 1069
 					"-lc++",
690 1070
 				);
691 1071
 				PRODUCT_NAME = Example;
1072
+				VERSIONING_SYSTEM = "apple-generic";
1073
+			};
1074
+			name = Release;
1075
+		};
1076
+		2D02E4971E0B4A5E006451C7 /* Debug */ = {
1077
+			isa = XCBuildConfiguration;
1078
+			buildSettings = {
1079
+				ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
1080
+				ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
1081
+				CLANG_ANALYZER_NONNULL = YES;
1082
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
1083
+				CLANG_WARN_INFINITE_RECURSION = YES;
1084
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
1085
+				DEBUG_INFORMATION_FORMAT = dwarf;
1086
+				ENABLE_TESTABILITY = YES;
1087
+				GCC_NO_COMMON_BLOCKS = YES;
1088
+				INFOPLIST_FILE = "Example-tvOS/Info.plist";
1089
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
1090
+				LIBRARY_SEARCH_PATHS = (
1091
+					"$(inherited)",
1092
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
1093
+				);
1094
+				OTHER_LDFLAGS = (
1095
+					"-ObjC",
1096
+					"-lc++",
1097
+				);
1098
+				PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.Example-tvOS";
1099
+				PRODUCT_NAME = "$(TARGET_NAME)";
1100
+				SDKROOT = appletvos;
1101
+				TARGETED_DEVICE_FAMILY = 3;
1102
+				TVOS_DEPLOYMENT_TARGET = 9.2;
1103
+			};
1104
+			name = Debug;
1105
+		};
1106
+		2D02E4981E0B4A5E006451C7 /* Release */ = {
1107
+			isa = XCBuildConfiguration;
1108
+			buildSettings = {
1109
+				ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
1110
+				ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
1111
+				CLANG_ANALYZER_NONNULL = YES;
1112
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
1113
+				CLANG_WARN_INFINITE_RECURSION = YES;
1114
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
1115
+				COPY_PHASE_STRIP = NO;
1116
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
1117
+				GCC_NO_COMMON_BLOCKS = YES;
1118
+				INFOPLIST_FILE = "Example-tvOS/Info.plist";
1119
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
1120
+				LIBRARY_SEARCH_PATHS = (
1121
+					"$(inherited)",
1122
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
1123
+				);
1124
+				OTHER_LDFLAGS = (
1125
+					"-ObjC",
1126
+					"-lc++",
1127
+				);
1128
+				PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.Example-tvOS";
1129
+				PRODUCT_NAME = "$(TARGET_NAME)";
1130
+				SDKROOT = appletvos;
1131
+				TARGETED_DEVICE_FAMILY = 3;
1132
+				TVOS_DEPLOYMENT_TARGET = 9.2;
1133
+			};
1134
+			name = Release;
1135
+		};
1136
+		2D02E4991E0B4A5E006451C7 /* Debug */ = {
1137
+			isa = XCBuildConfiguration;
1138
+			buildSettings = {
1139
+				BUNDLE_LOADER = "$(TEST_HOST)";
1140
+				CLANG_ANALYZER_NONNULL = YES;
1141
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
1142
+				CLANG_WARN_INFINITE_RECURSION = YES;
1143
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
1144
+				DEBUG_INFORMATION_FORMAT = dwarf;
1145
+				ENABLE_TESTABILITY = YES;
1146
+				GCC_NO_COMMON_BLOCKS = YES;
1147
+				INFOPLIST_FILE = "Example-tvOSTests/Info.plist";
1148
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
1149
+				LIBRARY_SEARCH_PATHS = (
1150
+					"$(inherited)",
1151
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
1152
+				);
1153
+				PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.Example-tvOSTests";
1154
+				PRODUCT_NAME = "$(TARGET_NAME)";
1155
+				SDKROOT = appletvos;
1156
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Example-tvOS.app/Example-tvOS";
1157
+				TVOS_DEPLOYMENT_TARGET = 10.1;
1158
+			};
1159
+			name = Debug;
1160
+		};
1161
+		2D02E49A1E0B4A5E006451C7 /* Release */ = {
1162
+			isa = XCBuildConfiguration;
1163
+			buildSettings = {
1164
+				BUNDLE_LOADER = "$(TEST_HOST)";
1165
+				CLANG_ANALYZER_NONNULL = YES;
1166
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
1167
+				CLANG_WARN_INFINITE_RECURSION = YES;
1168
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
1169
+				COPY_PHASE_STRIP = NO;
1170
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
1171
+				GCC_NO_COMMON_BLOCKS = YES;
1172
+				INFOPLIST_FILE = "Example-tvOSTests/Info.plist";
1173
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
1174
+				LIBRARY_SEARCH_PATHS = (
1175
+					"$(inherited)",
1176
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
1177
+				);
1178
+				PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.Example-tvOSTests";
1179
+				PRODUCT_NAME = "$(TARGET_NAME)";
1180
+				SDKROOT = appletvos;
1181
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Example-tvOS.app/Example-tvOS";
1182
+				TVOS_DEPLOYMENT_TARGET = 10.1;
692 1183
 			};
693 1184
 			name = Release;
694 1185
 		};
@@ -726,13 +1217,7 @@
726 1217
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
727 1218
 				GCC_WARN_UNUSED_FUNCTION = YES;
728 1219
 				GCC_WARN_UNUSED_VARIABLE = YES;
729
-				HEADER_SEARCH_PATHS = (
730
-					"$(inherited)",
731
-					/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
732
-					"$(SRCROOT)/../node_modules/react-native/React/**",
733
-					"$(SRCROOT)/../node_modules/react-native-permissions/**",
734
-				);
735
-				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
1220
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
736 1221
 				MTL_ENABLE_DEBUG_INFO = YES;
737 1222
 				ONLY_ACTIVE_ARCH = YES;
738 1223
 				SDKROOT = iphoneos;
@@ -767,13 +1252,7 @@
767 1252
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
768 1253
 				GCC_WARN_UNUSED_FUNCTION = YES;
769 1254
 				GCC_WARN_UNUSED_VARIABLE = YES;
770
-				HEADER_SEARCH_PATHS = (
771
-					"$(inherited)",
772
-					/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
773
-					"$(SRCROOT)/../node_modules/react-native/React/**",
774
-					"$(SRCROOT)/../node_modules/react-native-permissions/**",
775
-				);
776
-				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
1255
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
777 1256
 				MTL_ENABLE_DEBUG_INFO = NO;
778 1257
 				SDKROOT = iphoneos;
779 1258
 				VALIDATE_PRODUCT = YES;
@@ -801,6 +1280,24 @@
801 1280
 			defaultConfigurationIsVisible = 0;
802 1281
 			defaultConfigurationName = Release;
803 1282
 		};
1283
+		2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "Example-tvOS" */ = {
1284
+			isa = XCConfigurationList;
1285
+			buildConfigurations = (
1286
+				2D02E4971E0B4A5E006451C7 /* Debug */,
1287
+				2D02E4981E0B4A5E006451C7 /* Release */,
1288
+			);
1289
+			defaultConfigurationIsVisible = 0;
1290
+			defaultConfigurationName = Release;
1291
+		};
1292
+		2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "Example-tvOSTests" */ = {
1293
+			isa = XCConfigurationList;
1294
+			buildConfigurations = (
1295
+				2D02E4991E0B4A5E006451C7 /* Debug */,
1296
+				2D02E49A1E0B4A5E006451C7 /* Release */,
1297
+			);
1298
+			defaultConfigurationIsVisible = 0;
1299
+			defaultConfigurationName = Release;
1300
+		};
804 1301
 		83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Example" */ = {
805 1302
 			isa = XCConfigurationList;
806 1303
 			buildConfigurations = (

+ 129
- 0
Example/ios/Example.xcodeproj/xcshareddata/xcschemes/Example-tvOS.xcscheme View File

@@ -0,0 +1,129 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<Scheme
3
+   LastUpgradeVersion = "0820"
4
+   version = "1.3">
5
+   <BuildAction
6
+      parallelizeBuildables = "NO"
7
+      buildImplicitDependencies = "YES">
8
+      <BuildActionEntries>
9
+         <BuildActionEntry
10
+            buildForTesting = "YES"
11
+            buildForRunning = "YES"
12
+            buildForProfiling = "YES"
13
+            buildForArchiving = "YES"
14
+            buildForAnalyzing = "YES">
15
+            <BuildableReference
16
+               BuildableIdentifier = "primary"
17
+               BlueprintIdentifier = "2D2A28121D9B038B00D4039D"
18
+               BuildableName = "libReact.a"
19
+               BlueprintName = "React-tvOS"
20
+               ReferencedContainer = "container:../node_modules/react-native/React/React.xcodeproj">
21
+            </BuildableReference>
22
+         </BuildActionEntry>
23
+         <BuildActionEntry
24
+            buildForTesting = "YES"
25
+            buildForRunning = "YES"
26
+            buildForProfiling = "YES"
27
+            buildForArchiving = "YES"
28
+            buildForAnalyzing = "YES">
29
+            <BuildableReference
30
+               BuildableIdentifier = "primary"
31
+               BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
32
+               BuildableName = "Example-tvOS.app"
33
+               BlueprintName = "Example-tvOS"
34
+               ReferencedContainer = "container:Example.xcodeproj">
35
+            </BuildableReference>
36
+         </BuildActionEntry>
37
+         <BuildActionEntry
38
+            buildForTesting = "YES"
39
+            buildForRunning = "YES"
40
+            buildForProfiling = "NO"
41
+            buildForArchiving = "NO"
42
+            buildForAnalyzing = "YES">
43
+            <BuildableReference
44
+               BuildableIdentifier = "primary"
45
+               BlueprintIdentifier = "2D02E48F1E0B4A5D006451C7"
46
+               BuildableName = "Example-tvOSTests.xctest"
47
+               BlueprintName = "Example-tvOSTests"
48
+               ReferencedContainer = "container:Example.xcodeproj">
49
+            </BuildableReference>
50
+         </BuildActionEntry>
51
+      </BuildActionEntries>
52
+   </BuildAction>
53
+   <TestAction
54
+      buildConfiguration = "Debug"
55
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
56
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
57
+      shouldUseLaunchSchemeArgsEnv = "YES">
58
+      <Testables>
59
+         <TestableReference
60
+            skipped = "NO">
61
+            <BuildableReference
62
+               BuildableIdentifier = "primary"
63
+               BlueprintIdentifier = "2D02E48F1E0B4A5D006451C7"
64
+               BuildableName = "Example-tvOSTests.xctest"
65
+               BlueprintName = "Example-tvOSTests"
66
+               ReferencedContainer = "container:Example.xcodeproj">
67
+            </BuildableReference>
68
+         </TestableReference>
69
+      </Testables>
70
+      <MacroExpansion>
71
+         <BuildableReference
72
+            BuildableIdentifier = "primary"
73
+            BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
74
+            BuildableName = "Example-tvOS.app"
75
+            BlueprintName = "Example-tvOS"
76
+            ReferencedContainer = "container:Example.xcodeproj">
77
+         </BuildableReference>
78
+      </MacroExpansion>
79
+      <AdditionalOptions>
80
+      </AdditionalOptions>
81
+   </TestAction>
82
+   <LaunchAction
83
+      buildConfiguration = "Debug"
84
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
85
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
86
+      launchStyle = "0"
87
+      useCustomWorkingDirectory = "NO"
88
+      ignoresPersistentStateOnLaunch = "NO"
89
+      debugDocumentVersioning = "YES"
90
+      debugServiceExtension = "internal"
91
+      allowLocationSimulation = "YES">
92
+      <BuildableProductRunnable
93
+         runnableDebuggingMode = "0">
94
+         <BuildableReference
95
+            BuildableIdentifier = "primary"
96
+            BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
97
+            BuildableName = "Example-tvOS.app"
98
+            BlueprintName = "Example-tvOS"
99
+            ReferencedContainer = "container:Example.xcodeproj">
100
+         </BuildableReference>
101
+      </BuildableProductRunnable>
102
+      <AdditionalOptions>
103
+      </AdditionalOptions>
104
+   </LaunchAction>
105
+   <ProfileAction
106
+      buildConfiguration = "Release"
107
+      shouldUseLaunchSchemeArgsEnv = "YES"
108
+      savedToolIdentifier = ""
109
+      useCustomWorkingDirectory = "NO"
110
+      debugDocumentVersioning = "YES">
111
+      <BuildableProductRunnable
112
+         runnableDebuggingMode = "0">
113
+         <BuildableReference
114
+            BuildableIdentifier = "primary"
115
+            BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
116
+            BuildableName = "Example-tvOS.app"
117
+            BlueprintName = "Example-tvOS"
118
+            ReferencedContainer = "container:Example.xcodeproj">
119
+         </BuildableReference>
120
+      </BuildableProductRunnable>
121
+   </ProfileAction>
122
+   <AnalyzeAction
123
+      buildConfiguration = "Debug">
124
+   </AnalyzeAction>
125
+   <ArchiveAction
126
+      buildConfiguration = "Release"
127
+      revealArchiveInOrganizer = "YES">
128
+   </ArchiveAction>
129
+</Scheme>

+ 23
- 6
Example/ios/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme View File

@@ -1,11 +1,25 @@
1 1
 <?xml version="1.0" encoding="UTF-8"?>
2 2
 <Scheme
3
-   LastUpgradeVersion = "0620"
3
+   LastUpgradeVersion = "0820"
4 4
    version = "1.3">
5 5
    <BuildAction
6
-      parallelizeBuildables = "YES"
6
+      parallelizeBuildables = "NO"
7 7
       buildImplicitDependencies = "YES">
8 8
       <BuildActionEntries>
9
+         <BuildActionEntry
10
+            buildForTesting = "YES"
11
+            buildForRunning = "YES"
12
+            buildForProfiling = "YES"
13
+            buildForArchiving = "YES"
14
+            buildForAnalyzing = "YES">
15
+            <BuildableReference
16
+               BuildableIdentifier = "primary"
17
+               BlueprintIdentifier = "83CBBA2D1A601D0E00E9B192"
18
+               BuildableName = "libReact.a"
19
+               BlueprintName = "React"
20
+               ReferencedContainer = "container:../node_modules/react-native/React/React.xcodeproj">
21
+            </BuildableReference>
22
+         </BuildActionEntry>
9 23
          <BuildActionEntry
10 24
             buildForTesting = "YES"
11 25
             buildForRunning = "YES"
@@ -37,10 +51,10 @@
37 51
       </BuildActionEntries>
38 52
    </BuildAction>
39 53
    <TestAction
54
+      buildConfiguration = "Debug"
40 55
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
41 56
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
42
-      shouldUseLaunchSchemeArgsEnv = "YES"
43
-      buildConfiguration = "Debug">
57
+      shouldUseLaunchSchemeArgsEnv = "YES">
44 58
       <Testables>
45 59
          <TestableReference
46 60
             skipped = "NO">
@@ -62,15 +76,18 @@
62 76
             ReferencedContainer = "container:Example.xcodeproj">
63 77
          </BuildableReference>
64 78
       </MacroExpansion>
79
+      <AdditionalOptions>
80
+      </AdditionalOptions>
65 81
    </TestAction>
66 82
    <LaunchAction
83
+      buildConfiguration = "Debug"
67 84
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
68 85
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
69 86
       launchStyle = "0"
70 87
       useCustomWorkingDirectory = "NO"
71
-      buildConfiguration = "Debug"
72 88
       ignoresPersistentStateOnLaunch = "NO"
73 89
       debugDocumentVersioning = "YES"
90
+      debugServiceExtension = "internal"
74 91
       allowLocationSimulation = "YES">
75 92
       <BuildableProductRunnable
76 93
          runnableDebuggingMode = "0">
@@ -86,10 +103,10 @@
86 103
       </AdditionalOptions>
87 104
    </LaunchAction>
88 105
    <ProfileAction
106
+      buildConfiguration = "Release"
89 107
       shouldUseLaunchSchemeArgsEnv = "YES"
90 108
       savedToolIdentifier = ""
91 109
       useCustomWorkingDirectory = "NO"
92
-      buildConfiguration = "Release"
93 110
       debugDocumentVersioning = "YES">
94 111
       <BuildableProductRunnable
95 112
          runnableDebuggingMode = "0">

+ 2
- 2
Example/ios/Example/AppDelegate.m View File

@@ -9,8 +9,8 @@
9 9
 
10 10
 #import "AppDelegate.h"
11 11
 
12
-#import "RCTBundleURLProvider.h"
13
-#import "RCTRootView.h"
12
+#import <React/RCTBundleURLProvider.h>
13
+#import <React/RCTRootView.h>
14 14
 
15 15
 @implementation AppDelegate
16 16
 

+ 20
- 4
Example/ios/Example/Info.plist View File

@@ -8,8 +8,6 @@
8 8
 	<string>$(EXECUTABLE_NAME)</string>
9 9
 	<key>CFBundleIdentifier</key>
10 10
 	<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string>
11
-	<key>CFBundleInfoDictionaryVersion</key>
12
-	<string>6.0</string>
13 11
 	<key>CFBundleName</key>
14 12
 	<string>$(PRODUCT_NAME)</string>
15 13
 	<key>CFBundlePackageType</key>
@@ -28,13 +26,31 @@
28 26
 		<dict>
29 27
 			<key>localhost</key>
30 28
 			<dict>
31
-				<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
29
+				<key>NSExceptionAllowsInsecureHTTPLoads</key>
32 30
 				<true/>
33 31
 			</dict>
34 32
 		</dict>
35 33
 	</dict>
34
+	<key>NSAppleMusicUsageDescription</key>
35
+	<string>test</string>
36
+	<key>NSBluetoothPeripheralUsageDescription</key>
37
+	<string>test</string>
38
+	<key>NSCalendarsUsageDescription</key>
39
+	<string>test</string>
40
+	<key>NSCameraUsageDescription</key>
41
+	<string>test</string>
42
+	<key>NSContactsUsageDescription</key>
43
+	<string>test</string>
44
+	<key>NSLocationAlwaysUsageDescription</key>
45
+	<string>test</string>
36 46
 	<key>NSLocationWhenInUseUsageDescription</key>
37
-	<string>We need your location</string>
47
+	<string>test</string>
48
+	<key>NSMicrophoneUsageDescription</key>
49
+	<string>6.0</string>
50
+	<key>NSPhotoLibraryUsageDescription</key>
51
+	<string>test</string>
52
+	<key>NSRemindersUsageDescription</key>
53
+	<string>test</string>
38 54
 	<key>UIBackgroundModes</key>
39 55
 	<array>
40 56
 		<string>bluetooth-peripheral</string>

+ 1
- 1
Example/ios/Example/main.m View File

@@ -1,4 +1,4 @@
1
-  /**
1
+/**
2 2
  * Copyright (c) 2015-present, Facebook, Inc.
3 3
  * All rights reserved.
4 4
  *

+ 2
- 2
Example/ios/ExampleTests/ExampleTests.m View File

@@ -10,8 +10,8 @@
10 10
 #import <UIKit/UIKit.h>
11 11
 #import <XCTest/XCTest.h>
12 12
 
13
-#import "RCTLog.h"
14
-#import "RCTRootView.h"
13
+#import <React/RCTLog.h>
14
+#import <React/RCTRootView.h>
15 15
 
16 16
 #define TIMEOUT_SECONDS 600
17 17
 #define TEXT_TO_LOOK_FOR @"Welcome to React Native!"

+ 21
- 11
Example/package.json View File

@@ -1,13 +1,23 @@
1 1
 {
2
-  "name": "Example",
3
-  "version": "0.0.1",
4
-  "private": true,
5
-  "scripts": {
6
-    "start": "react-native start"
7
-  },
8
-  "dependencies": {
9
-    "react": "15.2.1",
10
-    "react-native": "^0.30.0",
2
+	"name": "Example",
3
+	"version": "0.0.1",
4
+	"private": true,
5
+	"scripts": {
6
+		"start": "react-native start",
7
+		"test": "jest"
8
+	},
9
+	"dependencies": {
10
+		"react": "15.4.2",
11
+		"react-native": "^0.41.0",
11 12
     "react-native-permissions": "../"
12
-  }
13
-}
13
+	},
14
+	"devDependencies": {
15
+		"babel-jest": "18.0.0",
16
+		"babel-preset-react-native": "1.9.1",
17
+		"jest": "18.1.0",
18
+		"react-test-renderer": "15.4.2"
19
+	},
20
+	"jest": {
21
+		"preset": "react-native"
22
+	}
23
+}

+ 7
- 2
RCTConvert+RNPStatus.h View File

@@ -6,7 +6,11 @@
6 6
 //  Copyright © 2016 Yonah Forst. All rights reserved.
7 7
 //
8 8
 
9
-#import "RCTConvert.h"
9
+#if __has_include("RCTConvert.h")
10
+  #import "RCTConvert.h"
11
+#else
12
+  #import <React/RCTConvert.h>
13
+#endif
10 14
 
11 15
 static NSString* RNPStatusUndetermined = @"undetermined";
12 16
 static NSString* RNPStatusDenied = @"denied";
@@ -25,7 +29,8 @@ typedef NS_ENUM(NSInteger, RNPType) {
25 29
     RNPTypeReminder,
26 30
     RNPTypeBluetooth,
27 31
     RNPTypeNotification,
28
-    RNPTypeBackgroundRefresh
32
+    RNPTypeBackgroundRefresh,
33
+    RNPTypeSpeechRecognition
29 34
 };
30 35
 
31 36
 @interface RCTConvert (RNPStatus)

+ 2
- 1
RCTConvert+RNPStatus.m View File

@@ -20,7 +20,8 @@ RCT_ENUM_CONVERTER(RNPType, (@{ @"location" : @(RNPTypeLocation),
20 20
                                 @"reminder" : @(RNPTypeReminder),
21 21
                                 @"bluetooth" : @(RNPTypeBluetooth),
22 22
                                 @"notification" : @(RNPTypeNotification),
23
-                                @"backgroundRefresh": @(RNPTypeBackgroundRefresh)
23
+                                @"backgroundRefresh": @(RNPTypeBackgroundRefresh),
24
+                                @"speechRecognition": @(RNPTypeSpeechRecognition)
24 25
                                 }),
25 26
                                 RNPTypeUnknown, integerValue)
26 27
 

+ 104
- 36
README.md View File

@@ -4,7 +4,7 @@ Request user permissions from React Native, iOS + Android
4 4
 The current supported permissions are:
5 5
 - Location
6 6
 - Camera
7
-- Microhone
7
+- Microphone
8 8
 - Photos
9 9
 - Contacts
10 10
 - Events
@@ -12,13 +12,23 @@ The current supported permissions are:
12 12
 - Bluetooth *(iOS only)*
13 13
 - Push Notifications *(iOS only)*
14 14
 - Background Refresh *(iOS only)*
15
+- Speech Recognition *(iOS only)*
15 16
 
16 17
 
17
-###New in version 0.2.X
18
-- Android support 🎉🎉🍾
19
-- Example app
18
+| Version | React Native Support |
19
+|---|---|
20
+| 0.2.7 | 0.40.0 - 0.41.0 |
21
+| 0.2.5 | 0.33.0 - 0.39.0 |
22
+*Complies with [react-native-version-support-table](https://github.com/dangnelson/react-native-version-support-table)*
23
+
24
+## General Usage
25
+```
26
+npm install --save react-native-permissions
27
+rnpm link
28
+```
29
+
30
+Add permissions to manifest for android and info.plist for ios (xcode >=8). See notes below for more details.
20 31
 
21
-##General Usage
22 32
 ```js
23 33
 const Permissions = require('react-native-permissions');
24 34
 
@@ -47,7 +57,7 @@ const Permissions = require('react-native-permissions');
47 57
     Permissions.checkMultiplePermissions(['camera', 'photo'])
48 58
       .then(response => {
49 59
         //response is an object mapping type to permission
50
-        this.setState({ 
60
+        this.setState({
51 61
           cameraPermission: response.camera,
52 62
           photoPermission: response.photo,
53 63
         })
@@ -55,7 +65,7 @@ const Permissions = require('react-native-permissions');
55 65
   }
56 66
 
57 67
   // this is a common pattern when asking for permissions.
58
-  // iOS only gives you once chance to show the permission dialog, 
68
+  // iOS only gives you once chance to show the permission dialog,
59 69
   // after which the user needs to manually enable them from settings.
60 70
   // the idea here is to explain why we need access and determine if
61 71
   // the user will say no, so that we don't blow our one chance.
@@ -66,7 +76,7 @@ const Permissions = require('react-native-permissions');
66 76
       'We need access so you can set your profile pic',
67 77
       [
68 78
         {text: 'No way', onPress: () => console.log('permission denied'), style: 'cancel'},
69
-        this.state.photoPermission == 'undetermined'? 
79
+        this.state.photoPermission == 'undetermined'?
70 80
           {text: 'OK', onPress: this._requestPermission.bind(this)}
71 81
           : {text: 'Open Settings', onPress: Permissions.openSettings}
72 82
       ]
@@ -75,19 +85,19 @@ const Permissions = require('react-native-permissions');
75 85
 //...
76 86
 ```
77 87
 
78
-##API
88
+## API
79 89
 
80
-###Permission statuses
90
+### Permission statuses
81 91
 Promises resolve into one of these statuses
82 92
 
83 93
 | Return value | Notes|
84 94
 |---|---|
85 95
 |`authorized`| user has authorized this permission |
86
-|`denied`| user has denied permissions 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'|
87
-|`restricted`| iOS only|
96
+|`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'|
97
+|`restricted`| *(iOS only)* user is not able to grant this permission, either because it's not supported by the device or because it has been blocked by parental controls. |
88 98
 |`undetermined`| user has not yet been prompted with a permission dialog |
89 99
 
90
-###Supported permission types
100
+### Supported permission types
91 101
 
92 102
 | Name | iOS | Android |
93 103
 |---|---|---|
@@ -101,25 +111,33 @@ Promises resolve into one of these statuses
101 111
 |`reminder`| ✔️ | ❌ |
102 112
 |`notification`| ✔️ | ❌ |
103 113
 |`backgroundRefresh`| ✔️ | ❌ |
114
+|`speechRecognition`| ✔️ | ❌ |
115
+|`storage`| ❌️ | ✔ |
104 116
 
105
-###Methods
117
+### Methods
106 118
 | Method Name | Arguments | Notes
107 119
 |---|---|---|
108
-| `getPermissionStatus` | `type` | - Returns a promise with the permission status. Note: for type `location`, iOS `AuthorizedAlways` and `AuthorizedWhenInUse` both return `authorized` |
109
-| `requestPermission` | `type` | - Accepts any permission type except `backgroundRefresh`. If the current status is `undetermined`, shows the permission dialog and returns a promise with the resulting status. Otherwise, immediately return a promise with the current status. Note: see below for special cases|
120
+| `getPermissionStatus` | `type` | - Returns a promise with the permission status. See iOS Notes for special cases |
121
+| `requestPermission` | `type` | - Accepts any permission type except `backgroundRefresh`. If the current status is `undetermined`, shows the permission dialog and returns a promise with the resulting status. Otherwise, immediately return a promise with the current status. See iOS Notes for special cases|
110 122
 | `checkMultiplePermissions` | `[types]` | - Accepts an array of permission types and returns a promise with an object mapping permission types to statuses |
111 123
 | `getPermissionTypes` | *none* | - Returns an array of valid permission types  |
112 124
 | `openSettings` | *none* | - Switches the user to the settings page of your app (iOS 8.0 and later)  |
113 125
 | `canOpenSettings` | *none* | - Returns a boolean indicating if the device supports switching to the settings page |
114 126
 
115
-###iOS Notes
127
+### iOS Notes
116 128
 Permission type `bluetooth` represents the status of the `CBPeripheralManager`. Don't use this if only need `CBCentralManager`
117 129
 
118
-`requestPermission` also accepts a second parameter for types `location` and `notification`.
119
-- `location`: the second parameter is a string, either `always` or `whenInUse`(default).
120
-- `notification`: the second parameter is an array with the desired alert types. Any combination of `alert`, `badge` and `sound` (default requests all three)
130
+Permission type `location` accepts a second parameter for `requestPermission` and `getPermissionStatus`;  the second parameter is a string, either `always` or `whenInUse`(default).
131
+
132
+Permission type `notification` accepts a second parameter for `requestPermission`. The second parameter is an array with the desired alert types. Any combination of `alert`, `badge` and `sound` (default requests all three)
133
+
121 134
 ```js
122 135
 ///example
136
+    Permissions.getPermissionStatus('location', 'always')
137
+      .then(response => {
138
+        this.setState({ locationPermission: response })
139
+      })
140
+
123 141
     Permissions.requestPermission('location', 'always')
124 142
       .then(response => {
125 143
         this.setState({ locationPermission: response })
@@ -131,37 +149,50 @@ Permission type `bluetooth` represents the status of the `CBPeripheralManager`.
131 149
       })
132 150
 ```
133 151
 
134
-###Android Notes
152
+You cannot request microphone permissions on the simulator.
153
+
154
+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.
155
+
156
+Example:
157
+If you need Contacts permission you have to add the key "Privacy - Contacts Usage Description".
158
+<img width="338" alt="3cde3b44-7ffd-11e6-918b-63888e33f983" src="https://cloud.githubusercontent.com/assets/1440796/18713019/271be540-8011-11e6-87fb-c3828c172dfc.png">
159
+
160
+### Android Notes
161
+
162
+Requires RN >= 0.29.0
163
+
135 164
 All required permissions also need to be included in the Manifest before they can be requested. Otherwise `requestPermission` will immediately return `denied`.
136 165
 
137 166
 Permissions are automatically accepted for targetSdkVersion < 23 but you can still use `getPermissionStatus` to check if the user has disabled them from Settings.
138 167
 
139
-Here's a map of types to Android system permissions names:  
140
-`location` -> `android.permission.ACCESS_FINE_LOCATION`  
141
-`camera` -> `android.permission.CAMERA`  
142
-`microphone` -> `android.permission.RECORD_AUDIO`  
143
-`photo` -> `android.permission.READ_EXTERNAL_STORAGE`  
144
-`contacts` -> `android.permission.READ_CONTACTS`  
145
-`event` -> `android.permission.READ_CALENDAR`  
168
+Here's a map of types to Android system permissions names:
169
+`location` -> `android.permission.ACCESS_FINE_LOCATION`
170
+`camera` -> `android.permission.CAMERA`
171
+`microphone` -> `android.permission.RECORD_AUDIO`
172
+`photo` -> `android.permission.READ_EXTERNAL_STORAGE`
173
+`storage` -> `android.permission.READ_EXTERNAL_STORAGE`
174
+`contacts` -> `android.permission.READ_CONTACTS`
175
+`event` -> `android.permission.READ_CALENDAR`
176
+
146 177
 
147 178
 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
148 179
 
149
-##Setup
180
+## Setup
150 181
 
151 182
 ````
152 183
 npm install --save react-native-permissions
153 184
 rnpm link
154 185
 ````
155 186
 
156
-###Or manualy linking   
187
+### Or manualy linking
157 188
 
158
-####iOS
189
+#### iOS
159 190
 * Run open node_modules/react-native-permissions
160 191
 * Drag ReactNativePermissions.xcodeproj into the Libraries group of your app's Xcode project
161 192
 * Add libReactNativePermissions.a to `Build Phases -> Link Binary With Libraries.
162 193
 
163
-####Android
164
-#####Step 1 - Update Gradle Settings
194
+#### Android
195
+##### Step 1 - Update Gradle Settings
165 196
 
166 197
 ```
167 198
 // file: android/settings.gradle
@@ -170,7 +201,7 @@ rnpm link
170 201
 include ':react-native-permissions'
171 202
 project(':react-native-permissions').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-permissions/android')
172 203
 ```
173
-#####Step 2 - Update Gradle Build
204
+##### Step 2 - Update Gradle Build
174 205
 
175 206
 ```
176 207
 // file: android/app/build.gradle
@@ -181,7 +212,7 @@ dependencies {
181 212
     compile project(':react-native-permissions')
182 213
 }
183 214
 ```
184
-#####Step 3 - Register React Package
215
+##### Step 3 - Register React Package
185 216
 ```
186 217
 ...
187 218
 import com.joshblour.reactnativepermissions.ReactNativePermissionsPackage; // <--- import
@@ -200,4 +231,41 @@ public class MainApplication extends Application implements ReactApplication {
200 231
 
201 232
     ...
202 233
 }
203
-```
234
+```
235
+## AppStore submission disclaimer
236
+
237
+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**.
238
+
239
+So before submitting your app to the `AppStore`, make sure that in your `Info.plist` you have the following keys:
240
+
241
+```
242
+
243
+<key>NSBluetoothPeripheralUsageDescription</key>
244
+<string>Some description</string>
245
+<key>NSCalendarsUsageDescription</key>
246
+<string>Some description</string>
247
+<key>NSCameraUsageDescription</key>
248
+<string>Some description</string>
249
+<key>NSLocationWhenInUseUsageDescription</key>
250
+<string>Some description</string>
251
+<key>NSPhotoLibraryUsageDescription</key>
252
+<string>Some description</string>
253
+
254
+```
255
+
256
+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.
257
+
258
+> Please note that it will only be shown to the users the usage descriptions of the permissions you really require in your app.
259
+
260
+You can find more informations about this issue in #46.
261
+
262
+## Troubleshooting
263
+
264
+#### Q: Android - `undefined is not a object (evaluating 'RNPermissions.requestPermissions')`
265
+A: `rnpm` may not have linked correctly. Follow the manual linking steps and make sure the library is linked
266
+
267
+#### Q: iOS - app crashes as soon as I request permission
268
+A: starting with xcode 8, you need to add permission descriptions. see iOS notes for more details. Thanks to @jesperlndk for discovering this.
269
+
270
+#### Q: iOS - app crashes when I change permissions from settings
271
+A: This is normal. iOS restarts your app when your privacy settings change. Just google "ios crash permission change"

+ 5
- 2
ReactNativePermissions.h View File

@@ -5,9 +5,12 @@
5 5
 //  Created by Yonah Forst on 18/02/16.
6 6
 //  Copyright © 2016 Yonah Forst. All rights reserved.
7 7
 //
8
-#import "RCTBridgeModule.h"
9 8
 
10
-#import <Foundation/Foundation.h>
9
+#if __has_include("RCTBridgeModule.h")
10
+  #import "RCTBridgeModule.h"
11
+#else
12
+  #import <React/RCTBridgeModule.h>
13
+#endif
11 14
 
12 15
 @interface ReactNativePermissions : NSObject <RCTBridgeModule>
13 16
 

+ 9
- 4
ReactNativePermissions.js View File

@@ -16,6 +16,7 @@ const RNPTypes = {
16 16
 		'bluetooth',
17 17
 		'notification',
18 18
 		'backgroundRefresh',
19
+		'speechRecognition',
19 20
 	],
20 21
 	android: [
21 22
 		'location',
@@ -23,8 +24,9 @@ const RNPTypes = {
23 24
 		'microphone',
24 25
 		'contacts',
25 26
 		'event',
26
-		'photos',
27 27
 		'notification',
28
+		'photo',
29
+		'storage'
28 30
 	]
29 31
 }
30 32
 
@@ -58,9 +60,9 @@ class ReactNativePermissions {
58 60
 	}
59 61
 
60 62
 
61
-	getPermissionStatus(permission) {
63
+	getPermissionStatus(permission, type) {
62 64
   	if (this.getPermissionTypes().indexOf(permission) >= 0) {
63
-			return RNPermissions.getPermissionStatus(permission)
65
+			return RNPermissions.getPermissionStatus(permission, type)
64 66
 		} else {
65 67
 			return Promise.reject(`ReactNativePermissions: ${permission} is not a valid permission type on ${Platform.OS}`)
66 68
 		}
@@ -69,13 +71,16 @@ class ReactNativePermissions {
69 71
 	requestPermission(permission, type) {
70 72
 		let options;
71 73
 
72
-		if (!this.getPermissionTypes().includes(permission)) {
74
+		if (this.getPermissionTypes().indexOf(permission) === -1) {
73 75
 			return Promise.reject(`ReactNativePermissions: ${permission} is not a valid permission type on ${Platform.OS}`)
74 76
 		} else if (permission == 'backgroundRefresh'){
75 77
 			return Promise.reject('ReactNativePermissions: You cannot request backgroundRefresh')
76 78
 		} else if (permission == 'location') {
77 79
 			options = type || 'whenInUse'
78 80
 		} else if (permission == 'notification') {
81
+			if (Platform.OS === 'android') {
82
+				return Promise.reject(`ReactNativePermissions: notification cannot be requested on Android`)
83
+			}
79 84
 			options = type || ['alert', 'badge', 'sound']
80 85
 		}
81 86
 

+ 41
- 8
ReactNativePermissions.m View File

@@ -10,9 +10,23 @@
10 10
 
11 11
 #import "ReactNativePermissions.h"
12 12
 
13
-#import "RCTBridge.h"
14
-#import "RCTConvert.h"
15
-#import "RCTEventDispatcher.h"
13
+#if __has_include("RCTBridge.h")
14
+  #import "RCTBridge.h"
15
+#else
16
+  #import <React/RCTBridge.h>
17
+#endif
18
+
19
+#if __has_include("RCTConvert.h")
20
+  #import "RCTConvert.h"
21
+#else
22
+  #import <React/RCTConvert.h>
23
+#endif
24
+
25
+#if __has_include("RCTEventDispatcher.h")
26
+  #import "RCTEventDispatcher.h"
27
+#else
28
+  #import <React/RCTEventDispatcher.h>
29
+#endif
16 30
 
17 31
 #import "RNPLocation.h"
18 32
 #import "RNPBluetooth.h"
@@ -22,6 +36,7 @@
22 36
 #import "RNPPhoto.h"
23 37
 #import "RNPContacts.h"
24 38
 #import "RNPBackgroundRefresh.h"
39
+#import "RNPSpeechRecognition.h"
25 40
 
26 41
 @interface ReactNativePermissions()
27 42
 @property (strong, nonatomic) RNPLocation *locationMgr;
@@ -58,23 +73,37 @@ RCT_REMAP_METHOD(canOpenSettings, canOpenSettings:(RCTPromiseResolveBlock)resolv
58 73
     resolve(@(UIApplicationOpenSettingsURLString != nil));
59 74
 }
60 75
 
61
-RCT_EXPORT_METHOD(openSettings)
76
+    
77
+RCT_EXPORT_METHOD(openSettings:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
62 78
 {
63 79
     if (@(UIApplicationOpenSettingsURLString != nil)) {
80
+        
81
+        NSNotificationCenter * __weak center = [NSNotificationCenter defaultCenter];
82
+        id __block token = [center addObserverForName:UIApplicationDidBecomeActiveNotification
83
+                                               object:nil
84
+                                                queue:nil
85
+                                           usingBlock:^(NSNotification *note) {
86
+                                               [center removeObserver:token];
87
+                                               resolve(@YES);
88
+                                           }];
89
+        
64 90
         NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
65 91
         [[UIApplication sharedApplication] openURL:url];
66 92
     }
67 93
 }
68 94
 
69
-RCT_REMAP_METHOD(getPermissionStatus, getPermissionStatus:(RNPType)type resolve:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
95
+
96
+RCT_REMAP_METHOD(getPermissionStatus, getPermissionStatus:(RNPType)type json:(id)json resolve:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
70 97
 {
71 98
     NSString *status;
72 99
     
73 100
     switch (type) {
74 101
             
75
-        case RNPTypeLocation:
76
-            status = [RNPLocation getStatus];
102
+        case RNPTypeLocation: {
103
+            NSString *locationPermissionType = [RCTConvert NSString:json];
104
+            status = [RNPLocation getStatusForType:locationPermissionType];
77 105
             break;
106
+        }
78 107
         case RNPTypeCamera:
79 108
             status = [RNPAudioVideo getStatus:@"video"];
80 109
             break;
@@ -102,6 +131,9 @@ RCT_REMAP_METHOD(getPermissionStatus, getPermissionStatus:(RNPType)type resolve:
102 131
         case RNPTypeBackgroundRefresh:
103 132
             status = [RNPBackgroundRefresh getStatus];
104 133
             break;
134
+        case RNPTypeSpeechRecognition:
135
+            status = [RNPSpeechRecognition getStatus];
136
+            break;
105 137
         default:
106 138
             break;
107 139
     }
@@ -132,6 +164,8 @@ RCT_REMAP_METHOD(requestPermission, permissionType:(RNPType)type json:(id)json r
132 164
             return [self requestBluetooth:resolve];
133 165
         case RNPTypeNotification:
134 166
             return [self requestNotification:json resolve:resolve];
167
+        case RNPTypeSpeechRecognition:
168
+            return [RNPSpeechRecognition request:resolve];
135 169
         default:
136 170
             break;
137 171
     }
@@ -139,7 +173,6 @@ RCT_REMAP_METHOD(requestPermission, permissionType:(RNPType)type json:(id)json r
139 173
 
140 174
 }
141 175
 
142
-
143 176
 - (void) requestLocation:(id)json resolve:(RCTPromiseResolveBlock)resolve
144 177
 {
145 178
     if (self.locationMgr == nil) {

+ 1
- 0
ReactNativePermissions.podspec View File

@@ -19,4 +19,5 @@ Pod::Spec.new do |s|
19 19
 
20 20
   s.preserve_paths      = 'docs', 'CHANGELOG.md', 'LICENSE', 'package.json', 'ReactNativePermissions.ios.js'
21 21
   s.source_files        = '**/*.{h,m}'
22
+  s.exclude_files       = 'Example/**/*'
22 23
 end

+ 7
- 1
ReactNativePermissions.xcodeproj/project.pbxproj View File

@@ -7,6 +7,7 @@
7 7
 	objects = {
8 8
 
9 9
 /* Begin PBXBuildFile section */
10
+		281CD5911E26B0C8003A72B2 /* RNPSpeechRecognition.m in Sources */ = {isa = PBXBuildFile; fileRef = 281CD5901E26B0C7003A72B2 /* RNPSpeechRecognition.m */; };
10 11
 		9D46283E1D34719100346A5B /* RNPAudioVideo.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D46282F1D34719100346A5B /* RNPAudioVideo.m */; };
11 12
 		9D46283F1D34719100346A5B /* RNPBackgroundRefresh.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D4628311D34719100346A5B /* RNPBackgroundRefresh.m */; };
12 13
 		9D4628401D34719100346A5B /* RNPBluetooth.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D4628331D34719100346A5B /* RNPBluetooth.m */; };
@@ -32,6 +33,8 @@
32 33
 /* End PBXCopyFilesBuildPhase section */
33 34
 
34 35
 /* Begin PBXFileReference section */
36
+		281CD5901E26B0C7003A72B2 /* RNPSpeechRecognition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNPSpeechRecognition.m; path = permissions/RNPSpeechRecognition.m; sourceTree = SOURCE_ROOT; };
37
+		281CD5921E26B266003A72B2 /* RNPSpeechRecognition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNPSpeechRecognition.h; path = permissions/RNPSpeechRecognition.h; sourceTree = SOURCE_ROOT; };
35 38
 		9D23B34F1C767B80008B4819 /* libReactNativePermissions.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libReactNativePermissions.a; sourceTree = BUILT_PRODUCTS_DIR; };
36 39
 		9D46282E1D34719100346A5B /* RNPAudioVideo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNPAudioVideo.h; path = permissions/RNPAudioVideo.h; sourceTree = SOURCE_ROOT; };
37 40
 		9D46282F1D34719100346A5B /* RNPAudioVideo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNPAudioVideo.m; path = permissions/RNPAudioVideo.m; sourceTree = SOURCE_ROOT; };
@@ -113,6 +116,8 @@
113 116
 				9D46283B1D34719100346A5B /* RNPNotification.m */,
114 117
 				9D46283C1D34719100346A5B /* RNPPhoto.h */,
115 118
 				9D46283D1D34719100346A5B /* RNPPhoto.m */,
119
+				281CD5921E26B266003A72B2 /* RNPSpeechRecognition.h */,
120
+				281CD5901E26B0C7003A72B2 /* RNPSpeechRecognition.m */,
116 121
 			);
117 122
 			name = permissions;
118 123
 			sourceTree = "<group>";
@@ -143,7 +148,7 @@
143 148
 		9D23B3471C767B80008B4819 /* Project object */ = {
144 149
 			isa = PBXProject;
145 150
 			attributes = {
146
-				LastUpgradeCheck = 0710;
151
+				LastUpgradeCheck = 0820;
147 152
 				ORGANIZATIONNAME = "Yonah Forst";
148 153
 				TargetAttributes = {
149 154
 					9D23B34E1C767B80008B4819 = {
@@ -175,6 +180,7 @@
175 180
 			files = (
176 181
 				9D46283F1D34719100346A5B /* RNPBackgroundRefresh.m in Sources */,
177 182
 				9D4628451D34719100346A5B /* RNPPhoto.m in Sources */,
183
+				281CD5911E26B0C8003A72B2 /* RNPSpeechRecognition.m in Sources */,
178 184
 				9D4628431D34719100346A5B /* RNPLocation.m in Sources */,
179 185
 				9D46283E1D34719100346A5B /* RNPAudioVideo.m in Sources */,
180 186
 				9D4628401D34719100346A5B /* RNPBluetooth.m in Sources */,

ReactNativePermissions.xcodeproj/xcuserdata/Yonah.xcuserdatad/xcschemes/ReactNativeHeading.xcscheme → ReactNativePermissions.xcodeproj/xcuserdata/Yonah.xcuserdatad/xcschemes/ReactNativePermissions.xcscheme View File


+ 4
- 4
android/build.gradle View File

@@ -11,12 +11,12 @@ buildscript {
11 11
 apply plugin: 'com.android.library'
12 12
 
13 13
 android {
14
-    compileSdkVersion 24
15
-    buildToolsVersion "24.0.1"
14
+    compileSdkVersion 23
15
+    buildToolsVersion "25.0.2"
16 16
 
17 17
     defaultConfig {
18
-        minSdkVersion 18
19
-        targetSdkVersion 24
18
+        minSdkVersion 16
19
+        targetSdkVersion 23
20 20
         versionCode 1
21 21
         versionName "1.0"
22 22
     }

+ 19
- 8
android/src/main/java/com/joshblour/reactnativepermissions/ReactNativePermissionsModule.java View File

@@ -11,6 +11,7 @@ import android.support.v4.content.PermissionChecker;
11 11
 
12 12
 import com.facebook.react.bridge.Callback;
13 13
 import com.facebook.react.bridge.Promise;
14
+import com.facebook.react.bridge.PromiseImpl;
14 15
 import com.facebook.react.bridge.ReactApplicationContext;
15 16
 import com.facebook.react.bridge.ReactContextBaseJavaModule;
16 17
 import com.facebook.react.bridge.ReactMethod;
@@ -18,6 +19,7 @@ import com.facebook.react.bridge.ReadableMap;
18 19
 import com.facebook.react.bridge.ReadableArray;
19 20
 import com.facebook.react.modules.permissions.PermissionsModule;
20 21
 
22
+import java.util.Locale;
21 23
 
22 24
 public class ReactNativePermissionsModule extends ReactContextBaseJavaModule {
23 25
   private final ReactApplicationContext reactContext;
@@ -31,7 +33,8 @@ public class ReactNativePermissionsModule extends ReactContextBaseJavaModule {
31 33
     MICROPHONE,
32 34
     CONTACTS,
33 35
     EVENT,
34
-    PHOTOS;
36
+    STORAGE,
37
+    PHOTO;
35 38
   }
36 39
 
37 40
   public ReactNativePermissionsModule(ReactApplicationContext reactContext) {
@@ -47,7 +50,7 @@ public class ReactNativePermissionsModule extends ReactContextBaseJavaModule {
47 50
   }
48 51
 
49 52
   @ReactMethod
50
-  public void getPermissionStatus(String permissionString, Promise promise) {
53
+  public void getPermissionStatus(String permissionString, String nullForiOSCompat, Promise promise) {
51 54
     String permission = permissionForString(permissionString);
52 55
 
53 56
     // check if permission is valid
@@ -92,13 +95,20 @@ public class ReactNativePermissionsModule extends ReactContextBaseJavaModule {
92 95
   @ReactMethod
93 96
   public void requestPermission(final String permissionString, String nullForiOSCompat, final Promise promise) {
94 97
     String permission = permissionForString(permissionString);
95
-    mPermissionsModule.requestPermission(permission, new Callback() {
98
+    Callback resolve = new Callback() {
96 99
       @Override
97 100
       public void invoke(Object... args) {
98
-        getPermissionStatus(permissionString, promise);
99
-//        promise.resolve((boolean)args[1] ? "authorized" : "denied");
101
+        getPermissionStatus(permissionString, "", promise);
100 102
       }
101
-    }, null);
103
+    };
104
+    Callback reject = new Callback() {
105
+      @Override
106
+      public void invoke(Object... args) {
107
+        // NOOP
108
+      }
109
+    };
110
+
111
+    mPermissionsModule.requestPermission(permission, new PromiseImpl(resolve, reject));
102 112
   }
103 113
 
104 114
 
@@ -120,7 +130,7 @@ public class ReactNativePermissionsModule extends ReactContextBaseJavaModule {
120 130
   }
121 131
 
122 132
   private String permissionForString(String permission) {
123
-    switch (RNType.valueOf(permission.toUpperCase())) {
133
+    switch (RNType.valueOf(permission.toUpperCase(Locale.ENGLISH))) {
124 134
       case LOCATION:
125 135
         return Manifest.permission.ACCESS_FINE_LOCATION;
126 136
       case CAMERA:
@@ -131,7 +141,8 @@ public class ReactNativePermissionsModule extends ReactContextBaseJavaModule {
131 141
         return Manifest.permission.READ_CONTACTS;
132 142
       case EVENT:
133 143
         return Manifest.permission.READ_CALENDAR;
134
-      case PHOTOS:
144
+      case STORAGE:
145
+      case PHOTO:
135 146
         return Manifest.permission.READ_EXTERNAL_STORAGE;
136 147
       default:
137 148
         return permission;

+ 1
- 1
package.json View File

@@ -1,6 +1,6 @@
1 1
 {
2 2
   "name": "react-native-permissions",
3
-  "version": "0.2.2",
3
+  "version": "0.3.0",
4 4
   "repository": {
5 5
     "type": "git",
6 6
     "url": "https://github.com/joshblour/react-native-permissions.git"

+ 1
- 1
permissions/RNPLocation.h View File

@@ -11,7 +11,7 @@
11 11
 
12 12
 @interface RNPLocation : NSObject
13 13
 
14
-+ (NSString *)getStatus;
14
++ (NSString *)getStatusForType:(NSString *)type;
15 15
 - (void)request:(NSString *)type completionHandler:(void (^)(NSString *))completionHandler;
16 16
 
17 17
 @end

+ 14
- 9
permissions/RNPLocation.m View File

@@ -17,13 +17,14 @@
17 17
 
18 18
 @implementation RNPLocation
19 19
 
20
-+ (NSString *)getStatus
20
++ (NSString *)getStatusForType:(NSString *)type
21 21
 {
22 22
     int status = [CLLocationManager authorizationStatus];
23 23
     switch (status) {
24 24
         case kCLAuthorizationStatusAuthorizedAlways:
25
-        case kCLAuthorizationStatusAuthorizedWhenInUse:
26 25
             return RNPStatusAuthorized;
26
+        case kCLAuthorizationStatusAuthorizedWhenInUse:
27
+            return [type isEqualToString:@"always"] ? RNPStatusDenied : RNPStatusAuthorized;
27 28
         case kCLAuthorizationStatusDenied:
28 29
             return RNPStatusDenied;
29 30
         case kCLAuthorizationStatusRestricted:
@@ -35,22 +36,26 @@
35 36
 
36 37
 - (void)request:(NSString*)type completionHandler:(void (^)(NSString *))completionHandler
37 38
 {
38
-    NSString *status = [RNPLocation getStatus];
39
+    NSString *status = [RNPLocation getStatusForType:nil];
39 40
     if (status == RNPStatusUndetermined) {
40 41
         self.completionHandler = completionHandler;
41
-        
42
+
42 43
         if (self.locationManager == nil) {
43 44
             self.locationManager = [[CLLocationManager alloc] init];
44 45
             self.locationManager.delegate = self;
45 46
         }
46
-        
47
+
47 48
         if ([type isEqualToString:@"always"]) {
48 49
             [self.locationManager requestAlwaysAuthorization];
49 50
         } else {
50 51
             [self.locationManager requestWhenInUseAuthorization];
51 52
         }
52 53
     } else {
53
-        completionHandler(status);
54
+        if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse && [type isEqualToString:@"always"]) {
55
+            completionHandler(RNPStatusDenied);
56
+        } else {
57
+            completionHandler(status);
58
+        }
54 59
     }
55 60
 }
56 61
 
@@ -60,14 +65,14 @@
60 65
             self.locationManager.delegate = nil;
61 66
             self.locationManager = nil;
62 67
         }
63
-        
68
+
64 69
         if (self.completionHandler) {
65 70
             //for some reason, checking permission right away returns denied. need to wait a tiny bit
66 71
             dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
67
-                self.completionHandler([RNPLocation getStatus]);
72
+                self.completionHandler([RNPLocation getStatusForType:nil]);
68 73
                 self.completionHandler = nil;
69 74
             });
70
-        }        
75
+        }
71 76
     }
72 77
 }
73 78
 @end

+ 12
- 31
permissions/RNPNotification.m View File

@@ -19,35 +19,21 @@ static NSString* RNPDidAskForNotification = @"RNPDidAskForNotification";
19 19
 + (NSString *)getStatus
20 20
 {
21 21
     BOOL didAskForPermission = [[NSUserDefaults standardUserDefaults] boolForKey:RNPDidAskForNotification];
22
+    BOOL isRegistered = [[UIApplication sharedApplication] isRegisteredForRemoteNotifications];
23
+    BOOL isEnabled = [[[UIApplication sharedApplication] currentUserNotificationSettings] types] != UIUserNotificationTypeNone;
22 24
     
23
-    if (didAskForPermission) {
24
-        if ([[UIApplication sharedApplication] respondsToSelector:@selector(isRegisteredForRemoteNotifications)]) {
25
-            // iOS8+
26
-            BOOL isRegistered = [[UIApplication sharedApplication] isRegisteredForRemoteNotifications];
27
-            BOOL isEnabled = [[[UIApplication sharedApplication] currentUserNotificationSettings] types] != UIUserNotificationTypeNone;
28
-            if (isRegistered || isEnabled) {
29
-                return isEnabled ? RNPStatusAuthorized : RNPStatusDenied;
30
-            }
31
-            else {
32
-                return RNPStatusDenied;
33
-            }
34
-        } else {
35
-            if ([[UIApplication sharedApplication] enabledRemoteNotificationTypes] == UIRemoteNotificationTypeNone) {
36
-                return RNPStatusDenied;
37
-            }
38
-            else {
39
-                return RNPStatusAuthorized;
40
-            }
41
-        }
25
+    if (isRegistered || isEnabled) {
26
+        return isEnabled ? RNPStatusAuthorized : RNPStatusDenied;
42 27
     } else {
43
-        return RNPStatusUndetermined;
28
+        return didAskForPermission ? RNPStatusDenied : RNPStatusUndetermined;
44 29
     }
45 30
 }
46 31
 
47 32
 - (void)request:(UIUserNotificationType)types completionHandler:(void (^)(NSString*))completionHandler
48 33
 {
49
-    BOOL didAskForPermission = [[NSUserDefaults standardUserDefaults] boolForKey:RNPDidAskForNotification];
50
-    if (!didAskForPermission) {
34
+    NSString *status = [self.class getStatus];
35
+    
36
+    if (status == RNPStatusUndetermined) {
51 37
         self.completionHandler = completionHandler;
52 38
         
53 39
         [[NSNotificationCenter defaultCenter] addObserver:self
@@ -55,19 +41,14 @@ static NSString* RNPDidAskForNotification = @"RNPDidAskForNotification";
55 41
                                                      name:UIApplicationDidBecomeActiveNotification
56 42
                                                    object:nil];
57 43
         
58
-        if ([[UIApplication sharedApplication] respondsToSelector:@selector(isRegisteredForRemoteNotifications)]) {
59
-            // iOS8+
60
-            UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
61
-            [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
62
-            [[UIApplication sharedApplication] registerForRemoteNotifications];
63
-        } else {
64
-            [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationType)types];
65
-        }
44
+        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
45
+        [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
46
+        [[UIApplication sharedApplication] registerForRemoteNotifications];
66 47
         
67 48
         [[NSUserDefaults standardUserDefaults] setBool:YES forKey:RNPDidAskForNotification];
68 49
         [[NSUserDefaults standardUserDefaults] synchronize];
69 50
     } else {
70
-        completionHandler([self.class getStatus]);
51
+        completionHandler(status);
71 52
     }
72 53
 }
73 54
 

+ 0
- 1
permissions/RNPPhoto.m View File

@@ -7,7 +7,6 @@
7 7
 //
8 8
 
9 9
 #import "RNPPhoto.h"
10
-#import <AddressBook/AddressBook.h>
11 10
 #import <AssetsLibrary/AssetsLibrary.h>
12 11
 
13 12
 @import Photos;

+ 17
- 0
permissions/RNPSpeechRecognition.h View File

@@ -0,0 +1,17 @@
1
+//
2
+//  RNPSpeechRecognition.h
3
+//  ReactNativePermissions
4
+//
5
+//  Created by Tres Trantham on 1/11/17.
6
+//  Copyright © 2017 Yonah Forst. All rights reserved.
7
+//
8
+
9
+#import <Foundation/Foundation.h>
10
+#import "RCTConvert+RNPStatus.h"
11
+
12
+@interface RNPSpeechRecognition : NSObject
13
+
14
++ (NSString *)getStatus;
15
++ (void)request:(void (^)(NSString *))completionHandler;
16
+
17
+@end

+ 44
- 0
permissions/RNPSpeechRecognition.m View File

@@ -0,0 +1,44 @@
1
+//
2
+//  RNPSpeechRecognition.m
3
+//  ReactNativePermissions
4
+//
5
+//  Created by Tres Trantham on 1/11/17.
6
+//  Copyright © 2017 Yonah Forst. All rights reserved.
7
+//
8
+
9
+#import "RNPSpeechRecognition.h"
10
+#import <Speech/Speech.h>
11
+
12
+@implementation RNPSpeechRecognition
13
+
14
++ (NSString *)getStatus
15
+{
16
+
17
+  int status = [SFSpeechRecognizer authorizationStatus];
18
+
19
+  switch (status) {
20
+      case SFSpeechRecognizerAuthorizationStatusAuthorized:
21
+          return RNPStatusAuthorized;
22
+      case SFSpeechRecognizerAuthorizationStatusDenied:
23
+          return RNPStatusDenied;
24
+      case SFSpeechRecognizerAuthorizationStatusRestricted:
25
+          return RNPStatusRestricted;
26
+      default:
27
+          return RNPStatusUndetermined;
28
+  }
29
+}
30
+
31
++ (void)request:(void (^)(NSString *))completionHandler
32
+{
33
+    void (^handler)(void) =  ^(void) {
34
+        dispatch_async(dispatch_get_main_queue(), ^{
35
+            completionHandler([self.class getStatus]);
36
+        });
37
+    };
38
+
39
+    [SFSpeechRecognizer requestAuthorization:^(SFSpeechRecognizerAuthorizationStatus status) {
40
+        handler();
41
+    }];
42
+}
43
+
44
+@end