Repository: beeware/briefcase
Pull request #1820 (2024-05-21 13:38:07)

Fix macOS camera / microphone / photo library permissions
## Problem
Built macOS app crashed when camera access was requested, due to the fact that (whilst the `Entitlements.plist` was being updated properly) the expected info was not being added to `Info.plist`

This PR fixes this issue by ensuring that, when the user provides `permissions.camera`, `permissions.microphone`, or `permissions.photo_library`, the messages are added to `Info.plist` under the relevant property key.

## Changes
- Added tests to [`test_create.py` for macOS](tests/platforms/macOS/app/test_create.py)
- Patched `macOSCreateMixin` in [`__init__.py` for macOS](src/briefcase/platforms/macOS/__init__.py)
- Updated documentation accordingly


## PR Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
- [x] All new features have been tested
- [x] All new features have been documented
- [x] I have read the **CONTRIBUTING.md** file
- [x] I will abide by the code of conduct



Patch:
diff --git a/changes/1817.misc.rst b/changes/1817.misc.rst
deleted file mode 100644
index 5b26b3b4..00000000
--- a/changes/1817.misc.rst
+++ /dev/null
@@ -1,1 +0,0 @@
-Pytest was bumped from version 8.1.2 to 8.2.1.
diff --git a/changes/1820.bugfix.rst b/changes/1820.bugfix.rst
new file mode 100644
index 00000000..a2f4a2e7
--- /dev/null
+++ b/changes/1820.bugfix.rst
@@ -0,0 +1,1 @@
+macOS apps now generate ``info.plist`` entries for camera, photo library and microphone permissions.
diff --git a/docs/reference/platforms/macOS/xcode.rst b/docs/reference/platforms/macOS/xcode.rst
index d00b8be0..6836acc1 100644
--- a/docs/reference/platforms/macOS/xcode.rst
+++ b/docs/reference/platforms/macOS/xcode.rst
@@ -117,8 +117,10 @@ Permissions
 Briefcase cross platform permissions map to a combination of ``info`` and ``entitlement``
 keys:
 
-* ``microphone``: an ``entitlement`` of ``com.apple.security.device.audio-input``
-* ``camera``: an ``entitlement`` of ``com.apple.security.device.camera``
+* ``microphone``: an ``info`` entry for ``NSMicrophoneUsageDescription``; and
+  an ``entitlement`` of ``com.apple.security.device.audio-input``
+* ``camera``: an ``info`` entry for ``NSCameraUsageDescription``; and
+  an ``entitlement`` of ``com.apple.security.device.camera``
 * ``coarse_location``: an ``info`` entry for ``NSLocationUsageDescription``
   (ignored if ``background_location`` or ``fine_location`` is defined); plus an
   entitlement of ``com.apple.security.personal-information.location``
@@ -127,7 +129,9 @@ keys:
   ``com.apple.security.personal-information.location``
 * ``background_location``: an ``info`` entry for ``NSLocationUsageDescription``;
   plus an ``entitlement`` of ``com.apple.security.personal-information.location``
-* ``photo_library``: an ``entitlement`` of ``com.apple.security.personal-information.photos-library``
+* ``photo_library``: an ``info`` entry for ``NSPhotoLibraryUsageDescription``;
+  plus an ``entitlement`` of
+  ``com.apple.security.personal-information.photos-library``
 
 Platform quirks
 ===============
diff --git a/pyproject.toml b/pyproject.toml
index e1f4f264..7fe18ed5 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -101,7 +101,7 @@ dev = [
     # Pre-commit 3.6.0 deprecated support for Python 3.8
     "pre-commit == 3.5.0 ; python_version < '3.9'",
     "pre-commit == 3.7.1 ; python_version >= '3.9'",
-    "pytest == 8.2.1",
+    "pytest == 8.1.2",
     "pytest-xdist == 3.6.1",
     "setuptools_scm == 8.0.4",
     "tox == 4.15.0",
diff --git a/src/briefcase/platforms/macOS/__init__.py b/src/briefcase/platforms/macOS/__init__.py
index 415ebd3e..e1ad5a87 100644
--- a/src/briefcase/platforms/macOS/__init__.py
+++ b/src/briefcase/platforms/macOS/__init__.py
@@ -168,8 +168,10 @@ in the macOS configuration section of your pyproject.toml.
 
         if cross_platform["camera"]:
             entitlements["com.apple.security.device.camera"] = True
+            info["NSCameraUsageDescription"] = cross_platform["camera"]
         if cross_platform["microphone"]:
             entitlements["com.apple.security.device.microphone"] = True
+            info["NSMicrophoneUsageDescription"] = cross_platform["microphone"]
 
         if cross_platform["background_location"]:
             info["NSLocationUsageDescription"] = cross_platform["background_location"]
@@ -182,6 +184,7 @@ in the macOS configuration section of your pyproject.toml.
             entitlements["com.apple.security.personal-information.location"] = True
 
         if cross_platform["photo_library"]:
+            info["NSPhotoLibraryUsageDescription"] = cross_platform["photo_library"]
             entitlements["com.apple.security.personal-information.photo_library"] = True
 
         # Override any info and entitlement definitions with the platform specific definitions


Test patch:
diff --git a/tests/platforms/macOS/app/test_create.py b/tests/platforms/macOS/app/test_create.py
index 8fed8470..91ab045e 100644
--- a/tests/platforms/macOS/app/test_create.py
+++ b/tests/platforms/macOS/app/test_create.py
@@ -73,7 +73,9 @@ def create_command(tmp_path, first_app_templated):
             {},
             {},
             {
-                "info": {},
+                "info": {
+                    "NSCameraUsageDescription": "I need to see you",
+                },
                 "entitlements": {
                     "com.apple.security.cs.allow-unsigned-executable-memory": True,
                     "com.apple.security.cs.disable-library-validation": True,
@@ -89,7 +91,9 @@ def create_command(tmp_path, first_app_templated):
             {},
             {},
             {
-                "info": {},
+                "info": {
+                    "NSMicrophoneUsageDescription": "I need to hear you",
+                },
                 "entitlements": {
                     "com.apple.security.cs.allow-unsigned-executable-memory": True,
                     "com.apple.security.cs.disable-library-validation": True,
@@ -236,7 +240,9 @@ def create_command(tmp_path, first_app_templated):
             {},
             {},
             {
-                "info": {},
+                "info": {
+                    "NSPhotoLibraryUsageDescription": "I need to see your library",
+                },
                 "entitlements": {
                     "com.apple.security.cs.allow-unsigned-executable-memory": True,
                     "com.apple.security.cs.disable-library-validation": True,