Uploading dSYM to Firebase Crashlytics via Xcode Cloud

Hello everyone, in this article I would like to share my experience on how our team faced the difficulties of uploading dSYM to Firebase Crashlytics, and how we solved these difficulties. It is important to say a few words about our stack: all dependencies are installed through the Swift Package Manager, we use Xcode 14, and we use Xcode Cloud as a CI CD from the first days of its release.

background

The whole story began with a message from CTO, in which he asked why, after the last release in the App Store, he received a lot of letters of this kind in the mail:

Messages about lost dSYM files.
Messages about lost dSYM files.

However, in addition to CTO, all developers from different teams that are in our Firebase received such letters. In order to somehow quickly correct the situation and stop clogging up my colleagues’ mail, I decided to turn off email notifications about this error while studying the problem. Then I learned that each member of Firebase’a must independently disable these notifications for themselves.

Disable notifications about lost dSYM files
Disable notifications about lost dSYM files

It seems that a large number of iOS developers have encountered lost dSYM files sooner or later, and, as a rule, it all comes down to double-checking the script in the Build phase or in CI and manually loading the missing dSYM files. At first glance, everything was fine with the script, so I decided to just download the dSYM files from the App Store Connect’a manually and upload them to Firebase Crashlytics, but then a nuance arose – I did not find these files for the latest builds.

Xcode 14 and Bitcode

Shortly before the release, we upgraded to Xcode 14 with the entire iOS team, and also transferred the IDE version to the same one in our release workflow in Xcode Cloud. Obviously, it was necessary to dig somewhere there, and I decided to take a closer look at the list of what has changed in the latest version of Xcode. Here is what I found in release notes Xcode 14:

depressions

Starting with Xcode 14, bitcode is no longer required for watchOS and tvOS applications, and the App Store no longer accepts bitcode submissions from Xcode 14.

Xcode no longer builds bitcode by default and generates a warning message if a project explicitly enables bitcode: “Building with bitcode is deprecated. Please update your project and/or target settings to disable bitcode.” The capability to build with bitcode will be removed in a future Xcode release. IPAs that contain bitcode will have the bitcode stripped before being submitted to the App Store. Debug symbols can only be downloaded from App Store Connect / TestFlight for existing bitcode submissions and are no longer available for submissions made with Xcode 14. (86118779)

And yes, indeed, I went to App Store Connect and saw that in the Build metadata for the build built on the 13th version, there are dSYM files, but for the build that was built on the latest, 14th version, they are not.

Build metadata for Xcode 13 and Xcode 14 builds
Build metadata for Xcode 13 and Xcode 14 builds

Where and how to download dSYM

In order to download the dSYM for assembly from Xcode Cloud, I went to the assembly I was interested in in the Xcode Cloud panel, and then, in the Artifacts section, I downloaded the iOS archive, which is .xcarchive file. dSYM files I found when I opened .xcarchive file through Show Package Contents and moved to the dSYM folder. I then successfully uploaded it all to Firebase Crashlytics manually, but the last and most interesting part is automating the upload process.

Download iOS archive of the assembly of interest from Xcode Cloud artifacts
Download iOS archive of the assembly of interest from Xcode Cloud artifacts

Automating dSYM Upload to Xcode Cloud

In order to write a script that would automate the process of loading dSYM into a crashlit, it was necessary to understand how to embed this logic into our CI workflow. As you know, in Xcode Cloud there are 3 types of scripts, each of which will be executed at a certain point in time. Details about custom builds scripts, and how to add them to your workflow are well described in documentation.

Types of scripts in Xcode Cloud
Types of scripts in Xcode Cloud

In our case, we are interested in post-xcodebuild script to be executed after a successful build. Next, we need to understand how we can access upload-symbols script from Firebase (documentation), which will unload our dSYM. In Xcode Cloud, there is a set of some variables that we can refer to in any of the scripts – we are talking about Environment variables. Here I will not analyze each of the variables, they are, however, perfectly described in the documentation itself. For our task, we need only two:

  • CI_DERIVED_DATA_PATH – this is exactly the directory, delving into which you can find upload-symbols script. * You can find a similar directory in your local /Library/Developer/Xcode/DerivedData/Your build;

  • CI_ARCHIVE_PATH is the way to .xcarchive the file I mentioned above. This is the same place where we will pick up fresh dSYM files.

Our script should do just one thing: run upload-symbols script with correct arguments (valid path to .plist and dSYM). That’s what I did:

#!/bin/sh
set -e
if [[ -n $CI_ARCHIVE_PATH ]];
then
    echo "Archive path is available. Let's run dSYMs uploading script"
    # Move up to parent directory
    cd ..
    # Debug
    echo "Derived data path: $CI_DERIVED_DATA_PATH"
    echo "Archive path: $CI_ARCHIVE_PATH"
    # Crashlytics dSYMs script
    $CI_DERIVED_DATA_PATH/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/upload-symbols -gsp /GoogleService-Info.plist -p ios $CI_ARCHIVE_PATH/dSYMs
else
    echo "Archive path isn't available. Unable to run dSYMs uploading script."
fi

However, that’s all, let’s run the workflow with this script and look at the logs. The script is executed successfully and dSYM files are loaded into the crashlit.

Logs from Xcode cloud
Logs from Xcode cloud

Additionally

If you encounter a similar warning, then pay attention to the information from documentation Apple:

Important

Xcode Cloud uses zsh as its default Unix shell. as a best practice, always include a shebang in the first line of your custom build script; example #!/bin/sh.

Be sure to change the type of your file to executable, this can be done with the command:

chmod +x ci_post_xcodebuild.sh

That’s all, our script is ready. Thank you for your attention and I will be glad to answer your questions.

Similar Posts

2 Comments

  1. Since nothing depends on this script, is there a way execute the symbols upload in background? So we can continue with other Xcode Cloud tasks immediately?

  2. In this line…

    “`
    $CI_DERIVED_DATA_PATH/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/upload-symbols -gsp /GoogleService-Info.plist -p ios $CI_ARCHIVE_PATH/dSYMs
    “`

    Where is the `GoogleService-Info.plist` relative to?

    I can’t seem to get it to find the file trying multiple different locations.

    Thanks

Leave a Reply

Your email address will not be published. Required fields are marked *