Geliştirici Kimliği olan macOS Yükleyici Paketlerini hazır hale getirme


189

Not: Bu yalnızca OS X Installer paketleri içindir, Mac App Store'a gönderilen paketler farklı kurallara uyar.

Mountain Lion's Gatekeeper yüzünden nihayet PackageMaker derleme betiğimi ahırın arkasına alıp vurmak zorunda kaldım . PackageMaker zaten Xcode kaldırıldı ve "Xcode için Yardımcı Araçlar" taşındı, umarım yakında unutulur.

Soru Ben kullanırım nasıl pkgbuild, productbuildve pkgutilbunu değiştirmek için?


Bu yüzden Packagemaker ile ilgili sorunun Mountain Lion'da gatekeeper ile kullanmak için pkg dosyalarını düzgün şekilde imzalayamadığını varsayalım?
JasonZ

1
Bu mümkün, ancak PackageMaker her zaman cehennem oldu ve Mac OS X 10.6 Snow Leopard ile kullanımdan kaldırıldı. Yeni araçlara aşina olmak için uzun vadede size zaman kazandıracak.
catlan

@catlan: Packagemaker'ın 10.6'da kullanımdan kaldırıldığını söyleyen resmi bir bağlantınız var mı?
Carl

2
@carleeto: Asla kullanımdan kaldırıldığı, Xcode'dan kaldırıldığı ve sonunda Birman protestocu gibi "kaybolduğu" açıklanmadı.
böcek

5
Xcode 4.6 sürüm notları: Package Maker'ın kullanımdan kaldırılması adcdownload.apple.com/Developer_Tools/xcode_4.6/…
catlan

Yanıtlar:


344

Örnek projemizin iki oluşturma hedefi vardır: HelloWorld.app ve Helper.app. Her biri için bir bileşen paketi hazırlıyoruz ve bunları bir ürün arşivinde birleştiriyoruz .

Bir bileşen, bir paket OS X yükleyicisi tarafından kurulacak yükleme içerir. Bir bileşen paketi kendi başına kurulabilse de, genellikle bir ürün arşivine eklenir .

Araçlarımız: pkgbuild , productbuild ve pkgutil

Başarılı bir "Derleme ve Arşivleme" işleminden sonra Terminal'de $ BUILT_PRODUCTS_DIR dosyasını açın.

$ cd ~/Library/Developer/Xcode/DerivedData/.../InstallationBuildProductsLocation
$ pkgbuild --analyze --root ./HelloWorld.app HelloWorldAppComponents.plist
$ pkgbuild --analyze --root ./Helper.app HelperAppComponents.plist

Bu bize bileşen-plist verir, değer açıklamasını "Bileşen Özellik Listesi" bölümünde bulabilirsiniz. pkgbuild -root bileşen paketlerini oluşturur, varsayılan özelliklerden herhangi birini değiştirmeniz gerekmiyorsa , aşağıdaki komutta --component-plist parametresini atlayabilirsiniz .

productbuild - sonuçları bir Dağıtım Tanımında sentezler .

$ pkgbuild --root ./HelloWorld.app \
    --component-plist HelloWorldAppComponents.plist \
    HelloWorld.pkg
$ pkgbuild --root ./Helper.app \
    --component-plist HelperAppComponents.plist \
    Helper.pkg
$ productbuild --synthesize \
    --package HelloWorld.pkg --package Helper.pkg \
    Distribution.xml 

In Distribution.xml Eğer başlık, arka plan, karşılama, Benioku'da, lisans ve benzeri şeyleri değiştirebilir. Eğer çevirmek bileşen paketleri bir içine bu komutla ve dağıtım tanımını ürün arşivde :

$ productbuild --distribution ./Distribution.xml \
    --package-path . \
    ./Installer.pkg

Neyin mümkün olduğunu görmek için iTunes Installers Distribution.xml dosyasına göz atmanızı öneririm . "Install iTunes.pkg" dosyasını aşağıdakilerle çıkarabilirsiniz:

$ pkgutil --expand "Install iTunes.pkg" "Install iTunes"

Bir araya getirelim

Projemde genellikle Dağıtım.xml, bileşen-plists, kaynaklar ve komut dosyaları gibi paket içeren bir klasör var.

Yalnızca yükleme sırasında Komut dosyasını çalıştır olarak ayarlanan "Generate Package" adlı bir Komut Dosyası Oluşturma Safhası ekleyin :

VERSION=$(defaults read "${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}/Contents/Info" CFBundleVersion)

PACKAGE_NAME=`echo "$PRODUCT_NAME" | sed "s/ /_/g"`
TMP1_ARCHIVE="${BUILT_PRODUCTS_DIR}/$PACKAGE_NAME-tmp1.pkg"
TMP2_ARCHIVE="${BUILT_PRODUCTS_DIR}/$PACKAGE_NAME-tmp2"
TMP3_ARCHIVE="${BUILT_PRODUCTS_DIR}/$PACKAGE_NAME-tmp3.pkg"
ARCHIVE_FILENAME="${BUILT_PRODUCTS_DIR}/${PACKAGE_NAME}.pkg"

pkgbuild --root "${INSTALL_ROOT}" \
    --component-plist "./Package/HelloWorldAppComponents.plist" \
    --scripts "./Package/Scripts" \
    --identifier "com.test.pkg.HelloWorld" \
    --version "$VERSION" \
    --install-location "/" \
    "${BUILT_PRODUCTS_DIR}/HelloWorld.pkg"
pkgbuild --root "${BUILT_PRODUCTS_DIR}/Helper.app" \
    --component-plist "./Package/HelperAppComponents.plist" \
    --identifier "com.test.pkg.Helper" \
    --version "$VERSION" \
    --install-location "/" \
    "${BUILT_PRODUCTS_DIR}/Helper.pkg"
productbuild --distribution "./Package/Distribution.xml"  \
    --package-path "${BUILT_PRODUCTS_DIR}" \
    --resources "./Package/Resources" \
    "${TMP1_ARCHIVE}"

pkgutil --expand "${TMP1_ARCHIVE}" "${TMP2_ARCHIVE}"

# Patches and Workarounds

pkgutil --flatten "${TMP2_ARCHIVE}" "${TMP3_ARCHIVE}"

productsign --sign "Developer ID Installer: John Doe" \
    "${TMP3_ARCHIVE}" "${ARCHIVE_FILENAME}"

Paketi, ürün oluşturma ile oluşturulduktan sonra değiştirmeniz gerekmiyorsapkgutil --expand ve pkgutil --flattenadımlarından kurtulabilirsiniz . Ayrıca kullanabilirsiniz --sign üzerinde parametresine productbuild yerine çalışan productsign .

OS X Yükleyicisini imzalama

Paketler, Developer Certificate Utility'den indirebileceğiniz Developer ID Installer sertifikası ile imzalanır .

İmzalama, pkgbuild , productbuild veya productsign--sign "Developer ID Installer: John Doe" parametresi ile yapılır .

Productbuild kullanarak imzalı bir ürün arşivi oluşturacaksanız , bileşen paketlerini imzalamanın bir nedeni olmadığını unutmayın .

Geliştirici Sertifikası Yardımcı Programı

Tüm yol: Paketi Xcode Arşivine Kopyala

Xcode Arşivine bir şey kopyalamak için Komut Dosyası Çalıştırma Derecesini Çalıştırma Aşamasını kullanamayız . Bunun için bir Şema Eylemi kullanmamız gerekiyor.

Düzeni düzenleyin ve Arşivi genişletin. Ardından işlem sonrası seçeneğini tıklayın ve Yeni Çalıştırılan Komut Dosyası İşlemi ekleyin :

Xcode 6'da:

#!/bin/bash

PACKAGES="${ARCHIVE_PATH}/Packages"

PACKAGE_NAME=`echo "$PRODUCT_NAME" | sed "s/ /_/g"`
ARCHIVE_FILENAME="$PACKAGE_NAME.pkg"
PKG="${OBJROOT}/../BuildProductsPath/${CONFIGURATION}/${ARCHIVE_FILENAME}"

if [ -f "${PKG}" ]; then
    mkdir "${PACKAGES}"
    cp -r "${PKG}" "${PACKAGES}"
fi

Xcode 5'te, PKGbunun için şu değeri kullanın:

PKG="${OBJROOT}/ArchiveIntermediates/${TARGET_NAME}/BuildProductsPath/${CONFIGURATION}/${ARCHIVE_FILENAME}"

Sürüm denetiminizin Xcode Şeması bilgilerini depolamaması durumunda, bunu projenize kabuk komut dosyası olarak eklemenizi öneririm;

Komut

İki farklı komut dosyası türü vardır: Dağıtım Tanımlama Dosyaları ve Kabuk Komut Dosyaları'nda JavaScript .

Kabuk Komut Dosyaları hakkında en iyi belgeleri WhiteBox'ta buldum - PackageMaker Nasıl Yapılır , ancak eski paket formatına atıfta bulunduğundan bunu dikkatle okuyun.

İlave Okuma

Bilinen Sorunlar ve Geçici Çözümler

Hedef Seçim Bölmesi

Kullanıcıya, yalnızca tek bir seçim olan hedef seçme seçeneği sunulur - "Bu bilgisayarın tüm kullanıcıları için yükle". Seçenek görsel olarak seçili olarak görünür, ancak kullanıcının kuruluma devam etmek için üzerine tıklaması gerekir ve bu da biraz karışıklığa neden olur.

Yükleyici hatasını gösteren örnek

Elmalar Belgeleri kullanılmasını önerir, <domains enable_anywhere ... />ancak bu, Apple'ın Paketlerinin hiçbirinde kullanmadığı yeni daha bugun Hedef Seçim Bölmesini tetikler.

Kullanımdan kaldırmayı kullanarak <options rootVolumeOnly="true" />size eski Hedef Seçim Bölmesini verin. Eski Hedef Seçim Bölmesini gösteren örnek


Geçerli kullanıcının ana klasörüne öğe yüklemek istiyorsunuz.

Kısa cevap: BUNU DENEMEYİN!

Uzun cevap: GERÇEKTEN; BUNU DENEME! Yükleyici Sorunları ve Çözümlerini okuyun . Bunu okuduktan sonra bile ne yaptığımı biliyor musun? Denemek için yeterince aptalcaydım. Kendime, sorunları 10.7 veya 10.8'de çözdüklerinden emin olduğumu söylüyorum.

Her şeyden önce zaman zaman yukarıda belirtilen Hedef Seçim Bölmesi Hatasını gördüm. Bu beni durdurmalıydı, ama görmezden geldim. Yazılımınızı yayınladıktan sonra bir hafta harcamak istemiyorsanız, destek e-postalarını yanıtlamak zorunda kaldıklarında, hoş mavi seçim bir kez bunu KULLANMAYIN.

Artık kullanıcılarınızın paneli anlayacak kadar akıllı olduğunu düşünüyorsunuz, değil mi? İşte ana klasör yüklemesi hakkında başka bir şey, ÇALIŞMAYIN!

İki hafta boyunca farklı işletim sistemi sürümlerine sahip 10 farklı makinede test ettim ve ne yapmadım ve asla başarısız olmadı. Ben de gönderdim. Yayınlandıktan bir saat sonra, yükleyemeyen kullanıcılardan geri döndüm. Günlükler, düzeltemeyeceğiniz izin sorunlarına işaret etti.

Şimdi bir kez daha tekrarlayalım: Yükleyiciyi ana klasör yüklemeleri için kullanmayız!


Hoş Geldiniz, Beni Oku, Lisans ve Sonuç için RTFD tarafından kabul edilmez productbuild.

Installer, RTFD dosyalarının başından beri resimlerle hoş karşılama ekranları yapmak için destekledi, ancak ürün geliştirme bunları kabul etmiyor.

Geçici çözümler: Sahte bir rtf dosyası kullanın ve paketin içinde bittikten sonra değiştirin productbuild.

Not: Ayrıca, RTFD dosyasının içinde Retina görüntüleri de olabilir. Bunun için çok görüntü tiff dosyaları kullanın: tiffutil -cat Welcome.tif Welcome_2x.tif -out FinalWelcome.tif. Daha fazla ayrıntı .


Kurulum bir BundlePostInstallScriptPath komut dosyası ile tamamlandığında uygulama başlatma :

#!/bin/bash

LOGGED_IN_USER_ID=`id -u "${USER}"`

if [ "${COMMAND_LINE_INSTALL}" = "" ]
then
    /bin/launchctl asuser "${LOGGED_IN_USER_ID}" /usr/bin/open -g PATH_OR_BUNDLE_ID
fi

exit 0

Uygulamayı yükleyici kullanıcı olarak değil, oturum açmış kullanıcı olarak çalıştırmak önemlidir. Bu, launchctl asuser uid yolu ile yapılır . Ayrıca, yalnızca bir yükleyici aracı veya Apple Remote Desktop ile yapılan bir komut satırı yüklemesi olmadığında çalıştırırız .



9
Bu mükemmel bir öğreticidir, ancak prefabrik paketlerin varlığını varsayar. Örneğin, /tmpbir postflight betiğinde daha sonra işlenmek üzere tek bir dosya kuracaksam, bileşen listesini nasıl yapılandırabilirim? Kullanılabilir tüm belgelerin, geliştiricinin --analyzeen azından başlangıçta oluşturduğunu varsaydığı görülmektedir .
böcek

1
Eğer içinde hiçbir şeyi değiştirmene Component Property Listgerek yoksa koşmana gerek yok --analyze. Postprocessing dosyaları için hepsini bir pakete koymanızı ve o pkg kurulum konumunu ayarlamanızı öneririm /tmp. Ama belki sorunuzu yanlış anlıyorum. Eğer öyleyse SO üzerinde daha ayrıntılı bir sürümde yayınlayın.
catlan

2
Paketleme uygulamasındaki tüm hatalardan kaçmaya çalışırken, komut satırı üzerinden paket yapmanın kesinlikle bir anlamı olmadığını lütfen unutmayın. Bunun yerine sizin için tüm sorunları çözen Stéphane Sudre'nin "Paketler" uygulamasını kullanma hakkındaki yorumuma bakın!
Bram de Jong

5
@BramdeJong "mantıklı değil". Katılmıyorum. Apple, komut satırı araçlarını korur. Packages, topluluk tarafından desteklenmeyen ve Apple'ın köklü bir şeyi değiştirmesi durumunda gelecekte kırılabilecek üçüncü taraf bir uygulamadır. Benim için, komut satırı tekniğini kullanmayı tercih ederim, böylece Apple sert bir şey değiştirirse, çalışmaya devam edebilirim.
Volomike

5
$ pkgbuild --root ./HelloWorld.app yanlış (.app'nin gerçek bir uygulama paketi olduğunu varsayarsak). pkgbuild bir hedef kök üzerinde çalışır: yani: xcode takım zinciri tarafından oluşturulan bir paketi İÇEREN bir klasör. Bu yüzden pkgbuild argümanı paketlemek istediğimiz paketin içerdiği klasörün yoludur. Bu doğru şekilde alınmazsa, yalnızca uygulama içeriği klasörünü içeren bir paket oluşturulur. Gerçek bir uygulama paketi olarak yüklenmez. Hediye bileşen plist içinde. Bu, uygulama paketini belirten bir RootRelativeBundlePath girdisi içermiyorsa, o zaman mahvoldunuz.
Jonathan Mitchell

185

Stéphane Sudre tarafından tüm bunları sizin için yapan, komut dosyası olan / komut satırından binayı destekleyen, süper güzel bir GUI'ye sahip ve ÜCRETSİZ olan çok ilginç bir uygulama var. Üzücü olan şey: Google'da bulmayı imkansız kılan "Paketler" olarak adlandırılıyor.

http://s.sudre.free.fr/Software/Packages/about.html

Kendi senaryolarımı el işi yapmaya başlamadan önce bunu öğrenmiş olmayı dilemiştim.

Paketler uygulama ekran görüntüsü


11
Bu yazının daha fazla anlamı olmadığına inanamıyorum. Bu yazılım şaşırtıcı ve komut satırından bina destekler.
Cesar Mendoza

1
Herkes bu araçla bir paket imzalamaya çalıştı mı? Etkinleştirmek için "Sertifika Ayarla" menü öğesini
alamıyorum

2
@ user283182: Çok geç yumru, elbette zaten anladınız, ancak belki bu başkalarına yardımcı olacaktır - Karşılaştığınız sorunun [Mac App Store İnceleme Yönergeleri] 'nde ayrıntılı olduğunu düşünüyorum ( developer.apple.com/app- store / review / yönergeler / mac /… ), kural 2.14: "Uygulamalar Xcode'un içerdiği Apple'ın paketleme teknolojileri kullanılarak paketlenmeli ve gönderilmelidir - üçüncü taraf yükleyicilere izin verilmez."
büyük yaşlı

4
Keşke bu ücretli bir uygulama ve geliştirici sürekli güncelleme ve yama. Packages.app özellikle uygulamanızı hızlı bir şekilde dağıtmak istiyorsanız harika. Genel Bakış'ı okumak, projemi kurmak ve yüklenebilir paketi oluşturmak toplam 3 dakikamı aldı. Stéphane'ye büyük kudos.
Nikolay Christov

1
Bu uygulama harika!
Spencer Müller Diniz

3

Bir paket veya eklenti için paket yükleyici oluşturmaya çalışanlar için FYI, kolaydır:

pkgbuild --component "Color Lists.colorPicker" --install-location ~/Library/ColorPickers ColorLists.pkg

2
Bilginize, bir .pkg oluşturmak ile karşılama ekranı, lisans vb. İle gerçek bir yükleyici oluşturmak arasında bir fark vardır.
catlan

evet farkındayım, buraya koyuyorum çünkü bir eklenti için bir pkg yükleyici oluşturmaya referans bulamadım.
gngrwzrd

Bu beni yuvarladı. Sadece topraklama vermek için minimum.
uchuugaka

3

Kabul edilen cevaba +1:

Yükleyicide Hedef Seçimi

Kullanıcı etki alanı ve sistem etki alanı arasında etki alanı (diğer adıyla hedef) seçimi isteniyorsa <domains enable_anywhere="true">aşağıdakileri kullanmayı denemek yerine :

<domains enable_currentUserHome="true" enable_localSystem="true"/>

enable_currentUserHome uygulama uygulamasını altına yükler ~/Applications/ve enable_localSystemuygulamanın/Application

Bunu El Capitan 10.11.6'da (15G1217) denedim ve 1 dev makinede ve denediğim 2 farklı VM'de mükemmel çalışıyor gibi görünüyor.


Bu iyi çalışır, ancak bir GOT'CHA ile: Önce kullanıcı başına yüklerseniz, makine başına yüklerseniz, yükleme kullanıcı dizininde olur, makine dizininde değil, sudo haklarıyla olur. Bunun tersi bir durum söz konusu değildir: makine başına ve daha sonra kullanıcı başına yükleyebilir ve her iki yerde de kullanabilirsiniz.
Terje Dahl

@TerjeDahl evet bunun nedeni, yükleme sonrası paketin aynı paket kimliğinin daha önce yükleyici tarafından yüklendiği konuma taşınmasıdır (ve yükleyici bunu bilir). Bu, şu anda hatırlamadığım manifest dosyasındaki bazı ayarlarla önlenebilir.
PnotNP

@ PnotNP Ah. Hatırlarsanız bu ayarlarla geri dönecek kadar nazik olsaydınız, bu harika olurdu!
Terje Dahl

2

İşte bir yapı kökünden imzalı bir yükleyici paketi oluşturan bir yapı komut dosyası .

#!/bin/bash
# TRIMCheck build script
# Copyright Doug Richardson 2015
# Usage: build.sh
#
# The result is a disk image that contains the TRIMCheck installer.
#

DSTROOT=/tmp/trimcheck.dst
SRCROOT=/tmp/trimcheck.src

INSTALLER_PATH=/tmp/trimcheck
INSTALLER_PKG="TRIMCheck.pkg"
INSTALLER="$INSTALLER_PATH/$INSTALLER_PKG"

#
# Clean out anything that doesn't belong.
#
echo Going to clean out build directories
rm -rf build $DSTROOT $SRCROOT $INSTALLER_PATH
echo Build directories cleaned out


#
# Build
#
echo ------------------
echo Installing Sources
echo ------------------
xcodebuild -project TRIMCheck.xcodeproj installsrc SRCROOT=$SRCROOT || exit 1

echo ----------------
echo Building Project
echo ----------------
pushd $SRCROOT
xcodebuild -project TRIMCheck.xcodeproj -target trimcheck -configuration Release install || exit 1
popd

echo ------------------
echo Building Installer
echo ------------------
mkdir -p "$INSTALLER_PATH" || exit 1

echo "Runing pkgbuild. Note you must be connected to Internet for this to work as it"
echo "has to contact a time server in order to generate a trusted timestamp. See"
echo "man pkgbuild for more info under SIGNED PACKAGES."
pkgbuild --identifier "com.delicioussafari.TRIMCheck" \
    --sign "Developer ID Installer: Douglas Richardson (4L84QT8KA9)" \
    --root "$DSTROOT" \
    "$INSTALLER" || exit 1


echo Successfully built TRIMCheck
open "$INSTALLER_PATH"

exit 0

1
Evet, pkgbuild bir .pkg yükleyici oluşturur.
Doug Richardson
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.