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 .
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 --expand
và pkgutil --flatten
cá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 .
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 để PKG
thay 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.
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.
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 productbuild
hoà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 .