Repository: beeware/briefcase

Issue:
Launch failed on ARM Mac
**Describe the bug**
The application cannot be opened for an unexpected reason

**To Reproduce**
Steps to reproduce the behavior:
1. Tutorial 1
2. Tutorial 2
3. Tutorial 3

**Expected behavior**
Works as described in the tutorial.

**Screenshots**
```
(beeware-venv) tony@x helloworld % briefcase run

[helloworld] Starting app...

The application cannot be opened for an unexpected reason, error=Error Domain=RBSRequestErrorDomain Code=5 "Launch failed." UserInfo={NSLocalizedFailureReason=Launch failed., NSUnderlyingError=0x60000361eb50 {Error Domain=NSPOSIXErrorDomain Code=153 "Unknown error: 153" UserInfo={NSLocalizedDescription=Launchd job spawn failed}}}

Unable to start app helloworld.
```
**Environment:**
 - Operating System: MacOS Monterey 12.1 (Apple M1 Pro)
 - Python version: 3.8.9
 - Software versions:
   - Briefcase: 0.3.5
   - Toga: 0.3.0.dev20


**Additional context**
Followed tutorials exactly.
Ran code in ~/Downloads folder.

```
python3 -d    
Python 3.8.9 (default, Oct 26 2021, 07:25:53) 
[Clang 13.0.0 (clang-1300.0.29.30)] on darwin
```

Discussion:

Patch:
diff --git a/changes/668.bugfix.rst b/changes/668.bugfix.rst
new file mode 100644
index 00000000..300feb98
--- /dev/null
+++ b/changes/668.bugfix.rst
@@ -0,0 +1,1 @@
+Xcode version checks are now more robust.
diff --git a/setup.cfg b/setup.cfg
index bbe517ad..8052b217 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -116,6 +116,7 @@ exclude=\
     local/*,\
     docs/*,\
     build/*,\
+    tests/apps/*,\
     .eggs/*,\
     .tox/*
 max-complexity = 10
diff --git a/src/briefcase/integrations/xcode.py b/src/briefcase/integrations/xcode.py
index 8ea1f1e8..6c50422d 100644
--- a/src/briefcase/integrations/xcode.py
+++ b/src/briefcase/integrations/xcode.py
@@ -174,16 +174,17 @@ Re-run Briefcase once that installation is complete.
         )
 
         if min_version is not None:
-            if output.startswith('Xcode '):
+            # Look for a line in the output that reads "Xcode X.Y.Z"
+            version_lines = [line for line in output.split('\n') if line.startswith('Xcode ')]
+            if version_lines:
                 try:
-                    # Split content up to the first \n
-                    # then split the content after the first space
+                    # Split the content after the first space
                     # and split that content on the dots.
                     # Append 0's to fill any gaps caused by
                     # version numbers that don't have a minor version.
                     version = tuple(
                         int(v)
-                        for v in output.split('\n')[0].split(' ')[1].split('.')
+                        for v in version_lines[0].split(' ')[1].split('.')
                     ) + (0, 0)
 
                     if version < min_version:


Test patch:
diff --git a/tests/integrations/xcode/test_ensure_xcode_is_installed.py b/tests/integrations/xcode/test_ensure_xcode_is_installed.py
index 181625fe..f82de173 100644
--- a/tests/integrations/xcode/test_ensure_xcode_is_installed.py
+++ b/tests/integrations/xcode/test_ensure_xcode_is_installed.py
@@ -26,9 +26,7 @@ def test_not_installed(tmp_path):
 
     # Test a location where Xcode *won't* be installed
     with pytest.raises(BriefcaseCommandError):
-        ensure_xcode_is_installed(
-            command,
-        )
+        ensure_xcode_is_installed(command)
 
 
 def test_not_installed_hardcoded_path(tmp_path):
@@ -113,6 +111,32 @@ def test_installed_no_minimum_version(xcode):
     )
 
 
+def test_installed_extra_output(capsys, xcode):
+    "If Xcode but outputs extra content, the check is still satisfied."
+    # This specific output was seen in the wild with Xcode 13.2.1; see #668
+    command = mock.MagicMock()
+    command.subprocess.check_output.return_value = '\n'.join([
+        "objc[86306]: Class AMSupportURLConnectionDelegate is implemented in both /usr/lib/libauthinstall.dylib (0x20d17ab90) and /Library/Apple/System/Library/PrivateFrameworks/MobileDevice.framework/Versions/A/MobileDevice (0x1084b82c8). One of the two will be used. Which one is undefined."  # noqa: E501
+        "objc[86306]: Class AMSupportURLSession is implemented in both /usr/lib/libauthinstall.dylib (0x20d17abe0) and /Library/Apple/System/Library/PrivateFrameworks/MobileDevice.framework/Versions/A/MobileDevice (0x1084b8318). One of the two will be used. Which one is undefined.",  # noqa: E501
+        "Xcode 13.2.1",
+        "Build version 13C100",
+    ])
+
+    # Check passes without an error.
+    ensure_xcode_is_installed(command, xcode_location=xcode, min_version=(11, 1))
+
+    # xcode-select was invoked
+    command.subprocess.check_output.assert_called_once_with(
+        ['xcodebuild', '-version'],
+        stderr=subprocess.STDOUT,
+        universal_newlines=True,
+    )
+
+    # No warning generated.
+    out = capsys.readouterr().out
+    assert "WARNING" not in out
+
+
 @pytest.mark.parametrize(
     'min_version, version',
     [