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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(ios): add scripts to upload dsyms #1823

Merged
merged 1 commit into from
Feb 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions ios/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* [Self host compatibility](#self-host-compatibility)
* [Quick reference](#quick-reference)
* [Getting started](#getting-started)
* [Crash Reporting](#crash-reporting)
* [Custom events](#custom-events)
* [Screen view](#screen-view)
* [Features](#features)
Expand Down Expand Up @@ -92,6 +93,29 @@ Reopen the app and check the Measure dashboard—you should see the crash report

🎉 Congratulations! You have successfully integrated Measure into your app!

# Crash Reporting

MeasureSDK automatically detects and exports crashes. To symbolicate these crashes, DSYM files need to be uploaded to the server. You can upload DSYM files using a standalone shell script or via Xcode’s Build Phases.

## Using Shell Script

Run the `upload_dsyms.sh` script to manually upload DSYM files after building your app.

```sh
sh upload_dsyms.sh <path_to_ipa> <path_to_dsym_folder> <api_url> <api_key>
```

## Using Build Phases

Add the `upload_dsym_build_phases.sh` script as a **New Run Script Phase** in Xcode to upload DSYM files automatically.

```sh
sh "${SRCROOT}/path/to/upload_dsym_build_phases.sh" <api_url> <api_key>
```

> [!CAUTION]
> If you are using Build Phases to upload DSYMs make sure to **upload DSYMs only for release builds**.

# Custom Events

Custom events provide more context on top of automatically collected events. They provide the context specific to the app to debug issues and analyze impact.
Expand Down
106 changes: 106 additions & 0 deletions ios/Scripts/upload_dsym_build_phases.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#!/bin/bash

# Ensure script is called with api_url and api_key parameters
if [ "$#" -ne 2 ]; then
echo "Usage: $0 <api_url> <api_key>"
exit 1
fi

# Assign parameters
api_url="$1"
api_key="$2"

# Set hardcoded values
MAPPING_TYPE="dsym"
BUILD_TYPE="ipa"

# Collect version name and version code from the Info.plist
INFO_PLIST="${TARGET_BUILD_DIR}/${INFOPLIST_PATH}"
VERSION_NAME=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "$INFO_PLIST" 2>/dev/null)
VERSION_CODE=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$INFO_PLIST" 2>/dev/null)

# Path to the app bundle
APP_BUNDLE_PATH="${TARGET_BUILD_DIR}/${FULL_PRODUCT_NAME}"

# Print key paths
echo "TARGET_BUILD_DIR=${TARGET_BUILD_DIR}"
echo "FULL_PRODUCT_NAME=${FULL_PRODUCT_NAME}"
echo "APP_BUNDLE_PATH=${APP_BUNDLE_PATH}"
echo "INFO_PLIST=${INFO_PLIST}"

# Ensure app bundle exists before proceeding
if [ ! -d "$APP_BUNDLE_PATH" ]; then
echo "Error: App bundle not found at $APP_BUNDLE_PATH"
exit 1
fi

# Calculate build size using `du` (disk usage)
BUILD_SIZE=$(du -sk "$APP_BUNDLE_PATH" | awk '{print $1}')
BUILD_SIZE=$((BUILD_SIZE * 1024)) # Convert kilobytes to bytes

# Locate all dSYM files in the build directory
echo "Searching for dSYM files in ${DWARF_DSYM_FOLDER_PATH}"
DSYM_FILES=($(find "${DWARF_DSYM_FOLDER_PATH}" -name "*.dSYM" -type d))

if [ ${#DSYM_FILES[@]} -eq 0 ]; then
echo "Error: No dSYM files found in ${DWARF_DSYM_FOLDER_PATH}"
exit 1
fi

# Log found dSYM files with full paths
echo "Found dSYM files:"
for DSYM in "${DSYM_FILES[@]}"; do
FULL_DSYM_PATH=$(realpath "$DSYM") # Get full absolute path
echo " - $FULL_DSYM_PATH"
done

# Compress dSYM files to .tgz format
TGZ_FILES=()
for DSYM in "${DSYM_FILES[@]}"; do
TGZ_FILE="$(basename "$DSYM").tgz"
echo "Compressing $DSYM to $(pwd)/$TGZ_FILE"

tar -czf "$TGZ_FILE" -C "$(dirname "$DSYM")" "$(basename "$DSYM")"

if [ -f "$TGZ_FILE" ]; then
echo "Successfully created $(pwd)/$TGZ_FILE"
TGZ_FILES+=("$(pwd)/$TGZ_FILE")
else
echo "Error: Failed to create $(pwd)/$TGZ_FILE"
exit 1
fi
done

# Print generated .tgz files
echo "Generated dSYM archives:"
for TGZ in "${TGZ_FILES[@]}"; do
echo " - $TGZ"
done

# Construct the curl command
CURL_COMMAND="curl --request PUT \
--url $api_url/builds \
--header 'Authorization: Bearer $api_key' \
--header 'Content-Type: multipart/form-data' \
--form version_name=$VERSION_NAME \
--form version_code=$VERSION_CODE \
--form mapping_type=$MAPPING_TYPE \
--form build_size=$BUILD_SIZE \
--form build_type=$BUILD_TYPE \
--form app_unique_id=sh.measure.DemoApp"

# Attach each dSYM .tgz file
for TGZ in "${TGZ_FILES[@]}"; do
CURL_COMMAND="$CURL_COMMAND --form mapping_file=@$TGZ"
done

# Execute the curl command
eval "$CURL_COMMAND"

# Clean up generated .tgz files
for TGZ in "${TGZ_FILES[@]}"; do
echo "Removing $TGZ"
rm -f "$TGZ"
done

echo "Script execution completed."
105 changes: 105 additions & 0 deletions ios/Scripts/upload_dsyms.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/bin/bash

# Check if required parameters are provided
if [ "$#" -ne 4 ]; then
echo "Usage: $0 <path_to_ipa> <path_to_dsym_folder> <api_url> <api_key>"
exit 1
fi

IPA_PATH=$1
DSYM_FOLDER=$2
API_URL=$3
API_KEY=$4

SCRIPT_DIR=$(pwd) # Get the directory where the script is running

# Validate the IPA file
if [ ! -f "$IPA_PATH" ]; then
echo "Error: IPA file not found at $IPA_PATH"
exit 1
fi

# Validate the dSYM folder
if [ ! -d "$DSYM_FOLDER" ]; then
echo "Error: dSYM folder not found at $DSYM_FOLDER"
exit 1
fi

# Unzip IPA file
TMP_DIR=$(mktemp -d)
unzip -q "$IPA_PATH" -d "$TMP_DIR"

echo "Contents of unzipped IPA:"
ls "$TMP_DIR"

# Locate the main app's Info.plist
INFO_PLIST=$(find "$TMP_DIR" -path "*/Payload/*.app/Info.plist" -type f | head -n 1)

if [ -z "$INFO_PLIST" ]; then
echo "Error: Info.plist not found in the IPA"
rm -rf "$TMP_DIR"
exit 1
fi

echo "Correct Info.plist found at: $INFO_PLIST"

# Extract version information
VERSION_NAME=$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "$INFO_PLIST" 2>/dev/null)
VERSION_CODE=$(/usr/libexec/PlistBuddy -c "Print :CFBundleVersion" "$INFO_PLIST" 2>/dev/null)
APP_UNIQUE_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$INFO_PLIST" 2>/dev/null)

# Handle missing version information gracefully
[ -z "$VERSION_NAME" ] && VERSION_NAME="Unknown"
[ -z "$VERSION_CODE" ] && VERSION_CODE="Unknown"
[ -z "$APP_UNIQUE_ID" ] && APP_UNIQUE_ID="Unknown"

echo "Extracted VERSION_NAME=$VERSION_NAME"
echo "Extracted VERSION_CODE=$VERSION_CODE"
echo "Extracted APP_UNIQUE_ID=$APP_UNIQUE_ID"

# Create .tgz archives for all dSYMs in the script's directory
DSYM_TGZ_FILES=()
for DSYM_DIR in "$DSYM_FOLDER"/*.dSYM; do
if [ -d "$DSYM_DIR" ]; then
DSYM_TGZ="$SCRIPT_DIR/$(basename "$DSYM_DIR").tgz"
tar -czf "$DSYM_TGZ" -C "$DSYM_FOLDER" "$(basename "$DSYM_DIR")"
DSYM_TGZ_FILES+=("$DSYM_TGZ")
echo "Created dSYM archive at $DSYM_TGZ"
fi
done

if [ "${#DSYM_TGZ_FILES[@]}" -eq 0 ]; then
echo "Error: No dSYM files found in the folder"
rm -rf "$TMP_DIR"
exit 1
fi

# Calculate build size
BUILD_SIZE=$(stat -f%z "$IPA_PATH")
BUILD_TYPE="ipa"

# Construct the curl command
CURL_COMMAND="curl --request PUT \
--url $API_URL/builds \
--header 'Authorization: Bearer $API_KEY' \
--form version_name=$VERSION_NAME \
--form version_code=$VERSION_CODE \
--form mapping_type=dsym \
--form build_size=$BUILD_SIZE \
--form build_type=$BUILD_TYPE \
--form app_unique_id=$APP_UNIQUE_ID"

# Add each dSYM .tgz file to the curl command
for DSYM_TGZ in "${DSYM_TGZ_FILES[@]}"; do
CURL_COMMAND="$CURL_COMMAND --form mapping_file=@$DSYM_TGZ"
done

# Execute the curl command
echo "Executing curl command..."
eval "$CURL_COMMAND"

# Clean up
rm -rf "$TMP_DIR"
for DSYM_TGZ in "${DSYM_TGZ_FILES[@]}"; do
rm -f "$DSYM_TGZ"
done
Loading