Nosso projeto de exemplo tem dois destinos de construção: HelloWorld.app e Helper.app. Criamos um pacote de componentes para cada um e os combinamos em um arquivo de produtos .
Um pacote de componentes contém carga útil a ser instalada pelo OS X Installer. Embora um pacote de componentes possa ser instalado por si só, ele geralmente é incorporado a um arquivo do produto .
Após um "Build and Archive" bem-sucedido, abra $ BUILT_PRODUCTS_DIR no Terminal.
$ cd ~/Library/Developer/Xcode/DerivedData/.../InstallationBuildProductsLocation
$ pkgbuild --analyze --root ./HelloWorld.app HelloWorldAppComponents.plist
$ pkgbuild --analyze --root ./Helper.app HelperAppComponents.plist
Isso nos fornece o componente, você encontra a descrição do valor na seção "Lista de propriedades do componente" . O pkgbuild -root gera os pacotes de componentes , se você não precisar alterar nenhuma das propriedades padrão, poderá omitir o parâmetro --component-plist no comando a seguir.
productbuild - sintetiza resultados em uma definição de distribuição .
$ 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
No Distribution.xml, você pode alterar itens como título, plano de fundo, bem-vindo, leia-me, licença e assim por diante. Você transforma seus pacotes de componentes e definição de distribuição com este comando em um archive do produto :
$ productbuild --distribution ./Distribution.xml \
--package-path . \
./Installer.pkg
Eu recomendo dar uma olhada no iTunes Installers Distribution.xml para ver o que é possível. Você pode extrair "Instalar o iTunes.pkg" com:
$ pkgutil --expand "Install iTunes.pkg" "Install iTunes"
Vamos colocá-lo juntos
Normalmente, tenho uma pasta chamada Package no meu projeto, que inclui coisas como Distribution.xml, lista de componentes, recursos e scripts.
Adicione uma Fase de Criação de Script de Execução denominada "Gerar Pacote", configurada como Executar script apenas ao instalar :
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}"
Se você não precisar alterar o pacote depois que ele for gerado com o productbuild, poderá se livrar das etapas pkgutil --expand
e pkgutil --flatten
. Além disso, você pode usar o parâmetro --sign no productbuild em vez de executar o productsign .
Assine um instalador do OS X
Os pacotes são assinados com o certificado do Developer ID Installer , que você pode baixar no Developer Certificate Utility .
A assinatura é feita com o --sign "Developer ID Installer: John Doe"
parâmetro pkgbuild , productbuild ou productsign .
Observe que, se você deseja criar um arquivo de produtos assinado usando o productbuild, não há razão para assinar os pacotes de componentes .
Todo o caminho: Copie o pacote no arquivo Xcode
Para copiar algo no arquivo Xcode, não podemos usar a fase de criação de script de execução . Para isso, precisamos usar uma ação de esquema.
Edite Esquema e expanda Arquivar. Em seguida, clique em pós-ações e adicione uma nova ação de script de execução :
No Xcode 6:
#!/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
No Xcode 5, use este valor para PKG
:
PKG="${OBJROOT}/ArchiveIntermediates/${TARGET_NAME}/BuildProductsPath/${CONFIGURATION}/${ARCHIVE_FILENAME}"
Caso seu controle de versão não armazene informações sobre o Esquema Xcode, sugiro adicioná-lo como shell script ao seu projeto para que você possa restaurar a ação com facilidade, arrastando o script da área de trabalho para a pós-ação.
Script
Existem dois tipos diferentes de script: JavaScript em arquivos de definição de distribuição e scripts de shell.
A melhor documentação sobre scripts de shell que encontrei no WhiteBox - PackageMaker How-to , mas leia isso com cautela, pois se refere ao formato antigo do pacote.
Leitura Adicional
Problemas conhecidos e soluções alternativas
Painel de Seleção de Destino
É apresentada ao usuário a opção de seleção de destino com apenas uma opção: "Instalar para todos os usuários deste computador". A opção aparece visualmente selecionada, mas o usuário precisa clicar nela para prosseguir com a instalação, causando alguma confusão.
A Documentação da Apple recomenda o uso, <domains enable_anywhere ... />
mas isso aciona o novo Painel de Seleção de Destino com mais bugs, que a Apple não usa em nenhum de seus Pacotes.
Usando o descontinuado, <options rootVolumeOnly="true" />
você obtém o antigo Painel de Seleção de Destino.
Você deseja instalar itens na pasta inicial do usuário atual.
Resposta curta: NÃO TENTE!
Resposta longa: REALMENTE; NÃO TENTE! Leia Problemas e soluções do instalador . Você sabe o que eu fiz, mesmo depois de ler isso? Eu fui estúpido o suficiente para tentar. Dizendo a mim mesmo que tenho certeza de que eles resolveram os problemas em 10.7 ou 10.8.
Antes de tudo, vi de tempos em tempos o Bug do Painel de Seleção de Destino acima mencionado. Isso deveria ter me parado, mas eu ignorei. Se você não deseja passar a semana após o lançamento do software, respondendo a e-mails de suporte nos quais eles precisam clicar uma vez que a bela seleção azul NÃO use isso.
Agora você está pensando que seus usuários são inteligentes o suficiente para descobrir o painel, não é? Bem, aqui está outra coisa sobre a instalação da pasta pessoal: ELES NÃO FUNCIONAM!
Testei-o por duas semanas em cerca de 10 máquinas diferentes com versões diferentes do sistema operacional e quais não, e nunca falhou. Então eu enviei. Dentro de uma hora do lançamento, recebo respostas de usuários que simplesmente não conseguiam instalá-lo. Os logs sugerem problemas de permissão que você não poderá corrigir.
Então, vamos repetir mais uma vez: Não usamos o Installer para instalações de pastas pessoais!
RTFD para Boas-vindas, Leia-me, Licença e Conclusão não é aceito por productbuild
.
O instalador é suportado desde o início dos arquivos RTFD para criar lindas telas de boas-vindas com imagens, mas o productbuild não as aceita.
Soluções alternativas: use um arquivo rtf fictício e substitua-o no pacote depois que productbuild
terminar.
Nota: Você também pode ter imagens Retina dentro do arquivo RTFD. Use arquivos TIFF multi-imagem para isso: tiffutil -cat Welcome.tif Welcome_2x.tif -out FinalWelcome.tif
. Mais detalhes .
Iniciando um aplicativo quando a instalação é concluída com um script BundlePostInstallScriptPath :
#!/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
É importante executar o aplicativo como usuário conectado, não como usuário instalador. Isso é feito com o caminho launchctl asuser uid . Também o executamos apenas quando não é uma instalação de linha de comando, feita com a ferramenta de instalação ou o Apple Remote Desktop .