Как создать красивый DMG для Mac OS X с помощью инструментов командной строки?


Мне нужно создать хороший установщик для приложения Mac. Я хочу, чтобы это был образ диска (DMG), с предопределенным размером, макетом и фоновым изображением.

Мне нужно сделать это программно в скрипте, чтобы быть интегрированным в существующую систему сборки (на самом деле это скорее пакетная система, так как она только создает инсталляторы. Сборки выполняются отдельно).

У меня уже есть создание DMG с использованием "hdiutil", но я еще не выяснил, как сделать макет значка и указать растровое изображение фона.

14 198

14 ответов:

После долгих исследований я пришел к этому ответу, и поэтому я помещаю его здесь в качестве ответа на мой собственный вопрос, Для справки:

  1. Убедитесь, что в разделе Системные настройки>>Универсальный доступ установлен флажок" Разрешить доступ для вспомогательных устройств". Это необходимо для работы AppleScript. Возможно, вам придется перезагрузиться после этого изменения (иначе это не работает на Mac OS X Server 10.4).

  2. Создайте R/W DMG. Она должна быть больше, чем результат. В этом например, переменная bash "size" содержит размер в КБ, а содержимое папки в переменной bash" source " будет скопировано в 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
    
  3. Смонтируйте образ диска и сохраните имя устройства (после выполнения этой операции можно использовать режим ожидания в течение нескольких секунд):

    device=$(hdiutil attach -readwrite -noverify -noautoopen "pack.temp.dmg" | \
             egrep '^/dev/' | sed 1q | awk '{print $1}')
    
  4. Сохраните фоновое изображение (в формате PNG) в папке под названием ".background " в DMG и сохраните его имя в переменной backgroundPictureName.

  5. Используйте AppleScript для установки визуальных стилей (имя .приложение должно быть в переменной bash "applicationName" , используйте переменные для других свойств по мере необходимости):

    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 
    

На Snow Leopard приведенный выше applescript не установит правильное положение значка - похоже, это ошибка Snow Leopard. Один обходной путь состоит в том, чтобы просто вызвать 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

Есть небольшой скрипт Bash под названиемcreate-dmg , который создает причудливые DMG с пользовательским фоном, пользовательским расположением значков и именем Тома.

Я построил его много лет назад для компании, которой управлял в то время; с тех пор он выживает за счет вклада других людей и, как сообщается, хорошо работает.

Есть такжеnode-appdmg , который выглядит как более современное и активное усилие, основанное на Node.js; проверьте это также.

Не ходи туда. Как долгосрочный разработчик Mac, я могу заверить вас, что ни одно решение не работает хорошо. Я перепробовал так много решений, но все они не слишком хороши. Я думаю, что проблема заключается в том, что Apple на самом деле не документирует формат метаданных для необходимых данных.

Вот как я делаю это долгое время, очень успешно:

  1. Создайте новый DMG, доступный для записи(!), достаточно большой, чтобы вместить ожидаемые двоичные и дополнительные файлы, такие как readme (sparse может работа).

  2. Установите DMG и дайте ему макет вручную в Finder или с помощью любых инструментов, подходящих для этого (см. ссылку FileStorm внизу для хорошего инструмента). Фоновое изображение-это обычно изображение, которое мы помещаем в скрытую папку (".что-то") на DMG. Поместите туда копию вашего приложения (подойдет любая версия, даже устаревшая). Копировать другие файлы (псевдонимы, readme и т. д.) вы хотите там, опять же, устаревшие версии будут делать просто отлично. Убедитесь, что значки имеют правильные размеры и позиции (IOW, макет DMG так, как вы хотите, чтобы он был).

  3. Снова отключите DMG,все настройки должны быть сохранены.

  4. Напишите сценарий create DMG, который работает следующим образом:

      Он копирует DMG, так что оригинал больше никогда не трогается.
  5. он монтирует копию.
  6. он заменяет все файлы самыми современными (например, последнее приложение после сборки). Вы можете просто использовать mv или ditto для этого в командной строке. Обратите внимание, что при замене такого файла значок останется прежним, позиция останется прежней, все, кроме содержимого файла (или каталога), останется прежним (по крайней мере, с ditto, который мы обычно используем для этой задачи). Вы можете, конечно, также заменить фоновое изображение другим (просто убедитесь, что оно имеет те же размеры).
  7. после замены файлов заставьте скрипт снова размонтировать копию DMG.
  8. Наконец вызовите hdiutil для преобразования записываемого файла в сжатый (и такие не пишутся) DMG.
Этот метод может показаться неоптимальным, но поверьте мне, он действительно хорошо работает на практике. Вы можете поместить исходный DMG (шаблон DMG) даже под управление версиями (например, SVN), так что если вы когда-нибудь случайно измените/уничтожите его, вы можете просто вернуться к ревизии, где он все еще был в порядке. Вы можете добавить шаблон DMG в свой проект Xcode вместе со всеми другими файлами, которые принадлежат DMG (readme, URL-файл, фоновое изображение), все под управлением версий а затем создайте цель (например, внешнюю цель с именем "Create DMG") и там запустите сценарий DMG выше и добавьте вашу старую основную цель в качестве зависимой цели. Вы можете получить доступ к файлам в дереве Xcode, используя ${SRCROOT} в скрипте (всегда является исходным корнем вашего продукта), и вы можете получить доступ к продуктам сборки с помощью ${BUILT_PRODUCTS_DIR} (всегда является каталогом, где Xcode создает результаты сборки).

Результат: фактически Xcode может создать DMG в конце сборки. DMG, который готов выпускать. Таким образом, вы можете не только создать relase DMG довольно легко, но и сделать это в автоматическом процессе (на обезглавленном сервере, если хотите), используя xcodebuild из командной строки (например, автоматические ночные сборки).

Что касается начального макета шаблона, FileStorm является хорошим инструментом для его выполнения. Он коммерческий, но очень мощный и простой в использовании. Обычная версия стоит меньше 20 долларов,поэтому она действительно доступна. Может быть, можно автоматизировать FileStorm для создания DMG (например, через AppleScript), никогда не пробовал этого, но как только вы нашли идеальный шаблон DMG, его действительно легко обновить для каждого выпуска.

Актуализация этого вопроса путем предоставления этого ответа.

appdmg это простая, простая в использовании программа командной строки с открытым исходным кодом, которая создает dmg-файлы из простой спецификации json. Взгляните на readme на официальном сайте:

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)

Для тех из вас, кто интересуется этой темой, я должен упомянуть, как я создаю DMG:

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

My app, DropDMG , - это простой способ создания образов дисков с фоновыми изображениями, макетами значков, пользовательскими значками томов и лицензионными соглашениями на программное обеспечение. Им можно управлять из системы сборки с помощью инструмента командной строки "dropdmg" или AppleScript. При желании файлы RTF с картинками и лицензиями можно сохранить в системе управления версиями.

Я нашел это замечательное приложение для Mac, чтобы автоматизировать процесс - http://www.araelium.com/dmgcanvas/ вы должны посмотреть, если вы создаете DMG installer для вашего Mac app

Если вы хотите установить пользовательский значок громкости, то используйте команду ниже

/*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

Теперь создайте чтение / запись dmg

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

.Файлы DS_Store хранят настройки windows в Mac. Настройки Windows включают в себя расположение иконок, фон окна, размер окна и т. д. То.Файл DS_Store необходим при создании окна для смонтированных изображений, чтобы сохранить расположение файлов и фон windows.

Как только вы это сделаете .Файл DS_Store создан, вы можете просто скопировать его в созданный вами установщик (DMG).

Я также нуждаюсь в использовании подхода командной строки, чтобы сделать упаковку и создание dmg "программно в скрипте". Лучший ответ, который я нашел до сих пор, - это от Adium project' Release building framework (см. R1). Существует пользовательский скрипт (AdiumApplescriptRunner), позволяющий избежать взаимодействия с графическим интерфейсом OSX WindowsServer. - osascript applescript.подход "scpt" требует, чтобы вы вошли в систему как конструктор и запустили создание dmg из сеанса командной строки vt100.

Система управления пакетами OSX не такова продвинутый по сравнению с другими Unixen, которые могут сделать эту задачу легко и систематически.

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

Я, наконец, получил эту работу в моем собственном проекте (который, оказывается, находится в Xcode). Добавление этих 3 сценариев на этапе сборки автоматически создаст образ диска для вашего продукта, который будет красивым и аккуратным. Все, что вам нужно сделать, это построить свой проект, и DMG будет ждать в папке продуктов.

Сценарий 1 (Создание Образа Временного Диска):

#!/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

Script 2 (Set Window Properties Script):

#!/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/!

Для создания красивого DMG теперь можно просто использовать некоторые хорошо написанные открытые источники:

Эти ответы слишком сложны, и времена изменились. Следующее работает на 10.9 просто отлично, разрешения правильные, и это выглядит красиво.

Создайте 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 "-c c=64,a=16,e=16" \
  -format UDZO -imagekey zlib-level=9 "$DMG"

if [ -n "$CODESIGN_IDENTITY" ]; then
  codesign -s "$CODESIGN_IDENTITY" -v "$DMG"
fi

Создайте DMG только для чтения со значком (.тип icns)

#!/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 "-c c=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

Если что-то еще должно произойти, проще всего сделать временную копию SRC_DIR и применить изменения к ней перед созданием DMG.

Я только что написал новую (дружественную) утилиту командной строки для этого. Он не зависит от Finder / AppleScript или от любого из (устаревших) API Alias Manager, и его легко настроить и использовать.

В любом случае, любой, кто заинтересован, может найти его на PyPi; документация доступна на Read the Docs.