如何使用命令行工具为Mac OS X创build漂亮的DMG?

我需要为Mac应用程序创build一个很好的安装程序。 我希望它是一个磁盘映像(DMG),具有预定义的大小,布局和背景图像。

我需要在脚本中以编程的方式执行此操作,以便集成到现有的构build系统中(实际上更多的是构build包系统,因为它只创build安装程序,构build是分开完成的)。

我已经使用“hdiutil”完成了DMG的创build,但我还没有发现如何制作图标布局和指定背景位图。

经过大量的研究,我已经提出了这个答案,我现在把它作为我自己的问题的答案,作为参考:

  1. 确保在“系统预置”>>“通用访问”中选中“启用访问辅助设备”。 AppleScript是必需的。 更改后可能必须重新启动(在Mac OS X Server 10.4上不起作用)。

  2. 创build一个R / W DMG。 它必须大于结果。 在这个例子中,bashvariables“size”包含了Kb的大小,而“source”bashvariables中的文件夹内容将被复制到DMG中:

    hdiutil create -srcfolder "${source}" -volname "${title}" -fs HFS+ \ -fsargs "-cc=64,a=16,e=16" -format UDRW -size ${size}k pack.temp.dmg 
  3. 装载磁盘映像,并存储设备名称(在此操作之后,您可能需要使用几秒钟的睡眠时间):

     device=$(hdiutil attach -readwrite -noverify -noautoopen "pack.temp.dmg" | \ egrep '^/dev/' | sed 1q | awk '{print $1}') 
  4. 将背景图片(PNG格式)存储在DMG中名为“.background”的文件夹中,并将其名称存储在“backgroundPictureName”variables中。

  5. 使用AppleScript设置视觉样式(.app的名称必须在bashvariables“applicationName”中,根据需要使用其他属性的variables):

     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 
  6. 通过正确设置权限来完成DMG的压缩和释放:

     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 

在雪豹上面的applescript不会正确设置图标的位置 – 这似乎是一个雪豹的bug。 一种解决方法是在设置图标后简单地调用close / open,即:

 .. set position of item "'${applicationName}'" of container window to {100, 100} set position of item "Applications" of container window to {375, 100} close open 

有一个名为create-dmg的小Bash脚本,它可以构build出带有自定义背景,自定义图标定位和卷名称的奇特DMG。

多年前,我为我当时所经营的公司build立了它; 自那时以来一直活在别人的贡献之下,据说效果不错。

还有node-appdmg ,看起来像基于Node.js的更现代化和积极的努力; 检查出来以及。

不要去那里。 作为一名长期的Mac开发人员,我可以向你保证,没有任何解决scheme能够很好地工作。 我尝试了很多解决scheme,但都不太好。 我认为问题在于,苹果公司并没有真正logging必要数据的元数据格式。

以下是我很长一段时间的工作,非常成功:

  1. 创build一个新的DMG,可写(!),足够大,以容纳预期的二进制和额外的文件,如自述(稀疏可能工作)。

  2. 安装DMG并在Finder中手动设置布局,或者使用适合您的任何工具(请参见位于底部的FileStorm链接以获取更好的工具)。 背景图片通常是我们放入DMG的隐藏文件夹(“.something”)的图片。 把你的应用程序的副本(任何版本,甚至过时的人会做)。 复制你想要的其他文件(别名,自述文件等),再次,过时的版本将会很好。 确保图标的尺寸和位置正确(IOW,按您希望的方式布置DMG)。

  3. 再次卸载DMG,现在所有的设置都应该被保存。

  4. 编写一个创buildDMG脚本,其工作原理如下:

    • 它复制了DMG,所以原来的那个再也不会碰到了。
    • 它挂载副本。
    • 它取代了所有最新的文件(比如最新的应用程序)。 你可以简单地在命令行上使用mv或者ditto 。 注意,当你像这样replace文件时,图标将保持不变,位置将保持不变,除了文件(或目录)内容保持不变(至less与我们通常用于该任务的文件相同) 。 你当然也可以用另一个replace背景图片(只要确保它具有相同的尺寸)。
    • replace文件后,使脚本再次卸载DMG副本。
    • 最后,调用hdiutil将可写,转换为压缩(而不是可写)的DMG。

这种方法听起来不是最佳的,但相信我,它在实践中效果很好。 你甚至可以在版本控制(例如SVN)下放置原来的DMG(DMG模板),所以如果你不小心改变/销毁它,你可以回到一个修改版本。 您可以将DMG模板与属于DMG(自述文件,URL文件,背景图像)的所有其他文件(全部在版本控制下)一起添加到您的Xcode项目中,然后创build目标(例如名为“创buildDMG”的外部目标)并运行上面的DMG脚本,并将您的旧主目标添加为依赖目标。 您可以使用脚本中的$ {SRCROOT}来访问Xcode树中的文件(始终是产品的源代码),您可以使用$ {BUILT_PRODUCTS_DIR}访问构build产品(始终是Xcode创build构build结果的目录) 。

结果:实际上Xcode可以在构build结束时生成DMG。 准备释放的DMG。 不仅如此,您可以非常容易地创build一个DMG,您可以在自动化过程中(如果您喜欢,可以在无头服务器上)使用命令行中的xcodebuild(例如,自动构build夜间)。

关于模板的初始布局, FileStorm是一个很好的工具。 这是商业的,但非常强大,易于使用。 正常版本不到20美元,所以真的很实惠。 也许可以自动化FileStorm创build一个DMG(例如通过AppleScript),从来没有尝试过,但一旦你find了完美的模板DMG,它很容易更新每个版本。

通过提供这个答案来回答这个问题。

appdmg是一个简单易用的开源命令行程序,可以从简单的json规范创builddmg文件。 看看官方网站上的自述文件:

https://github.com/LinusU/node-appdmg

快速示例:

  1. 安装appdmg

     npm install -g appdmg 
  2. 写一个json文件( 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" } ] } 
  3. 运行程序

     appdmg spec.json test.dmg 

(免责声明我是appdmg的创造者)

对于那些对这个主题感兴趣的人,我应该提到我如何创buildDMG:

 hdiutil create XXX.dmg -volname "YYY" -fs HFS+ -srcfolder "ZZZ" 

哪里

 XXX == disk image file name (duh!) YYY == window title displayed when DMG is opened ZZZ == Path to a folder containing the files that will be copied into the DMG 

我的应用程序DropDMG是一种用背景图片,图标布局,自定义音量图标和软件许可证协议创build磁盘映像的简单方法。 它可以通过“dropdmg”命令行工具或AppleScript从构build系统进行控制。 如果需要,图片和许可证RTF文件可以存储在您的版本控制系统下。

如果你想设置自定义音量图标,然后使用下面的命令

 /*Add a drive icon*/ cp "/Volumes/customIcon.icns" "/Volumes/dmgName/.VolumeIcon.icns" /*SetFile -c icnC will change the creator of the file to icnC*/ SetFile -c icnC /<your path>/.VolumeIcon.icns 

现在创build读/写dmg

 /*to set custom icon attribute*/ SetFile -a C /Volumes/dmgName 

.DS_Store文件在Mac中存储Windows设置。 Windows设置包括图标布局,窗口背景,窗口大小等等。创build挂载的图像窗口需要.DS_Store文件来保存文件和窗口背景的排列。

一旦创build了.DS_Store文件,就可以将其复制到您创build的安装程序(DMG)中。

我还需要使用命令行方法来“编程地在脚本中”进行包装和dmg的创build。 我发现迄今为止最好的答案是从Adium项目的“发布构build框架”(参见R1)。 有一个自定义脚本(AdiumApplescriptRunner)允许您避免OSX WindowsServer GUI交互。 “osascript applescript.scpt”方法要求您以构build器身份login并从命令行vt100会话运行dmg创build。

OSX软件包pipe理系统与其他可以轻松系统地完成这项任务的Unixen相比并不那么先进。

R1: http : //hg.adium.im/adium-1.4/file/00d944a3ef16/Release

为了创build一个漂亮的DMG,你现在可以使用一些写得很好的开源代码:

  • 创build-DMG
  • 节点appdmg
  • dmgbuild

这些答案太复杂了,时代已经变了。 下面的10.9就好了,权限是正确的,它看起来不错。

从目录创build一个只读的DMG

 #!/bin/sh # create_dmg Frobulator Frobulator.dmg path/to/frobulator/dir [ 'Your Code Sign Identity' ] set -e VOLNAME="$1" DMG="$2" SRC_DIR="$3" CODESIGN_IDENTITY="$4" hdiutil create -srcfolder "$SRC_DIR" \ -volname "$VOLNAME" \ -fs HFS+ -fsargs "-cc=64,a=16,e=16" \ -format UDZO -imagekey zlib-level=9 "$DMG" if [ -n "$CODESIGN_IDENTITY" ]; then codesign -s "$CODESIGN_IDENTITY" -v "$DMG" fi 

使用图标创build只读DMG(图标types)

 #!/bin/sh # create_dmg_with_icon Frobulator Frobulator.dmg path/to/frobulator/dir path/to/someicon.icns [ 'Your Code Sign Identity' ] set -e VOLNAME="$1" DMG="$2" SRC_DIR="$3" ICON_FILE="$4" CODESIGN_IDENTITY="$5" TMP_DMG="$(mktemp -u -t XXXXXXX)" trap 'RESULT=$?; rm -f "$TMP_DMG"; exit $RESULT' INT QUIT TERM EXIT hdiutil create -srcfolder "$SRC_DIR" -volname "$VOLNAME" -fs HFS+ \ -fsargs "-cc=64,a=16,e=16" -format UDRW "$TMP_DMG" TMP_DMG="${TMP_DMG}.dmg" # because OSX appends .dmg DEVICE="$(hdiutil attach -readwrite -noautoopen "$TMP_DMG" | awk 'NR==1{print$1}')" VOLUME="$(mount | grep "$DEVICE" | sed 's/^[^ ]* on //;s/ ([^)]*)$//')" # start of DMG changes cp "$ICON_FILE" "$VOLUME/.VolumeIcon.icns" SetFile -c icnC "$VOLUME/.VolumeIcon.icns" SetFile -a C "$VOLUME" # end of DMG changes hdiutil detach "$DEVICE" hdiutil convert "$TMP_DMG" -format UDZO -imagekey zlib-level=9 -o "$DMG" if [ -n "$CODESIGN_IDENTITY" ]; then codesign -s "$CODESIGN_IDENTITY" -v "$DMG" fi 

如果还有其他事情需要发生,最简单的方法就是创buildSRC_DIR的临时副本,并在创buildDMG之前应用更改。

我刚刚写了一个新的(友好的)命令行工具来做到这一点。 它不依赖于Finder / AppleScript,或者任何(不build议使用的)Alias Manager API,并且configuration和使用都很简单。

无论如何,任何有兴趣的人都可以在PyPi上find它 ; 该文档可在“读取文档”中find 。

我终于在自己的项目中得到了这个工作(恰好在Xcode中)。 将这3个脚本添加到构build阶段将自动为您的产品创build一个漂亮而整洁的磁盘映像。 您所要做的就是构build您的项目,DMG将在您的产品文件夹中等待。

脚本1(创build临时磁盘映像):

 #!/bin/bash #Create a R/W DMG dir="$TEMP_FILES_DIR/disk" dmg="$BUILT_PRODUCTS_DIR/$PRODUCT_NAME.temp.dmg" rm -rf "$dir" mkdir "$dir" cp -R "$BUILT_PRODUCTS_DIR/$PRODUCT_NAME.app" "$dir" ln -s "/Applications" "$dir/Applications" mkdir "$dir/.background" cp "$PROJECT_DIR/$PROJECT_NAME/some_image.png" "$dir/.background" rm -f "$dmg" hdiutil create "$dmg" -srcfolder "$dir" -volname "$PRODUCT_NAME" -format UDRW #Mount the disk image, and store the device name hdiutil attach "$dmg" -noverify -noautoopen -readwrite 

脚本2(设置窗口属性脚本):

 #!/usr/bin/osascript #get the dimensions of the main window using a bash script set {width, height, scale} to words of (do shell script "system_profiler SPDisplaysDataType | awk '/Main Display: Yes/{found=1} /Resolution/{width=$2; height=$4} /Retina/{scale=($2 == \"Yes\" ? 2 : 1)} /^ {8}[^ ]+/{if(found) {exit}; scale=1} END{printf \"%d %d %d\\n\", width, height, scale}'") set x to ((width / 2) / scale) set y to ((height / 2) / scale) #get the product name using a bash script set {product_name} to words of (do shell script "printf \"%s\", $PRODUCT_NAME") set background to alias ("Volumes:"&product_name&":.background:some_image.png") tell application "Finder" tell disk product_name 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 {x, y, (x + 479), (y + 383)} set theViewOptions to the icon view options of container window set arrangement of theViewOptions to not arranged set icon size of theViewOptions to 128 set background picture of theViewOptions to background set position of item (product_name & ".app") of container window to {100, 225} set position of item "Applications" of container window to {375, 225} update without registering applications close end tell end tell 

上述的测量窗口为我的项目特别是由于我的背景图片和图标分辨率的大小; 您可能需要修改您自己的项目的这些值。

脚本3(制作最终的磁盘映像脚本):

 #!/bin/bash dir="$TEMP_FILES_DIR/disk" cp "$PROJECT_DIR/$PROJECT_NAME/some_other_image.png" "$dir/" #unmount the temp image file, then convert it to final image file sync sync hdiutil detach /Volumes/$PRODUCT_NAME rm -f "$BUILT_PRODUCTS_DIR/$PRODUCT_NAME.dmg" hdiutil convert "$BUILT_PRODUCTS_DIR/$PRODUCT_NAME.temp.dmg" -format UDZO -imagekey zlib-level=9 -o "$BUILT_PRODUCTS_DIR/$PRODUCT_NAME.dmg" rm -f "$BUILT_PRODUCTS_DIR/$PRODUCT_NAME.temp.dmg" #Change the icon of the image file sips -i "$dir/some_other_image.png" DeRez -only icns "$dir/some_other_image.png" > "$dir/tmpicns.rsrc" Rez -append "$dir/tmpicns.rsrc" -o "$BUILT_PRODUCTS_DIR/$PRODUCT_NAME.dmg" SetFile -a C "$BUILT_PRODUCTS_DIR/$PRODUCT_NAME.dmg" rm -rf "$dir" 

确保您使用的图像文件位于$ PROJECT_DIR / $ PROJECT_NAME /目录中!