Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

On iOS, Expo Camera requires NSMicrophoneUsageDescription key to use the feature #11736

Closed
thisisgit opened this issue Jan 25, 2021 · 36 comments 路 Fixed by #12860 or #13690
Closed

On iOS, Expo Camera requires NSMicrophoneUsageDescription key to use the feature #11736

thisisgit opened this issue Jan 25, 2021 · 36 comments 路 Fixed by #12860 or #13690
Assignees
Labels
Camera docs needs validation Issue needs to be validated

Comments

@thisisgit
Copy link

thisisgit commented Jan 25, 2021

馃悰 Bug Report

Summary of Issue

Hi, I just started using Expo Camera on my bare RN project and facing some issues.
I followed the installation process here and according to Configure for iOS, I only need to add NSCameraUsageDescription key but doing so produces following error:

This app is missing either NSCameraUsageDescription or 
NSMicrophoneUsageDescription, so audio/video services will fail. Add one of
these entries to your bundle's Info.plist.

But adding NSMicrophoneUsageDescription key solves the error.
I simply copied the code from here and I believe it shouldn't require permission for mic since I'm not going to use camera to take a video. So it should rather considered optional.

Environment - output of expo diagnostics & the platform(s) you're targeting

Expo CLI 4.0.17 environment info:
    System:
      OS: macOS 11.1
      Shell: 5.8 - /bin/zsh
    Binaries:
      Node: 15.4.0 - /usr/local/bin/node
      Yarn: 1.22.5 - ~/.yarn/bin/yarn
      npm: 7.0.15 - /usr/local/bin/npm
      Watchman: 4.9.0 - /usr/local/bin/watchman
    Managers:
      CocoaPods: 1.10.1 - /usr/local/bin/pod
    SDKs:
      iOS SDK:
        Platforms: iOS 14.3, DriverKit 20.2, macOS 11.1, tvOS 14.3, watchOS 7.2
    IDEs:
      Android Studio: 4.1 AI-201.8743.12.41.6953283
      Xcode: 12.3/12C33 - /usr/bin/xcodebuild
    npmPackages:
      react: 16.13.1 => 16.13.1 
      react-native: 0.63.3 => 0.63.3 
    npmGlobalPackages:
      expo-cli: 4.0.17
    Expo Workflow: bare

Steps to Reproduce

  1. Create bare RN app with unimodules installed.
  2. Install Expo Camera following this page
  3. Copy the example from here
  4. Running it throws this error:
    Simulator Screen Shot - iPhone 12 - 2021-01-25 at 17 35 43
@thisisgit thisisgit added the needs validation Issue needs to be validated label Jan 25, 2021
@zercha55
Copy link

zercha55 commented Feb 2, 2021

I am getting the same error

@gie3d
Copy link

gie3d commented Feb 12, 2021

I also faced this problem and did some work around like this.

in node_modules/expo-camera/ios/EXCamera/EXCameraPermissionRequester.m, which is where it checks for permission.

I changed it from

- (NSDictionary *)getPermissions
{
  AVAuthorizationStatus systemStatus;
  UMPermissionStatus status;
  NSString *cameraUsageDescription = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSCameraUsageDescription"];
  NSString *microphoneUsageDescription = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSMicrophoneUsageDescription"];
  if (!(cameraUsageDescription && microphoneUsageDescription)) {
    UMFatal(UMErrorWithMessage(@"This app is missing either NSCameraUsageDescription or NSMicrophoneUsageDescription, so audio/video services will fail. Add one of these entries to your bundle's Info.plist."));
    systemStatus = AVAuthorizationStatusDenied;
  } else {
    systemStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
  }
  // ...

to be

- (NSDictionary *)getPermissions
{
  AVAuthorizationStatus systemStatus;
  UMPermissionStatus status;
  NSString *cameraUsageDescription = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSCameraUsageDescription"];
  if (!cameraUsageDescription) {
    // changed a bit of its exception
    UMFatal(UMErrorWithMessage(@"This app is missing either NSCameraUsageDescription. Add this entry to your bundle's Info.plist."));
    systemStatus = AVAuthorizationStatusDenied;
  } else {
    systemStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
  }
  // ... 

I'm sure this is not a good practice.

I guess we may need a new prop to let the component knows whether it needs a check for using video or not (in that case, it has to check for NSMicrophone) or should we separate the component for Video and Camera?

@AlimovSV
Copy link

Any updates?

@rueiwoqp
Copy link

I'm also seeing this issue in a bare project that was ejected from a managed app that worked perfectly. I also checked Info.plist and the NSCameraUsageDescription is present but NSMicrophoneUsageDescription is not because the app does not use the microphone.

@maurobalbi
Copy link

I ran into the same issue with a bare RN project, it's a bit misleading since the docs say that microphone is optional. But looking at @gie3d's comment suggests otherwise.

@timarney
Copy link

timarney commented Apr 29, 2021

Confirming as well.

When using only the Camera for QR Code scan

Testing local build - works without the Microphone permission. - forgot we have a separate debug .plist file that still has the microphone entry

Pushing to TestFlight - the error occurs - "Use camera" prompt doesn't pop up

@conormuldoon
Copy link

I have the same error. It's detected locally when using Xcode 12.4/iOS 14.4 and an iPhone 11.

@ajsmth
Copy link
Contributor

ajsmth commented May 5, 2021

For now, the safest option is to specify the NSMicrophoneUsageDescription in Info.plist in order to get this working.

I did some digging and it seems that the microphone permission prompt will only show if you use any sort of audio component with the camera. For something like the BarcodeScanner, this shouldn't ever really happen because it doesn't need to capture audio.

However, if you're using the expo-camera.recordAsync() method anywhere, then you are capturing audio by default, and so the microphone description is required -- if it's not present, it will crash the app when a user tries to record video.

If you don't want to record audio, then specifying recordAsync({ mute: true }) will not capture audio and no microphone prompt will be displayed.

The takeaways are that the expo-barcode-scanner probably shouldn't check for NSMicrophoneUsageDescription permissions in Info.plist, and expo-camera might need NSMicrophoneUsageDescription depending on how it is being used.

One downside to requiring all users specify a microphone permission in expo-camera is that it might be flagged by Apple on submission - I'm not sure how consistent they are with this, but if my app is just using a Camera for photos yet specifies a microphone usage description, it might catch some attention. I think the best course of action is to only request permissions required

I think we should extend the requestPermissionsAsync() to specify just video or both video and audio and update our documentation to reflect this, with an important note about the possibility of crashing if you attempt to capture audio without specifying a NSMicrophoneUsageDescription

@timarney
Copy link

timarney commented May 5, 2021

One downside to requiring all users specify a microphone permission in expo-camera is that it might be flagged by Apple on submission

  • App store review -> This is a primary concern for sure
  • Also for anyone looking at the Info.plist i.e. open source repo etc... it's confusing

We might try patching via https://www.npmjs.com/package/patch-package or something based on

#11736 (comment)

@timarney
Copy link

timarney commented May 6, 2021

Update re: trying to using a patch via patch-package

Applying a patch via patch-package isn't working

We cleaned the our project using react-native-clean-project (all caches, pod files etc...)

Applied the patch - checked the node_modules dir to ensure the patch was applied + ran builds across multiple computers.

Somehow we're still seeing the

This app is missing either 'NSCameraUsageDescription' or 'NSMicrophoneUsageDescription', .... error

vs

the patched This app is missing 'NSCameraUsageDescription' Add entry ... error.

We're are using a React Native project vs an expo project - could it be something to do with react-native-unimodules ?
Could there be some compiling happening somewhere?
Could the file we patched be getting pulled from a different location ?

node_modules/expo-barcode-scanner/ios/EXBarCodeScanner/EXBarCodeCameraRequester.m

@brentvatne
Copy link
Member

@timarney - i'll try this in a new repository and report back in a moment

@brentvatne
Copy link
Member

brentvatne commented May 6, 2021

ah sorry - my bad. i forgot to mention that by default we compile xcframeworks of expo packages at publish time, so that developers using them have faster builds. if you patch a module and want to build it from source, then you can disable this either for all modules or on a per-module basis in your Podfile: https://github.com/brentvatne/microphone-permissions/blob/7ad6815caf90a2d283cf6c1cd81d6cb117bdc002/ios/Podfile#L7-L12

# Compile this from source rather than using prebuilt xcframework.
# Alternatively, set the `EXPO_USE_SOURCE=1` env var to disable prebuilds for
# all modules.
$ExpoUseSources = [
  'expo-barcode-scanner',
]

confirmed that everything works well with your patch in this repo (although i had installed expo-barcode-scanner@10.1.2 there, your patch still applied cleanly and the issue reprod before the above podfile fix)

@timarney
Copy link

timarney commented May 6, 2021

Nice we'll also we updating to expo-barcode-scanner@10.1.2

Thanks for hunting that down @brentvatne

Prebuilt modules

https://github.com/expo/fyi/blob/master/prebuilt-modules.md

@WilbertJanney
Copy link

WilbertJanney commented Jun 4, 2021

We don't use expo-barcode-scanner so using that as a solution didn't work. I had to add the microphone permission to get around this issue. Is there a fix planned to fix this to not require the microphone if an app doesn't need it?

@brentvatne
Copy link
Member

brentvatne commented Jun 4, 2021

@WilbertJanney - you use expo-camera then or what? if so, you can cherry-pick the changes from this pr and follow the $ExpoUseSources instruction above.

@rdsedmundo
Copy link

I'm also seeing this using expo-camera, it states that the requestCameraPermissionsAsync doesn't even exist. The PR that fixed it was opened 45+ days ago, this release model of expo is weird, it doesn't make any sense to wait so long to have a non-breaking change available.

@ajsmth
Copy link
Contributor

ajsmth commented Jun 24, 2021

@rdsedmundo which version of this package are you using? Those functions should be available in v11.1.0

ref: https://github.com/expo/expo/blob/master/packages/expo-camera/CHANGELOG.md

@rdsedmundo
Copy link

rdsedmundo commented Jun 24, 2021

@ajsmth 11.0.3, that's the one tagged as latest on NPM, although now that you said I can see that there's a 11.1.0 available. Is that expected?

Screen Shot 2021-06-24 at 14 08 37

@ajsmth
Copy link
Contributor

ajsmth commented Jun 24, 2021

I believe we'll need to promote to the latest version - you can install this version explicitly in the meantime

@gie3d
Copy link

gie3d commented Jul 14, 2021

Sorry, I removed my recent comment as I still observe the problem

I changed Camera.requestPermissionsAsync to Camera.requestCameraPermissionsAsync and expected that the EXCameraCameraPermissionRequester should take responsible to request permission. However, I still get the following error:

This app is missing either NSCameraUsageDescription or NSMicrophoneUsageDescription, so audio/video services will fail. Add one of these entries to your bundle's Info.plist.

which was defined in EXCameraPermissionRequester. However, I tried to hack this file by changing the error message to prove that it was really happened in this file. After rerun I still got the same error.

It would be nice if

  • Any one can confirm this is fixed
    or
  • If someone could guide me a little more if there is another permission requester
    or
  • I did it all wrong 馃槬

@brentvatne
Copy link
Member

@gie3d - what sdk version are you using? or expo-camera version?

@gie3d
Copy link

gie3d commented Jul 15, 2021

@brentvatne i tested with

  • Expo sdk 42
  • expo-camera 11.2.1

@ajsmth
Copy link
Contributor

ajsmth commented Jul 16, 2021

@gie3d hey there - I've just tested this on SDK 42 and it seems to be working fine - you can check out a repro here: https://github.com/ajsmth/expo-camera-sdk-42

That error message should only be coming from Camera.requestPermissionsAsync() are you sure you are using the right method? Can you provide some sample source code of how you are implementing this?

@gie3d
Copy link

gie3d commented Jul 16, 2021

@ajsmth many thanks for the information. I'll fine time this weekend to test it out.

Btw, looked into your repo and found that the primary different between this and my code is that I open the camera <Camera>.

I'll fork your project and reproduce the problem and then I'll get back again.

@ajsmth
Copy link
Contributor

ajsmth commented Jul 20, 2021

@gie3d did your problem go away or are you still having issues? I might have reproduced a similar situation to yours - let me know!

@gie3d
Copy link

gie3d commented Jul 20, 2021

@ajsmth I tested on a newly forked repo (https://github.com/gie3d/expo-camera-sdk-42) in bare workflow and it seems working correctly.

I saw you mentioned this issue in a PR. Could you share if you can reproduce this issue.

@matinzd
Copy link
Contributor

matinzd commented Dec 11, 2022

This is a logical issue in the written code. Permissions should be checked based on the media types the user is requesting. If the media type is just for image, microphone permission should be dismissed.

if cameraUsageDescription == nil || microphoneUsageDescription == nil {
EXFatal(EXErrorWithMessage("""
This app is missing either 'NSCameraUsageDescription' or 'NSMicrophoneUsageDescription', so audio/video services will fail. \
Ensure both of these keys exist in app's Info.plist.
"""))
systemStatus = AVAuthorizationStatus.denied
} else {
systemStatus = AVCaptureDevice.authorizationStatus(for: AVMediaType.video)
}

@kaladivo
Copy link

kaladivo commented May 3, 2023

@matinzd I agree. Our app uses expo-image-picker to select user's profile picture. We don't need microphone permission, but the app crashes when opening camera.

With this plugin setting:

      'expo-image-picker',
      {
        'photosPermission':
          '...',
        'cameraPermission':
          '...',
        'microphonePermission': false,
      },
    ],

This is an issue when apple is reviewing the app, since the app has setup unnecessary permission.

For now, the hotfix is to add this patch file:

index 3cc81e0f8a4d1804ef42c5ee632527597f890950..ae0db1900d70f627ab50d7a75edd152e48151b9d 100644
--- a/ios/ImagePickerPermissionRequesters.swift
+++ b/ios/ImagePickerPermissionRequesters.swift
@@ -18,8 +18,7 @@ public class CameraPermissionRequester: NSObject, EXPermissionsRequester {
     var systemStatus: AVAuthorizationStatus
     var status: EXPermissionStatus
     let cameraUsageDescription = Bundle.main.object(forInfoDictionaryKey: "NSCameraUsageDescription")
-    let microphoneUsageDescription = Bundle.main.object(forInfoDictionaryKey: "NSMicrophoneUsageDescription")
-    if cameraUsageDescription == nil || microphoneUsageDescription == nil {
+    if cameraUsageDescription == nil {
       EXFatal(EXErrorWithMessage("""
       This app is missing either 'NSCameraUsageDescription' or 'NSMicrophoneUsageDescription', so audio/video services will fail. Ensure both of these keys exist in app's Info.plist. 

@ryonwhyte
Copy link

I am getting the same error here as @kaladivo . Seems to still be an issue

@jonrh
Copy link

jonrh commented Dec 27, 2023

Same here. Using expo-image-picker v14.3.2 & Expo v49 to allow user to take photos directly. Works in Expo Go but crashes on a physical device in TestFlight. Seems like a bug or a regression in Expo. Was able to work around it by giving a permission string value to microphonePermission even though the microphone is not used at all.

@ryonwhyte
Copy link

ryonwhyte commented Feb 26, 2024

Hi @jonrh Jut in case you come back here
In my case, I used a config plugin to solve my issue. Here is my code

const { createRunOncePlugin, withPlugins } = require("@expo/config-plugins");

/**
 * @typedef {import('@expo/config-plugins').ConfigPlugin} ConfigPlugin
 */

/**
 * Modify the camera permission requester to ignore the microphone permission check.
 *
 * @type {ConfigPlugin}
 */
const withIgnoreMicrophonePermissionCheck = (
  config,
  { ignoreMicrophonePermissionCheck } = {}
) => {
  return withPlugins(config, [
    [
      "expo-image-picker",
      {
        // Set ignoreMicrophonePermissionCheck to true to bypass the microphone permission check
        microphonePermission: ignoreMicrophonePermissionCheck ? false : "...",
      },
    ],
  ]);
};

module.exports = createRunOncePlugin(
  withIgnoreMicrophonePermissionCheck,
  "withIgnoreMicrophonePermissionCheck",
  "1.0.0"
);

I then added it to my app,json plugin section

      ....
      ...
      "./config/withIgnoreMicrophonePermissionCheck.js",

And set the "microphonePermission": false in the expo-image-picker plugin as well

@highmountainmedia
Copy link

@ryonwhyte can you elaborate a little on your code or any other suggestions? I've tried using this code, I've tried setting both the expo-image-picker plugin "microphonePermission" to a string as well as false, and also setting the "NSMicrophoneUsageDescription" to string, and my app still crashes once built for preview or testflight. Using SDK 50 and expo-image-picker 14.7.1. Pulling my hair out as no build works with any variations of these options set or not set.

image

@ryonwhyte
Copy link

@highmountainmedia I think you may be having another issue.
This is what is in my app.json along with the config plugin code above.

 "expo-image-picker",
        {
          "photosPermission": "Allow appname to access photos to choose profile picture",
          "cameraPermission": "Allow appname to open the camera to capture a profile picture",
          "microphonePermission": false
        }

@highmountainmedia
Copy link

@ryonwhyte I finally got this working with using your script, but had to put a string value in for the microphonePermission entry. That's the only way it would not crash.

@ryonwhyte
Copy link

Hmm. Thats interesting. I have not encountered any issues. I will test in production and see. Thanks for sharing @highmountainmedia

@ryonwhyte
Copy link

@highmountainmedia Yeah my new build on expo 50 is crashing now. I changed "microphonePermission": to a string in my app.json. Did you edit the config plugin?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment