In my app user has to tap a microphone to send an audio message, before opening the voice record bottom sheet I need to check for microphone permission. The native iOS microphone permission pop up won't open after requesting permission. I had to change the RNPermissionHandlerMicrophone.m to the following:
#import "RNPermissionHandlerMicrophone.h"
@import AVFoundation;
@implementation RNPermissionHandlerMicrophone
+ (NSArray<NSString *> * _Nonnull)usageDescriptionKeys {
return @[@"NSMicrophoneUsageDescription"];
}
+ (NSString * _Nonnull)handlerUniqueId {
return @"ios.permission.MICROPHONE";
}
- (void)checkWithResolver:(void (^ _Nonnull)(RNPermissionStatus))resolve
rejecter:(void (__unused ^ _Nonnull)(NSError * _Nonnull))reject {
switch ([[AVAudioSession sharedInstance] recordPermission]) {
case AVAudioSessionRecordPermissionUndetermined:
return resolve(RNPermissionStatusNotDetermined);
case AVAudioSessionRecordPermissionDenied:
return resolve(RNPermissionStatusDenied);
case AVAudioSessionRecordPermissionGranted:
return resolve(RNPermissionStatusAuthorized);
}
}
- (void)requestWithResolver:(void (^ _Nonnull)(RNPermissionStatus))resolve
rejecter:(void (^ _Nonnull)(NSError * _Nonnull))reject {
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio
completionHandler:^(__unused BOOL granted) {
[self checkWithResolver:resolve rejecter:reject];
}];
}
@end
After applying this change the native pop up kicks in after I request for permission and it works as expected.
I patch-package'd the module, patch-package crashes so we need to patch patch-package using patch-package
Here's a patch react-native-permissions+3.0.0.patch:
diff --git a/node_modules/react-native-permissions/ios/Microphone/RNPermissionHandlerMicrophone.m b/node_modules/react-native-permissions/ios/Microphone/RNPermissionHandlerMicrophone.m
index 5885228..0bac37d 100644
--- a/node_modules/react-native-permissions/ios/Microphone/RNPermissionHandlerMicrophone.m
+++ b/node_modules/react-native-permissions/ios/Microphone/RNPermissionHandlerMicrophone.m
@@ -14,14 +14,12 @@ + (NSString * _Nonnull)handlerUniqueId {
- (void)checkWithResolver:(void (^ _Nonnull)(RNPermissionStatus))resolve
rejecter:(void (__unused ^ _Nonnull)(NSError * _Nonnull))reject {
- switch ([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio]) {
- case AVAuthorizationStatusNotDetermined:
+ switch ([[AVAudioSession sharedInstance] recordPermission]) {
+ case AVAudioSessionRecordPermissionUndetermined:
return resolve(RNPermissionStatusNotDetermined);
- case AVAuthorizationStatusRestricted:
- return resolve(RNPermissionStatusRestricted);
- case AVAuthorizationStatusDenied:
+ case AVAudioSessionRecordPermissionDenied:
return resolve(RNPermissionStatusDenied);
- case AVAuthorizationStatusAuthorized:
+ case AVAudioSessionRecordPermissionGranted:
return resolve(RNPermissionStatusAuthorized);
}
}
react-native info output:
System:
OS: macOS 11.2.1
CPU: (8) x64 Intel(R) Core(TM) i5-8279U CPU @ 2.40GHz
Memory: 959.40 MB / 8.00 GB
Shell: 5.8 - /bin/zsh
Binaries:
Node: 12.18.3 - ~/.nvm/versions/node/v12.18.3/bin/node
Yarn: 1.22.10 - ~/.nvm/versions/node/v12.18.3/bin/yarn
npm: 7.5.6 - ~/.nvm/versions/node/v12.18.3/bin/npm
Watchman: 4.9.0 - /usr/local/bin/watchman
Managers:
CocoaPods: 1.10.1 - /Users/stathis/.rbenv/shims/pod
SDKs:
iOS SDK:
Platforms: iOS 14.4, DriverKit 20.2, macOS 11.1, tvOS 14.3, watchOS 7.2
Android SDK:
API Levels: 26, 28, 29
Build Tools: 28.0.3, 29.0.2, 29.0.3, 30.0.2
System Images: android-27 | Google APIs Intel x86 Atom
Android NDK: Not Found
IDEs:
Android Studio: 4.1 AI-201.8743.12.41.7042882
Xcode: 12.4/12D4e - /usr/bin/xcodebuild
Languages:
Java: 1.8.0_275 - /usr/bin/javac
Python: 2.7.16 - /usr/bin/python
npmPackages:
@react-native-community/cli: Not Found
react: 16.13.1 => 16.13.1
react-native: ^0.63.4 => 0.63.4
react-native-macos: Not Found
npmGlobalPackages:
*react-native*: Not Found
Library version: 3.0.0
Just create a request for iOS microphone permission.
Describe what you expected to happen:
Open the native iOS pop up requesting microphone permission.
@efstathiosntonas Thank you! Can you please open a pull request instead?
@zoontek sure
It seems a bit weird that updating the checkWithResolver method fix the request. You are still calling [AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio completionHandler:] which is responsible for showing the popup.
this is the code:
#import "RNPermissionHandlerMicrophone.h"
@import AVFoundation;
@implementation RNPermissionHandlerMicrophone
+ (NSArray<NSString *> * _Nonnull)usageDescriptionKeys {
return @[@"NSMicrophoneUsageDescription"];
}
+ (NSString * _Nonnull)handlerUniqueId {
return @"ios.permission.MICROPHONE";
}
- (void)checkWithResolver:(void (^ _Nonnull)(RNPermissionStatus))resolve
rejecter:(void (__unused ^ _Nonnull)(NSError * _Nonnull))reject {
switch ([[AVAudioSession sharedInstance] recordPermission]) {
case AVAudioSessionRecordPermissionUndetermined:
return resolve(RNPermissionStatusNotDetermined);
case AVAudioSessionRecordPermissionDenied:
return resolve(RNPermissionStatusDenied);
case AVAudioSessionRecordPermissionGranted:
return resolve(RNPermissionStatusAuthorized);
}
}
- (void)requestWithResolver:(void (^ _Nonnull)(RNPermissionStatus))resolve
rejecter:(void (^ _Nonnull)(NSError * _Nonnull))reject {
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio
completionHandler:^(__unused BOOL granted) {
[self checkWithResolver:resolve rejecter:reject];
}];
}
@end
i think the issue is in this line: [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio], this line won't call it immediately for some reason and it returns undetermined
This is only used to check permission, not triggering the popup. See iOS documentation: https://developer.apple.com/documentation/avfoundation/avcapturedevice/1624613-authorizationstatusformediatype
This method perform incorrectly on the simulator, but not on real devices (https://stackoverflow.com/questions/32988277/avauthorizationstatusnotdetermined-on-ios-simulator)
Did you enabled Microphone capability on Xcode? Which device are you using (and with which iOS version)?
I'm on Xcode 12.4, ios 14.4, iPhone XS and I have enabled microphone capability on Xcode (NSMicrophoneUsageDescription on info.plist).
On the so link you provided, the answer provided uses the same logic as my changes hmmm
edit: witch one would be better to use though? I mean for the package it self. Should we add one more request type that forces the pop up to open?
@efstathiosntonas Not according to Apple documentation:

[AVAudioSession sharedInstance] also expose a requestRecordPermission method. It's probably better to change the check and the request to use this API if it's perform better:
I made a release with the fix: https://github.com/zoontek/react-native-permissions/releases/tag/3.0.1 (tried it on the simulator and a device, it works perfectly well)
Thanks for your help!
thanks @zoontek, was going to PR it later but you got me first 😀
Most helpful comment
I made a release with the fix: https://github.com/zoontek/react-native-permissions/releases/tag/3.0.1 (tried it on the simulator and a device, it works perfectly well)
Thanks for your help!