Previously, BrowserStack offered seamless integration with Visual Studio App Center, allowing it to fetch builds automatically without requiring manual uploads. However, since App Center was decommissioned on March 31, 2025, builds must now be uploaded directly to BrowserStack's App Automate and App Live services. This can be efficiently handled using a simple Bash script integrated within Azure Pipelines. The same script can also be adapted for use with other CI/CD tools like Jenkins.
1 Answer
steps:
- task: DownloadPipelineArtifact@2
displayName: 'Download Artifact'
inputs:
buildtype: 'current'
downloadtype: 'specific'
downloadPath: '$(System.ArtifactoryDirectory)'
targetPath: '$(System.ArtifactoryDirectory)'
- task: Bash@3
displayName: 'Copy and Upload to BrowserStack (App Live & App Automate)'
inputs:
targetType: inline
script: |
#!/bin/bash
# Define directories
SOURCE_DIR="$(System.ArtifactsDirectory)"
DEFAULT_DIR="$(System.DefaultWorkingDirectory)"
DEST_DIR="$DEFAULT_DIR/artifacts"
# BrowserStack Upload URLs
APP_LIVE_UPLOAD_URL="https://api-cloud.browserstack.com/app-live/upload"
APP_AUTOMATE_UPLOAD_URL="https://api-cloud.browserstack.com/app-automate/upload"
# Replace with your actual BrowserStack username and access key, and securely reference them using variable groups from the Azure DevOps Library.)
BROWSERSTACK_USERNAME="resfeber_JwNHAx"
BROWSERSTACK_ACCESS_KEY="Enter Your Key Here"
# Create destination directory if it doesn't exist
mkdir -p "$DEST_DIR"
# Find and copy matching APK and IPA files from both SOURCE_DIR and DEFAULT_DIR
find "$SOURCE_DIR" "$DEFAULT_DIR" -type f \( -name "*.apk or.aab" -o -name "*.ipa" \) -exec cp {} "$DEST_DIR" \;
echo "✅ Matching artifacts copied to $DEST_DIR"
# List files in the destination directory
ls -al "$DEST_DIR"
# Find the latest artifact
ARTIFACT_PATH=$(ls -t "$DEST_DIR"/*.apk or .aab "$DEST_DIR"/*.ipa 2>/dev/null | head -n 1)
# Check if an artifact was found
if [[ -z "$ARTIFACT_PATH" ]]; then
echo "❌ Error: No valid artifact found in $DEST_DIR" >&2
exit 1
fi
echo "✅ Artifact selected for upload: $ARTIFACT_PATH"
# Function to upload to BrowserStack
upload_to_browserstack() {
local UPLOAD_URL=$1
local UPLOAD_TYPE=$2
echo "🚀 Uploading to BrowserStack $UPLOAD_TYPE..."
RESPONSE=$(curl -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_ACCESS_KEY" \
-X POST "$UPLOAD_URL" \
-F "file=@$ARTIFACT_PATH")
echo "📤 Upload response: $RESPONSE"
# Extract app_url from response
APP_URL=$(echo "$RESPONSE" | jq -r '.app_url')
if [[ -n "$APP_URL" && "$APP_URL" != "null" ]]; then
echo "✅ $UPLOAD_TYPE Upload Successful!"
echo "🔗 Use this link to open the app in BrowserStack $UPLOAD_TYPE: $APP_URL"
else
echo "❌ Error: Upload to $UPLOAD_TYPE failed!" >&2
exit 1
fi
}
# Upload to both App Live and App Automate
upload_to_browserstack "$APP_LIVE_UPLOAD_URL" "App Live"
upload_to_browserstack "$APP_AUTOMATE_UPLOAD_URL" "App Automate"