Browse Source

Merge pull request #70 from trestrantham/master

Add support for iOS 10 speech recognition permission requests
Yonah Forst 8 years ago
parent
commit
f401e694e3

+ 1 - 1
Example/ios/Example.xcodeproj/project.pbxproj

@@ -584,7 +584,7 @@
 		83CBB9F71A601CBA00E9B192 /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 610;
+				LastUpgradeCheck = 0820;
 				ORGANIZATIONNAME = Facebook;
 				TargetAttributes = {
 					00E356ED1AD99517003FC87E = {

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

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

+ 2 - 1
RCTConvert+RNPStatus.h

@@ -25,7 +25,8 @@ typedef NS_ENUM(NSInteger, RNPType) {
     RNPTypeReminder,
     RNPTypeBluetooth,
     RNPTypeNotification,
-    RNPTypeBackgroundRefresh
+    RNPTypeBackgroundRefresh,
+    RNPTypeSpeechRecognition
 };
 
 @interface RCTConvert (RNPStatus)

+ 2 - 1
RCTConvert+RNPStatus.m

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

+ 17 - 14
README.md

@@ -12,6 +12,7 @@ The current supported permissions are:
 - Bluetooth *(iOS only)*
 - Push Notifications *(iOS only)*
 - Background Refresh *(iOS only)*
+- Speech Recognition *(iOS only)*
 
 
 | Version | React Native Support |
@@ -56,7 +57,7 @@ const Permissions = require('react-native-permissions');
     Permissions.checkMultiplePermissions(['camera', 'photo'])
       .then(response => {
         //response is an object mapping type to permission
-        this.setState({ 
+        this.setState({
           cameraPermission: response.camera,
           photoPermission: response.photo,
         })
@@ -64,7 +65,7 @@ const Permissions = require('react-native-permissions');
   }
 
   // this is a common pattern when asking for permissions.
-  // iOS only gives you once chance to show the permission dialog, 
+  // iOS only gives you once chance to show the permission dialog,
   // after which the user needs to manually enable them from settings.
   // the idea here is to explain why we need access and determine if
   // the user will say no, so that we don't blow our one chance.
@@ -75,7 +76,7 @@ const Permissions = require('react-native-permissions');
       'We need access so you can set your profile pic',
       [
         {text: 'No way', onPress: () => console.log('permission denied'), style: 'cancel'},
-        this.state.photoPermission == 'undetermined'? 
+        this.state.photoPermission == 'undetermined'?
           {text: 'OK', onPress: this._requestPermission.bind(this)}
           : {text: 'Open Settings', onPress: Permissions.openSettings}
       ]
@@ -110,6 +111,7 @@ Promises resolve into one of these statuses
 |`reminder`| ✔️ | ❌ |
 |`notification`| ✔️ | ❌ |
 |`backgroundRefresh`| ✔️ | ❌ |
+|`speechRecognition`| ✔️ | ❌ |
 |`storage`| ❌️ | ✔ |
 
 ###Methods
@@ -163,14 +165,15 @@ All required permissions also need to be included in the Manifest before they ca
 
 Permissions are automatically accepted for targetSdkVersion < 23 but you can still use `getPermissionStatus` to check if the user has disabled them from Settings.
 
-Here's a map of types to Android system permissions names:  
-`location` -> `android.permission.ACCESS_FINE_LOCATION`  
-`camera` -> `android.permission.CAMERA`  
-`microphone` -> `android.permission.RECORD_AUDIO`  
-`photo` -> `android.permission.READ_EXTERNAL_STORAGE`  
-`storage` -> `android.permission.READ_EXTERNAL_STORAGE`  
-`contacts` -> `android.permission.READ_CONTACTS`  
-`event` -> `android.permission.READ_CALENDAR`  
+Here's a map of types to Android system permissions names:
+`location` -> `android.permission.ACCESS_FINE_LOCATION`
+`camera` -> `android.permission.CAMERA`
+`microphone` -> `android.permission.RECORD_AUDIO`
+`photo` -> `android.permission.READ_EXTERNAL_STORAGE`
+`storage` -> `android.permission.READ_EXTERNAL_STORAGE`
+`contacts` -> `android.permission.READ_CONTACTS`
+`event` -> `android.permission.READ_CALENDAR`
+
 
 You can request write access to any of these types by also including the appropriate write permission in the Manifest. Read more here: https://developer.android.com/guide/topics/security/permissions.html#normal-dangerous
 
@@ -181,7 +184,7 @@ npm install --save react-native-permissions
 rnpm link
 ````
 
-###Or manualy linking   
+###Or manualy linking
 
 ####iOS
 * Run open node_modules/react-native-permissions
@@ -233,10 +236,10 @@ public class MainApplication extends Application implements ReactApplication {
 ##Troubleshooting
 
 #### Q: Android - `undefined is not a object (evaluating 'RNPermissions.requestPermissions')`
-A: `rnpm` may not have linked correctly. Follow the manual linking steps and make sure the library is linked 
+A: `rnpm` may not have linked correctly. Follow the manual linking steps and make sure the library is linked
 
 #### Q: iOS - app crashes as soon as I request permission
 A: starting with xcode 8, you need to add permission descriptions. see iOS notes for more details. Thanks to @jesperlndk for discovering this.
 
 #### Q: iOS - app crashes when I change permissions from settings
-A: This is normal. iOS restarts your app when your privacy settings change. Just google "ios crash permission change"
+A: This is normal. iOS restarts your app when your privacy settings change. Just google "ios crash permission change"

+ 1 - 0
ReactNativePermissions.js

@@ -16,6 +16,7 @@ const RNPTypes = {
 		'bluetooth',
 		'notification',
 		'backgroundRefresh',
+		'speechRecognition',
 	],
 	android: [
 		'location',

+ 6 - 0
ReactNativePermissions.m

@@ -22,6 +22,7 @@
 #import "RNPPhoto.h"
 #import "RNPContacts.h"
 #import "RNPBackgroundRefresh.h"
+#import "RNPSpeechRecognition.h"
 
 @interface ReactNativePermissions()
 @property (strong, nonatomic) RNPLocation *locationMgr;
@@ -104,6 +105,9 @@ RCT_REMAP_METHOD(getPermissionStatus, getPermissionStatus:(RNPType)type json:(id
         case RNPTypeBackgroundRefresh:
             status = [RNPBackgroundRefresh getStatus];
             break;
+        case RNPTypeSpeechRecognition:
+            status = [RNPSpeechRecognition getStatus];
+            break;
         default:
             break;
     }
@@ -134,6 +138,8 @@ RCT_REMAP_METHOD(requestPermission, permissionType:(RNPType)type json:(id)json r
             return [self requestBluetooth:resolve];
         case RNPTypeNotification:
             return [self requestNotification:json resolve:resolve];
+        case RNPTypeSpeechRecognition:
+            return [RNPSpeechRecognition request:resolve];
         default:
             break;
     }

+ 7 - 1
ReactNativePermissions.xcodeproj/project.pbxproj

@@ -7,6 +7,7 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
+		281CD5911E26B0C8003A72B2 /* RNPSpeechRecognition.m in Sources */ = {isa = PBXBuildFile; fileRef = 281CD5901E26B0C7003A72B2 /* RNPSpeechRecognition.m */; };
 		9D46283E1D34719100346A5B /* RNPAudioVideo.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D46282F1D34719100346A5B /* RNPAudioVideo.m */; };
 		9D46283F1D34719100346A5B /* RNPBackgroundRefresh.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D4628311D34719100346A5B /* RNPBackgroundRefresh.m */; };
 		9D4628401D34719100346A5B /* RNPBluetooth.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D4628331D34719100346A5B /* RNPBluetooth.m */; };
@@ -32,6 +33,8 @@
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
+		281CD5901E26B0C7003A72B2 /* RNPSpeechRecognition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNPSpeechRecognition.m; path = permissions/RNPSpeechRecognition.m; sourceTree = SOURCE_ROOT; };
+		281CD5921E26B266003A72B2 /* RNPSpeechRecognition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNPSpeechRecognition.h; path = permissions/RNPSpeechRecognition.h; sourceTree = SOURCE_ROOT; };
 		9D23B34F1C767B80008B4819 /* libReactNativePermissions.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libReactNativePermissions.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		9D46282E1D34719100346A5B /* RNPAudioVideo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNPAudioVideo.h; path = permissions/RNPAudioVideo.h; sourceTree = SOURCE_ROOT; };
 		9D46282F1D34719100346A5B /* RNPAudioVideo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNPAudioVideo.m; path = permissions/RNPAudioVideo.m; sourceTree = SOURCE_ROOT; };
@@ -113,6 +116,8 @@
 				9D46283B1D34719100346A5B /* RNPNotification.m */,
 				9D46283C1D34719100346A5B /* RNPPhoto.h */,
 				9D46283D1D34719100346A5B /* RNPPhoto.m */,
+				281CD5921E26B266003A72B2 /* RNPSpeechRecognition.h */,
+				281CD5901E26B0C7003A72B2 /* RNPSpeechRecognition.m */,
 			);
 			name = permissions;
 			sourceTree = "<group>";
@@ -143,7 +148,7 @@
 		9D23B3471C767B80008B4819 /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 0710;
+				LastUpgradeCheck = 0820;
 				ORGANIZATIONNAME = "Yonah Forst";
 				TargetAttributes = {
 					9D23B34E1C767B80008B4819 = {
@@ -175,6 +180,7 @@
 			files = (
 				9D46283F1D34719100346A5B /* RNPBackgroundRefresh.m in Sources */,
 				9D4628451D34719100346A5B /* RNPPhoto.m in Sources */,
+				281CD5911E26B0C8003A72B2 /* RNPSpeechRecognition.m in Sources */,
 				9D4628431D34719100346A5B /* RNPLocation.m in Sources */,
 				9D46283E1D34719100346A5B /* RNPAudioVideo.m in Sources */,
 				9D4628401D34719100346A5B /* RNPBluetooth.m in Sources */,

+ 17 - 0
permissions/RNPSpeechRecognition.h

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

+ 44 - 0
permissions/RNPSpeechRecognition.m

@@ -0,0 +1,44 @@
+//
+//  RNPSpeechRecognition.m
+//  ReactNativePermissions
+//
+//  Created by Tres Trantham on 1/11/17.
+//  Copyright © 2017 Yonah Forst. All rights reserved.
+//
+
+#import "RNPSpeechRecognition.h"
+#import <Speech/Speech.h>
+
+@implementation RNPSpeechRecognition
+
++ (NSString *)getStatus
+{
+
+  int status = [SFSpeechRecognizer authorizationStatus];
+
+  switch (status) {
+      case SFSpeechRecognizerAuthorizationStatusAuthorized:
+          return RNPStatusAuthorized;
+      case SFSpeechRecognizerAuthorizationStatusDenied:
+          return RNPStatusDenied;
+      case SFSpeechRecognizerAuthorizationStatusRestricted:
+          return RNPStatusRestricted;
+      default:
+          return RNPStatusUndetermined;
+  }
+}
+
++ (void)request:(void (^)(NSString *))completionHandler
+{
+    void (^handler)(void) =  ^(void) {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            completionHandler([self.class getStatus]);
+        });
+    };
+
+    [SFSpeechRecognizer requestAuthorization:^(SFSpeechRecognizerAuthorizationStatus status) {
+        handler();
+    }];
+}
+
+@end