DMG files are containers for apps in macOS. You open them, drag the app to your Applications folder, and then eject them, saving you the hassle of the dreaded “Install Wizard” of most Windows apps.
After lots of research, I've come up with this answer, and I'm hereby putting it here as an answer for my own question, for reference:
Make sure that "Enable access for assistive devices" is checked in System Preferences>>Universal Access. It is required for the AppleScript to work. You may have to reboot after this change (it doesn't work otherwise on Mac OS X Server 10.4).
Create a R/W DMG. It must be larger than the result will be. In this example, the bash variable "size" contains the size in Kb and the contents of the folder in the "source" bash variable will be copied into the DMG:
hdiutil create -srcfolder "${source}" -volname "${title}" -fs HFS+ \
-fsargs "-c c=64,a=16,e=16" -format UDRW -size ${size}k pack.temp.dmg
Mount the disk image, and store the device name (you might want to use sleep for a few seconds after this operation):
device=$(hdiutil attach -readwrite -noverify -noautoopen "pack.temp.dmg" | \
egrep '^/dev/' | sed 1q | awk '{print $1}')
Store the background picture (in PNG format) in a folder called ".background" in the DMG, and store its name in the "backgroundPictureName" variable.
Use AppleScript to set the visual styles (name of .app must be in bash variable "applicationName", use variables for the other properties as needed):
echo '
tell application "Finder"
tell disk "'${title}'"
open
set current view of container window to icon view
set toolbar visible of container window to false
set statusbar visible of container window to false
set the bounds of container window to {400, 100, 885, 430}
set theViewOptions to the icon view options of container window
set arrangement of theViewOptions to not arranged
set icon size of theViewOptions to 72
set background picture of theViewOptions to file ".background:'${backgroundPictureName}'"
make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"}
set position of item "'${applicationName}'" of container window to {100, 100}
set position of item "Applications" of container window to {375, 100}
update without registering applications
delay 5
close
end tell
end tell
' | osascript
Finialize the DMG by setting permissions properly, compressing and releasing it:
chmod -Rf go-w /Volumes/"${title}"
sync
sync
hdiutil detach ${device}
hdiutil convert "/pack.temp.dmg" -format UDZO -imagekey zlib-level=9 -o "${finalDMGName}"
rm -f /pack.temp.dmg
On Snow Leopard, the above applescript will not set the icon position correctly - it seems to be a Snow Leopard bug. One workaround is to simply call close/open after setting the icons, i.e.:
..
set position of item "'${applicationName}'" of container window to {100, 100}
set position of item "Applications" of container window to {375, 100}
close
open
There's a little Bash script called create-dmg that builds fancy DMGs with custom backgrounds, custom icon positioning and volume name.
I've built it many years ago for the company that I ran at the time; it survives on other people's contribution since then, and reportedly works well.
There's also node-appdmg which looks like a more modern and active effort based on Node.js; check it out as well.
Don't go there. As a long term Mac developer, I can assure you, no solution is really working well. I tried so many solutions, but they are all not too good. I think the problem is that Apple does not really document the meta data format for the necessary data.
Here's how I'm doing it for a long time, very successfully:
Create a new DMG, writeable(!), big enough to hold the expected binary and extra files like readme (sparse might work).
Mount the DMG and give it a layout manually in Finder or with whatever tools suits you for doing that. The background image is usually an image we put into a hidden folder (".something") on the DMG. Put a copy of your app there (any version, even outdated one will do). Copy other files (aliases, readme, etc.) you want there, again, outdated versions will do just fine. Make sure icons have the right sizes and positions (IOW, layout the DMG the way you want it to be).
Unmount the DMG again, all settings should be stored by now.
Write a create DMG script, that works as follows:
This method may not sound optimal, but trust me, it works really well in practice. You can put the original DMG (DMG template) even under version control (e.g. SVN), so if you ever accidentally change/destroy it, you can just go back to a revision where it was still okay. You can add the DMG template to your Xcode project, together with all other files that belong onto the DMG (readme, URL file, background image), all under version control and then create a target (e.g. external target named "Create DMG") and there run the DMG script of above and add your old main target as dependent target. You can access files in the Xcode tree using ${SRCROOT} in the script (is always the source root of your product) and you can access build products by using ${BUILT_PRODUCTS_DIR} (is always the directory where Xcode creates the build results).
Result: Actually Xcode can produce the DMG at the end of the build. A DMG that is ready to release. Not only you can create a release DMG pretty easy that way, you can actually do so in an automated process (on a headless server if you like), using xcodebuild from command line (automated nightly builds for example).
Bringing this question up to date by providing this answer.
appdmg
is a simple, easy-to-use, open-source command line program that creates dmg-files from a simple json specification. Take a look at the readme at the official website:
https://github.com/LinusU/node-appdmg
Quick example:
Install appdmg
npm install -g appdmg
Write a json file (spec.json
)
{
"title": "Test Title",
"background": "background.png",
"icon-size": 80,
"contents": [
{ "x": 192, "y": 344, "type": "file", "path": "TestApp.app" },
{ "x": 448, "y": 344, "type": "link", "path": "/Applications" }
]
}
Run program
appdmg spec.json test.dmg
(disclaimer. I'm the creator of appdmg)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With