Deploying BusyContacts via MDM or Scripted Installation
BusyContacts does not currently support direct MDM-based licensing for App Store subscriptions, due to limitations imposed by Apple. The Mac App Store is designed around individual iCloud-based subscriptions, which unfortunately do not support business-wide deployments under a single MDM license.
For organizations and IT admins who wish to manage multiple installations of BusyContacts across devices, we recommend using our direct license version—available from our website—which allows volume purchases (e.g., a 5-seat license) and supports custom deployment workflows.
Benefits of our Direct Version vs. App Store
For more details, please visit the licensing page as we have given a detailed comparison there.
Essentially, our direct version allows you to:
- Purchase multi-seat licenses with 18 months of updates included.
- Deploy BusyContacts manually or via scripts.
- Register and activate using a license key
- Optional Upgrades
Managed Installation on a Single Machine
You can manually install and activate BusyContacts on any Mac using the following steps:
1. Download the latest DMG
2. Mount the DMG
Open Terminal and run:
hdiutil attach /path/to/BusyContacts.dmg
This command will mount the DMG file as a volume on your system. Take note of the mount point displayed in the command output (e.g., /Volumes/BusyContacts).
3. Copy BusyContacts to Applications
cp -R /Volumes/BusyContacts/BusyContacts.app /Applications/
4. Register BusyContacts with a License Key
You can register BusyContacts by opening a special URL with your license key:
open "busycontacts://register/YOUR-LICENSE-KEY-HERE"
Replace YOUR-LICENSE-KEY-HERE with your actual license key. This will silently register the installed copy in the background.
Sample Deployment Script for Automation
For automating this across multiple machines, here’s a sample Bash script:
This script can be adapted for deployment tools like Jamf, Munki, or custom shell workflows across managed Macs.
#!/bin/bash
# --- Configuration ---
BASE_URL="https://www.busymac.com/download" # Base URL for downloads
DMG_NAME="BusyContacts.dmg" # Base name for the downloaded file and in URL
DMG_URL="$BASE_URL/$DMG_NAME" # Construct the full download URL
DMG_PATH="/tmp/$DMG_NAME" # Full path for the downloaded file
APP_NAME="BusyContacts.app" # Name of the application bundle inside the DMG
LICENSE_KEY="YOUR-LICENSE-KEY-HERE" # Replace with actual license key
# --- End Configuration ---
# Variable to store the determined mount point
MOUNT_POINT=""
# Function for cleanup actions
cleanup() {
echo "--- Cleaning up ---"
# Attempt to detach using the determined mount point, if available and mounted
if [ -n "$MOUNT_POINT" ] && hdiutil info | grep -q -F "$MOUNT_POINT"; then
echo "Unmounting volume at $MOUNT_POINT..."
hdiutil detach "$MOUNT_POINT" -force > /dev/null 2>&1
fi
# Remove the downloaded DMG file
if [ -f "$DMG_PATH" ]; then
echo "Removing downloaded DMG at $DMG_PATH..."
rm "$DMG_PATH"
fi
echo "Cleanup finished."
}
trap cleanup EXIT
# --- Main Script ---
echo "Starting BusyContacts installation script..."
# Check for xmllint availability
if ! command -v xmllint &> /dev/null; then
echo "Error: xmllint command not found. Install via: brew install libxml2" >&2
exit 1
fi
# Download BusyContacts DMG
echo "Downloading $DMG_URL to $DMG_PATH..."
if ! curl --fail -L -o "$DMG_PATH" "$DMG_URL"; then
echo "Error: Failed to download DMG from $DMG_URL." >&2
exit 1
fi
echo "Download complete."
# Mount the DMG and capture the output plist
echo "Mounting DMG: $DMG_PATH..."
MOUNT_INFO_PLIST=$(hdiutil attach "$DMG_PATH" -nobrowse -noverify -plist)
ATTACH_STATUS=$? # Capture exit status of hdiutil attach
if [ $ATTACH_STATUS -ne 0 ]; then
echo "Error: Failed to mount DMG. hdiutil exited with status $ATTACH_STATUS." >&2
exit 1
fi
# Parse the plist output using plutil and xmllint to find the mount point
echo "Parsing mount point information..."
# Convert plist to XML, pipe to xmllint, use XPath to extract the string value
# following the 'mount-point' key. Suppress stderr from plutil.
MOUNT_POINT=$(echo "$MOUNT_INFO_PLIST" | plutil -convert xml1 -o - - 2>/dev/null | \
xmllint --xpath 'string(//key[.="mount-point"]/following-sibling::string[1])' - 2>/dev/null)
PARSE_STATUS=$? # Capture exit status of the command pipeline
if [ $PARSE_STATUS -ne 0 ]; then
echo "Error: Failed to parse mount point using xmllint (exit status $PARSE_STATUS)." >&2
# Attempt to detach using the DMG path as a fallback
hdiutil detach "$DMG_PATH" -force > /dev/null 2>&1
exit 1
fi
# Validate that we found a mount point
if [ -z "$MOUNT_POINT" ]; then
echo "Error: Could not determine mount point from hdiutil output (xmllint parsing failed to find it)." >&2
# Attempt to detach using the DMG path as a fallback
hdiutil detach "$DMG_PATH" -force > /dev/null 2>&1
exit 1
fi
echo "DMG mounted successfully at: $MOUNT_POINT"
# Define the source path for the application
SOURCE_APP_PATH="$MOUNT_POINT/$APP_NAME"
# Check if the application exists at the expected path within the mounted volume
if [ ! -d "$SOURCE_APP_PATH" ]; then
echo "Error: Application '$APP_NAME' not found at '$SOURCE_APP_PATH'." >&2
exit 1
fi
echo "Located application at: $SOURCE_APP_PATH"
# Copy the app to /Applications
echo "Copying $APP_NAME to /Applications/ ..."
if ! cp -R "$SOURCE_APP_PATH" /Applications/; then
echo "Error: Failed to copy '$APP_NAME' to /Applications/." >&2
exit 1
fi
echo "Application copied successfully."
# Register the app using the URL scheme
echo "Attempting to register the application..."
# Add a small delay before trying to register, sometimes needed for the system
# to recognize the newly copied app and its URL scheme handler.
sleep 2
if ! open -g "busycontacts://register/$LICENSE_KEY"; then
echo "Registration failed."
exit 1
fi
echo "Registration command sent."
# Unmounting and cleanup will be handled by the EXIT trap
echo "BusyContacts installation script completed successfully."
# Explicitly exit successfully, triggering the cleanup trap
exit 0