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

212

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

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

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

Людвиг Норин
источник
1
Разве это не что-то для Ask Different?
Ленар Хойт
2
github.com/LinusU/node-appdmg
Проф. Фалькен,

Ответы:

199

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

  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 для установки визуальных стилей (имя .app должно быть в переменной 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 приведенный выше яблочный скрипт не будет правильно устанавливать положение иконки - похоже, это ошибка 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
Людвиг Норин
источник
1
Превосходно. Два вопроса по этому поводу: 1. Вы рекомендуете sleepпосле нанесения изображения. Сколько? Разве нельзя детерминистски ждать завершения процесса? То же самое delay 5в вашем AppleScript. Я всегда настороженно отношусь к такому произвольному времени ожидания, потому что у меня был очень плохой опыт с ними. 2. На вашем шаге 6 вы звоните syncдважды - почему?
Конрад Рудольф
Я не нашел способа детерминистически дождаться завершения команды «обновление без регистрации приложений». Я не уверен, что сон нужен после "hdiutil attach", вам придется проверить документацию (man hdiutil). Синхронизацию нужно вызывать только один раз, я делаю это дважды по старой привычке со времен старых добрых дней SunOS.
Людвиг А. Норин
1
Это позволяет яблочный скрипт имитировать ввод с клавиатуры и мыши и кучу других вещей.
Людвиг А. Норин
1
Если сценарий зависает до истечения времени ожидания в строке «обновление без регистрации приложений», то шаг 1 не был выполнен (или отменен). Я только что выяснил это трудным путем.
Джей Мейнард K5ZC
Я думаю, что обнаружил небольшой сбой - в AppleScript есть извлечение, которое делается до того, как вы попытаетесь запустить chmod. Сбой chmod, потому что диск теперь извлечен.
Трейказ
56

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

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

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

Андрей Таранцов
источник
7
Ссылка на ваш bash скрипт не работает. Можете ли вы положить это в сущности на github.com? Спасибо
dquimper
create-dmg НЕ позиционирует значок хорошо. Если вам нужна эта функция, не используйте ее.
laike9m
1
@ laike9m Прошло более 5 лет с тех пор, как я в последний раз касался этого. Я не считаю DMG лучшим способом распространения программного обеспечения для Mac. Таким образом, он выживает за счет вкладов других - надеюсь, кто-то тоже выяснит проблему с иконками.
Андрей Таранцов
3
@Zmey Ну, как пользователь, я предпочитаю zip-файлы. Бонусные баллы за автоматическое копирование, /Applicationsесли приложение обнаруживает, что оно запущено ~/Downloads. Смотрите также эту старую статью Джона Грубера .
Андрей Таранцов
37

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

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

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

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

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

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

    • Он копирует DMG, поэтому оригинал никогда не трогать снова.
    • Это монтирует копию.
    • Он заменяет все файлы самыми последними (например, последнее приложение после сборки). Вы можете просто использовать mv или ditto для этого в командной строке. Обратите внимание, что при замене файла таким образом значок останется прежним, позиция останется прежней, все содержимое файла (или каталога) останется прежним (по крайней мере, с тем же, что мы обычно используем для этой задачи) , Конечно, вы также можете заменить фоновое изображение другим (просто убедитесь, что оно имеет те же размеры).
    • После замены файлов заставьте скрипт снова размонтировать копию DMG.
    • Наконец, вызовите hdiutil для преобразования записываемого в сжатый (и такой не записываемый) DMG.

Этот метод может показаться неоптимальным, но поверьте мне, на практике он работает очень хорошо. Вы можете поместить оригинальный DMG (шаблон DMG) даже под контроль версий (например, SVN), поэтому, если вы когда-нибудь случайно его измените / уничтожите, вы можете просто вернуться к ревизии, где все было в порядке. Вы можете добавить шаблон DMG в свой проект XCode вместе со всеми другими файлами, которые принадлежат DMG (readme, файл URL, фоновое изображение), все под контролем версий, а затем создать цель (например, внешнюю цель с именем «Create DMG») и там запустить сценарий DMG выше и добавить вашу старую основную цель в качестве зависимой цели. Вы можете получить доступ к файлам в дереве Xcode, используя $ {SRCROOT} в скрипте (всегда является исходным корнем вашего продукта), и вы можете получить доступ к продуктам сборки, используя $ {BUILT_PRODUCTS_DIR} (всегда каталог, где Xcode создает результаты сборки) ,

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

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

Mecki
источник
3
Я уже отказался от идеи сделать это по нескольким причинам. Вот два из них: содержание инсталляторов зависит от продукта, и мы хотим полагаться только на программное обеспечение, установленное на компьютерах с пакетом, и на скрипты - единую минимальную ручную процедуру добавления новых продуктов.
Людвиг А. Норин
Это тот же сценарий, что и у нас. У нас более десятка продуктов; у каждого совершенно другой DMG. Создание одного шаблона DMG для каждого продукта - одноразовая задача, занимающая пару минут. А что вы подразумеваете под "установщиком"? PKG / MPKG установить пакеты?
Меки
Это не тот же сценарий. Мы добавляем продукты часто, с кратким уведомлением. Минимальная ручная процедура означает запуск сценария, дающего продукту имя и несколько других атрибутов. Помимо этого есть и другие причины, которые заставили нас принять решение не использовать такого рода решение.
Людвиг А. Норин
Мы отделили процесс упаковки от процесса сборки, потому что он выполняется разными людьми в разное время. В процессе упаковки также создаются установщики для Windows, Windows CE, Symbian, AIX, Linux и Solaris.
Людвиг А. Норин
Вы, вероятно, ссылаетесь на hdiutil, а не на hdutil.
Иван Вучица
25

Привести этот вопрос в актуальное состояние, предоставив этот ответ.

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

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

Быстрый пример:

  1. Установить приложение

    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)

Линус Уннебек
источник
3
просто и эффективно. Единственным недостатком является то, что для установки требуется npm
Джек Джеймс
@Creator: не могли бы вы сделать так, чтобы этот графический интерфейс предлагался без перетаскивания? s.sudre.free.fr/Software/Packages/about.html
Если файл .app не находится в той же папке, что и файл json, это не работает, он выдает ошибку «file not found», когда вы указываете относительный путь в «path»
Joey
@ Джои, не могли бы вы открыть проблему в репозитории Github, если она не работает для вас?
Линус Уннебек
@Joey: Не обязательно находиться в одной папке, у меня есть фон, приложение все по другому пути, просто передать относительные пути как ../../../ABC
Anoop Vaidya
22

Для тех из вас, кто интересуется этой темой, я должен упомянуть, как я создаю 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
Людвиг А. Норин
источник
1
Это нормально, но это не соответствует реальной потребности (фоновое изображение, расположение элементов в папке и т. Д.)
Том Богл,
создал DMG, но снова мне нужно запустить мой скрипт (.sh), используя CMD, мне нужно, чтобы он автоматически запускал sh после создания DMG
SANTOSH
13

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

Майкл Цай
источник
3
Моя команда прекрасно и автоматически работает на сервере сборки Jenkins CI, в комплекте с фоном и перетаскиванием в Приложения. Беги, не ходи, к DropDMG для создания образов дисков.
Пол Коллинз
Хорошее приложение, я собираюсь приобрести его после истечения срока действия пробной версии.
kilik52
Выглядит красиво, но, похоже, нет возможности изменить размер окна.
Ави
@avi DropDMG автоматически изменяет размер окна на фоновый рисунок , который вы установили (или вставки в эту картину , если необходимо).
Майкл Цай
Большое спасибо! Можно ли изменить размер без фонового изображения?
Ави
6

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

Саурабх
источник
1
Обратите внимание, что это не бесплатная программа, поэтому она не подходит для многих сред.
Джей Мейнард K5ZC
5

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

Anni S
источник
Может быть, они перенесли это. Вы можете использовать create-dmg и node-appdmg. Я использую Create-DMG. Это хорошо.
Anni S
@ PamelaCook-LightBeCorp Если вы все еще заинтересованы. Ссылка на dmgbuild была исправлена.
SubOptimal
4

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

/*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
оборота Параг Бафна
источник
Можете ли вы объяснить, что здесь означает «ваш путь»? Могу ли я использовать любой файл значков на диске, и SetFile скопирует его, или мне нужно будет использовать файл, который находится внутри .dmg? У меня только один Mac, поэтому сложно проверить, будет ли работать на других машинах.
Милан Бабушков
«ваш путь» - это имя DMG. (/ Volumes / dmgName)
Параг Бафна
Вы должны скопировать файл icns. cp "/Volumes/customIcon.icns" "/Volumes/dmgName/.VolumeIcon.icns"
Параг Бафна
4

Я наконец получил это, работая в моем собственном проекте (который, случается, в 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

Скрипт 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 /!

П.М.
источник
Это создает пустой образ диска в моем проекте. Любое предложение.
ManiaChamp
Часть сценария оболочки работает только, но как я могу добавить сценарий Apple с сценарием оболочки в RunScript в фазе сборки, он показывает ошибку, каждый оператор сценария яблока является символом не найден.
ManiaChamp
2

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

Создав файл .DS_Store, вы можете просто скопировать его в созданную программу установки (DMG).

hor10zs
источник
Но сначала добавьте фоновое изображение в dmg, назвав его чем-то вроде .background.png, а затем используя Cmd-J, чтобы добавить это (!) Изображение к фону.
Gijs
2

Мне также нужно использовать подход командной строки, чтобы сделать упаковку и создание dmg «программно в сценарии». Наилучший ответ, который я нашел на данный момент, - это проект Adium 'Release building framework (см. R1). Существует специальный скрипт (AdiumApplescriptRunner), позволяющий избежать взаимодействия с OSX WindowsServer GUI. Подход "osascript applecript.scpt" требует, чтобы вы вошли в систему как строитель и запустили создание dmg из сеанса командной строки vt100.

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

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

Ти Джей Ян
источник
2

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

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

Аластер
источник
1

Эти ответы слишком сложны, и времена изменились. Следующее работает на 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.

user246672
источник
Этот ответ не добавляет ничего к тому, что было написано ранее, а также не отвечает на первоначальный вопрос (речь идет не просто о том, чтобы поместить значок в dmg или как его подписать; вопрос в том, чтобы добавить графику и расположенные значки программным способом в DMG).
Людвиг А. Норин