Tạo các gói cài đặt macOS đã sẵn sàng cho ID nhà phát triển


188

Lưu ý: Đây chỉ dành cho các gói Trình cài đặt OS X , các gói để gửi tới Mac App Store theo các quy tắc khác nhau.

Gatekeeper của Mountain Lion, cuối cùng tôi đã phải lấy kịch bản xây dựng GóiMaker của mình đằng sau chuồng ngựa và bắn nó. GóiMaker đã bị xóa khỏi Xcode và được chuyển vào "Công cụ phụ trợ cho Xcode", vì vậy hy vọng nó sẽ sớm bị lãng quên.

Câu hỏi đặt ra là làm thế nào để sử dụng pkgbuild, productbuildpkgutilđể thay thế nó?


Vì vậy, tôi cho rằng vấn đề với packagemaker là không thể ký đúng các tệp pkg để sử dụng với gatekeeper trên Mountain Lion?
JasonZ

1
Điều đó là có thể, nhưng GóiMaker luôn bị lỗi và bị từ chối với Mac OS X 10.6 Snow Leopard. Nó sẽ giúp bạn tiết kiệm thời gian trong thời gian dài để làm quen với các công cụ mới.
catlan

@catlan: Bạn có một liên kết chính thức nói rằng packagemaker đã bị từ chối vào ngày 10.6 không?
Carl

2
@carleeto: Nó không bao giờ được thông báo là không được chấp nhận, chỉ bị xóa khỏi Xcode và cuối cùng "biến mất" như một người biểu tình Miến Điện.
lỗi

5
Ghi chú phát hành Xcode 4.6: Khấu hao của Trình tạo gói quảng cáo.cdple.com/Developer_Tools/xcode_4.6/ trên
catlan

Câu trả lời:


343

Dự án ví dụ của chúng tôi có hai mục tiêu xây dựng: HelloWorld.app và Helper.app. Chúng tôi tạo một gói thành phần cho mỗi và kết hợp chúng vào một kho lưu trữ sản phẩm .

Một gói phần chứa payload được cài đặt bởi OS X Installer. Mặc dù một gói thành phần có thể tự cài đặt, nhưng nó thường được tích hợp vào kho lưu trữ sản phẩm .

Các công cụ của chúng tôi: pkgbuild , Productbuildpkgutil

Sau khi "Xây dựng và Lưu trữ" thành công, hãy mở $ BUILT_PRODUCTS_DIR trong Terminal.

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

Điều này cung cấp cho chúng tôi phần tử thành phần, bạn tìm thấy mô tả giá trị trong phần "Danh sách thuộc tính thành phần" . pkgbuild -root tạo các gói thành phần , nếu bạn không cần thay đổi bất kỳ thuộc tính mặc định nào, bạn có thể bỏ qua tham số --component-plist trong lệnh sau.

Productbuild - kết quả tổng hợp trong Định nghĩa phân phối .

$ 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 

Trong tệp phân phối, bạn có thể thay đổi những thứ như tiêu đề, nền, chào mừng, readme, giấy phép, v.v. Bạn biến các gói thành phần và định nghĩa phân phối của mình bằng lệnh này thành kho lưu trữ sản phẩm :

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

Tôi khuyên bạn nên xem qua iTunes Installers Distribution.xml để xem những gì có thể. Bạn có thể trích xuất "Cài đặt iTunes.pkg" bằng:

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

Hãy đặt nó lại với nhau

Tôi thường có một thư mục có tên là Gói trong dự án của mình, bao gồm những thứ như Distribution.xml, thành phần-plists, tài nguyên và tập lệnh.

Thêm Giai đoạn Xây dựng Tập lệnh Chạy có tên "Tạo gói", được đặt thành Chỉ chạy tập lệnh khi cài đặt :

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}"

Nếu bạn không phải thay đổi gói sau khi được tạo bằng sản phẩm, bạn có thể thoát khỏi pkgutil --expandpkgutil --flattencác bước. Ngoài ra bạn có thể sử dụng --sign paramenter trên productbuild thay vì chạy productsign .

Đăng ký Trình cài đặt OS X

Các gói được ký với chứng chỉ Trình cài đặt ID nhà phát triển mà bạn có thể tải xuống từ Tiện ích chứng chỉ dành cho nhà phát triển .

Họ ký hợp đồng với được thực hiện với các --sign "Developer ID Installer: John Doe"tham số của pkgbuild , productbuild hoặc productsign .

Lưu ý rằng nếu bạn định tạo một kho lưu trữ sản phẩm đã ký bằng Productbuild, không có lý do gì để ký các gói thành phần .

Tiện ích chứng chỉ nhà phát triển

Tất cả các cách: Sao chép Gói vào Lưu trữ Xcode

Để sao chép một cái gì đó vào Lưu trữ Xcode, chúng ta không thể sử dụng Giai đoạn xây dựng tập lệnh . Đối với điều này, chúng ta cần sử dụng một Scheme Action.

Chỉnh sửa sơ đồ và mở rộng Lưu trữ. Sau đó nhấp vào hậu hành động và thêm Hành động chạy tập lệnh mới :

Trong 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

Trong Xcode 5, sử dụng giá trị này để PKGthay thế:

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

Trong trường hợp kiểm soát phiên bản của bạn không lưu trữ thông tin Xcode Scheme, tôi đề nghị thêm đoạn mã này dưới dạng shell script vào dự án của bạn để bạn có thể khôi phục hành động đơn giản bằng cách kéo tập lệnh từ không gian làm việc vào hậu hành động.

Viết kịch bản

Có hai loại tập lệnh khác nhau: JavaScript trong Tệp định nghĩa phân phối và Tập lệnh Shell.

Tài liệu tốt nhất về Shell ScScript tôi tìm thấy trong WhiteBox - Gói hướng dẫn cách làm , nhưng hãy đọc nó một cách thận trọng vì nó đề cập đến định dạng gói cũ.

Đọc thêm

Các vấn đề và cách giải quyết đã biết

Điểm đến chọn ngăn

Người dùng được cung cấp tùy chọn chọn đích chỉ với một lựa chọn duy nhất - "Cài đặt cho tất cả người dùng máy tính này". Tùy chọn xuất hiện được chọn trực quan, nhưng người dùng cần nhấp vào nó để tiến hành cài đặt, gây ra một số nhầm lẫn.

Ví dụ hiển thị lỗi trình cài đặt

Tài liệu Táo khuyến nghị sử dụng <domains enable_anywhere ... />nhưng điều này sẽ kích hoạt Điểm đến mới có lỗi hơn Chọn ngăn mà Apple không sử dụng trong bất kỳ Gói nào của họ.

Sử dụng deprecate <options rootVolumeOnly="true" />cung cấp cho bạn Điểm đến cũ Chọn. Ví dụ hiển thị Điểm đến cũ Chọn Ngăn


Bạn muốn cài đặt các mục vào thư mục nhà của người dùng hiện tại.

Câu trả lời ngắn gọn: ĐỪNG THỬ NÓ!

Câu trả lời dài: THẬT SỰ; ĐỪNG CỐ THỬ NÓ! Đọc các vấn đề và giải pháp cài đặt . Bạn biết những gì tôi đã làm ngay cả sau khi đọc điều này? Tôi đã đủ ngu ngốc để thử nó. Nói với bản thân tôi Tôi chắc chắn rằng họ đã khắc phục các sự cố trong 10.7 hoặc 10.8.

Trước hết tôi thỉnh thoảng thấy Điểm đến được chọn ở trên. Điều đó đáng lẽ đã ngăn tôi lại, nhưng tôi lờ nó đi. Nếu bạn không muốn dành cả tuần sau khi bạn phát hành phần mềm trả lời e-mail hỗ trợ mà họ phải nhấp một lần thì lựa chọn màu xanh đẹp KHÔNG sử dụng cái này.

Bây giờ bạn đang nghĩ rằng người dùng của bạn đủ thông minh để tìm ra bảng điều khiển, phải không? Vâng, đây là một điều khác về cài đặt thư mục nhà, HỌ KHÔNG LÀM VIỆC!

Tôi đã thử nghiệm nó trong hai tuần trên khoảng 10 máy khác nhau với các phiên bản HĐH khác nhau và không, và nó không bao giờ thất bại. Vì vậy, tôi đã vận chuyển nó. Trong vòng một giờ kể từ khi phát hành, tôi lấy lại từ những người dùng không thể cài đặt nó. Nhật ký gợi ý các vấn đề về quyền mà bạn sẽ không thể khắc phục.

Vì vậy, hãy lặp lại một lần nữa: Chúng tôi không sử dụng Trình cài đặt để cài đặt thư mục nhà!


RTFD cho Chào mừng, Đọc tôi, Giấy phép và Kết luận không được chấp nhận bởi productbuild.

Trình cài đặt được hỗ trợ từ các tệp RTFD ban đầu để tạo các màn hình Chào mừng đẹp bằng hình ảnh, nhưng Productbuild không chấp nhận chúng.

Giải pháp thay thế: Sử dụng tệp rtf giả và thay thế nó trong gói sau khi productbuildhoàn tất.

Lưu ý: Bạn cũng có thể có hình ảnh Retina bên trong tệp RTFD. Sử dụng tập tin tiff nhiều hình ảnh cho việc này : tiffutil -cat Welcome.tif Welcome_2x.tif -out FinalWelcome.tif. Thêm chi tiết .


Bắt đầu một ứng dụng khi quá trình cài đặt được thực hiện với tập lệnh 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

Điều quan trọng là chạy ứng dụng như người dùng đã đăng nhập, không phải là người dùng trình cài đặt. Điều này được thực hiện với đường dẫn uid launchctl asuser . Ngoài ra, chúng tôi chỉ chạy nó khi nó không phải là cài đặt dòng lệnh, được thực hiện với công cụ cài đặt hoặc Apple Remote Desktop .



9
Đây là một hướng dẫn tuyệt vời, nhưng giả sử sự tồn tại của các bó đúc sẵn. Ví dụ, nếu tôi đã cài đặt một tệp duy nhất /tmpđể được xử lý sau trong tập lệnh postflight, làm cách nào để cấu trúc danh sách thành phần? Tất cả các tài liệu có sẵn dường như cho rằng nhà phát triển đã tạo ra nó --analyze, ít nhất là ban đầu.
lỗi

1
Nếu bạn không cần thay đổi bất cứ điều gì trong thì Component Property Listbạn không cần phải chạy --analyze. Đối với các tệp hậu xử lý, tôi khuyên bạn nên đặt tất cả chúng vào một pkg và đặt vị trí cài đặt pkg đó thành /tmp. Nhưng có lẽ tôi hiểu nhầm câu hỏi của bạn. Nếu vậy hãy đăng nó trong một phiên bản chi tiết hơn trên SO.
catlan

2
Xin lưu ý rằng việc tạo các gói thông qua dòng lệnh hoàn toàn vô nghĩa, cố gắng thoát khỏi tất cả các lỗi trong ứng dụng đóng gói. Thay vào đó, hãy xem nhận xét của tôi bên dưới về việc sử dụng ứng dụng "Gói" của Stéphane Sudre để giải quyết tất cả các vấn đề cho bạn!
Bram de Jong

5
@BramdeJong "vô nghĩa". Tôi không đồng ý. Apple duy trì các công cụ dòng lệnh. Gói là một ứng dụng của bên thứ ba không được cộng đồng hỗ trợ và có thể bị hỏng trong tương lai nếu Apple thay đổi điều gì đó quyết liệt. Đối với tôi, tôi muốn biết kỹ thuật dòng lệnh để nếu Apple thay đổi điều gì đó quyết liệt, thì tôi có thể tiếp tục chạy.
Volomike

5
$ pkgbuild --root ./HelloWorld.app là sai (giả sử rằng .app là gói ứng dụng thực tế). pkgbuild hoạt động trên một root đích: tức là: một thư mục CONTAIN một gói được tạo bởi chuỗi công cụ xcode. Vì vậy, đối số cho pkgbuild là đường dẫn đến thư mục chứa gói mà chúng ta muốn gói. Không nhận được kết quả đúng này trong gói chỉ chứa thư mục nội dung ứng dụng. Nó sẽ không cài đặt như một gói ứng dụng thực tế. Giveaway là trong thành phần plist. Nếu mục đó không chứa mục RootRelativeBundlePath chỉ định gói ứng dụng thì bạn đã làm hỏng việc.
Jonathan Mitchell

185

Có một ứng dụng rất thú vị của Stéphane Sudre, đó là tất cả những điều này cho bạn, đó là kịch bản / hỗ trợ xây dựng từ dòng lệnh, có GUI siêu đẹp và MIỄN PHÍ. Điều đáng buồn là: nó được gọi là "Gói" khiến google không thể tìm thấy.

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

Tôi ước tôi đã biết về nó trước khi tôi bắt đầu làm thủ công các kịch bản của riêng mình.

Ảnh chụp màn hình ứng dụng gói


11
Tôi không thể tin rằng bài đăng này không có nhiều điểm hơn. Phần mềm đó thật tuyệt vời và nó hỗ trợ xây dựng từ dòng lệnh.
Cesar Mendoza

1
Bất cứ ai cũng cố gắng ký một gói với công cụ này? Tôi không thể lấy mục menu "Đặt chứng chỉ" để kích hoạt ....
GTAE86

2
@ user283182: Cú va chạm rất muộn, chắc chắn bạn đã tìm ra rồi, nhưng có lẽ điều này sẽ giúp ích cho người khác - Tôi nghĩ rằng vấn đề bạn đang gặp phải được nêu chi tiết trong [Nguyên tắc đánh giá Mac App Store] ( developer.apple.com/app- lưu trữ / đánh giá / hướng dẫn / mac / trên ), quy tắc 2.14: "Ứng dụng phải được đóng gói và gửi bằng các công nghệ đóng gói của Apple có trong Xcode - không cho phép trình cài đặt của bên thứ ba."
người cao tuổi

4
Tôi ước đây là một ứng dụng trả phí và nhà phát triển liên tục cập nhật và vá lỗi. Gói.app là tuyệt vời đặc biệt nếu bạn muốn nhanh chóng triển khai ứng dụng của mình. Tôi mất tổng cộng 3 phút để cài đặt đọc Tổng quan, thiết lập dự án của tôi và tạo gói có thể cài đặt. Thanh danh lớn đến Stéphane.
Nikolay Christov

1
Ứng dụng này thật tuyệt vời!
Spencer Müller Diniz

3

FYI cho những người đang cố gắng tạo trình cài đặt gói cho gói hoặc plugin, thật dễ dàng:

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

2
FYI, có một sự khác biệt giữa việc tạo .pkg và tạo một trình cài đặt thực sự với màn hình chào mừng, giấy phép, v.v.
catlan

vâng tôi biết, tôi đặt cái này ở đây vì tôi không thể tìm thấy tài liệu tham khảo để tạo trình cài đặt pkg cho plugin.
gngrwzrd

Điều này khiến tôi lăn lộn. Chỉ cần tối thiểu để cung cấp cho nền tảng.
uchuugaka

3

+1 cho câu trả lời được chấp nhận:

Lựa chọn điểm đến trong Trình cài đặt

Nếu lựa chọn tên miền (còn gọi là đích) được mong muốn giữa miền người dùng và miền hệ thống thì thay vì thử <domains enable_anywhere="true">sử dụng như sau:

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

enable_cienUserHome cài đặt ứng dụng ứng dụng bên dưới ~/Applications/enable_localSystemcho phép ứng dụng được cài đặt bên dưới/Application

Tôi đã thử điều này trong El Capitan 10.11.6 (15G1217) và có vẻ như nó hoạt động hoàn toàn tốt trong 1 máy dev và 2 VM khác nhau mà tôi đã thử.


Điều này hoạt động tốt, nhưng với GOT'CHA: Nếu bạn lần đầu tiên cài đặt cho mỗi người dùng, sau đó cài đặt cho mỗi máy, cài đặt sẽ ở trong thư mục người dùng, không phải là máy-dir, nhưng có quyền sudo. Điều ngược lại không phải là trường hợp: bạn có thể cài đặt cho mỗi máy, sau đó mỗi người dùng sau đó và có nó ở cả hai nơi.
Terje Dahl

@TerjeDahl vâng, điều này là do cài đặt bài đăng, gói được chuyển đến vị trí cùng một gói id đã được cài đặt trước đó bởi trình cài đặt (và trình cài đặt biết điều đó). Điều này có thể được ngăn chặn bởi một số cài đặt trong tệp kê khai mà tôi không nhớ ngay bây giờ.
PnotNP

@ PnotNP À. Nếu bạn thật tử tế khi quay lại với những thiết lập đó nếu bạn có thể nhớ, thì đó sẽ là điều tuyệt vời!
Terje Dahl

2

Đây là một tập lệnh xây dựng để tạo ra một gói trình cài đặt đã ký từ gốc xây dựng.

#!/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
Có, pkgbuild tạo trình cài đặt .pkg.
Doug Richardson
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.