Unlike Windows MSI packages that support silent installation flags, macOS .dmg files are designed for interactive GUI installation. They typically require:
- Manual mounting of the disk image
- User agreement to EULA terms
- Drag-and-drop operations or installer package execution
- Unmounting after installation
For packages containing .pkg files within the .dmg, you can use the macOS installer command:
hdiutil attach installer.dmg -nobrowse -quiet
sudo installer -pkg /Volumes/YourApp/Install.pkg -target /
hdiutil detach /Volumes/YourApp
When dealing with complex .dmg installations that include EULA acceptance:
#!/bin/bash
# Mount the DMG silently
MOUNT_POINT=$(hdiutil attach -nobrowse -noverify -noautoopen -quiet "$1" | awk -F '\t' 'END{print $3}')
# Handle different installation types
if [ -d "$MOUNT_POINT"/*.app ]; then
# Copy .app to Applications
sudo cp -R "$MOUNT_POINT"/*.app /Applications/
elif [ -f "$MOUNT_POINT"/*.pkg ]; then
# Install .pkg silently
sudo installer -pkg "$MOUNT_POINT"/*.pkg -target /
fi
# Clean up
hdiutil detach "$MOUNT_POINT" -quiet
For more complex scenarios where you need to handle EULA dialogs:
import subprocess
import os
def silent_dmg_install(dmg_path):
# Mount the DMG
mount_cmd = ['hdiutil', 'attach', '-nobrowse', '-quiet', dmg_path]
result = subprocess.run(mount_cmd, capture_output=True, text=True)
mount_point = result.stdout.split('\t')[-1].strip()
# Find and install the package
for item in os.listdir(mount_point):
if item.endswith('.pkg'):
pkg_path = os.path.join(mount_point, item)
subprocess.run(['sudo', 'installer', '-pkg', pkg_path, '-target', '/'], check=True)
break
# Unmount
subprocess.run(['hdiutil', 'detach', mount_point, '-quiet'], check=True)
For applications that use custom installers or require additional steps:
- Use AppleScript via osascript for GUI automation when absolutely necessary
- Consider repackaging as a standard .pkg for easier deployment
- Explore third-party tools like Munki or Jamf for enterprise deployment
When automating installations:
# Always verify the checksum of your DMG before installation
expected_sha="YOUR_SHA256_HERE"
actual_sha=$(shasum -a 256 yourpackage.dmg | awk '{print $1}')
if [ "$expected_sha" != "$actual_sha" ]; then
echo "Checksum verification failed!"
exit 1
fi
Unlike Windows MSI packages that support silent installation flags, macOS DMG packages typically require manual interaction through graphical dialogs. This becomes problematic when deploying software across multiple machines or in CI/CD pipelines.
A typical DMG installation flow involves:
1. Mounting the disk image
2. Accepting EULA (if present)
3. Dragging application to Applications folder
4. Optional verification
5. Unmounting the disk image
We can automate this process using several approaches:
Method 1: hdiutil + cp (Basic DMG)
For simple DMGs without EULA:
#!/bin/bash
hdiutil attach package.dmg -nobrowse -quiet
cp -R /Volumes/PackageName/Application.app /Applications/
hdiutil detach /Volumes/PackageName
Method 2: AppleScript for GUI Automation
When EULA acceptance is required:
#!/usr/bin/osascript
tell application "Finder"
open disk image "package.dmg"
delay 2
tell application "System Events"
click button "Agree" of window "License Agreement"
delay 1
drag item "Application.app" of folder "PackageName" of disk "PackageName" to folder "Applications" of startup disk
delay 2
eject disk "PackageName"
end tell
end tell
Method 3: Using expect for Terminal-based Installers
For command-line installers within DMG:
#!/usr/bin/expect
spawn hdiutil attach package.dmg
expect "agree to the terms of the software license agreement"
send "agree\r"
spawn /Volumes/PackageName/Install.app/Contents/MacOS/Install --silent
expect eof
Package Conversion
For recurring deployments, consider converting DMG to PKG:
productbuild --component Application.app /Applications output.pkg
Python Automation
Using pyobjc for more control:
import os
from AppKit import NSWorkspace
def install_dmg(dmg_path):
os.system(f'hdiutil attach -nobrowse {dmg_path}')
ws = NSWorkspace.sharedWorkspace()
ws.openFile_('/Volumes/PackageName/Application.app')
# Additional automation via Apple Events can be added here
- Use
hdiutil info
to check mount status - Implement retry logic for network DMGs
- Add checksum verification for security
Example GitHub Actions workflow:
jobs:
deploy:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- run: |
hdiutil attach Application.dmg -nobrowse
sudo cp -R /Volumes/Application/Application.app /Applications/
hdiutil detach /Volumes/Application