Xcode “Build and Archive” from command line

2018-12-31 16:05发布

Xcode 3.2 provides an awesome new feature under the Build menu, "Build and Archive" which generates an .ipa file suitable for Ad Hoc distribution. You can also open the Organizer, go to "Archived Applications," and "Submit Application to iTunesConnect."

Is there a way to use "Build and Archive" from the command line (as part of a build script)? I'd assume that xcodebuild would be involved somehow, but the man page doesn't seem to say anything about this.

UPDATE Michael Grinich requested clarification; here's what exactly you can't do with command-line builds, features you can ONLY do with Xcode's Organizer after you "Build and Archive."

  1. You can click "Share Application..." to share your IPA with beta testers. As Guillaume points out below, due to some Xcode magic, this IPA file does not require a separately distributed .mobileprovision file that beta testers need to install; that's magical. No command-line script can do it. For example, Arrix's script (submitted May 1) does not meet that requirement.
  2. More importantly, after you've beta tested a build, you can click "Submit Application to iTunes Connect" to submit that EXACT same build to Apple, the very binary you tested, without rebuilding it. That's impossible from the command line, because signing the app is part of the build process; you can sign bits for Ad Hoc beta testing OR you can sign them for submission to the App Store, but not both. No IPA built on the command-line can be beta tested on phones and then submitted directly to Apple.

I'd love for someone to come along and prove me wrong: both of these features work great in the Xcode GUI and cannot be replicated from the command line.

18条回答
十年一品温如言
2楼-- · 2018-12-31 16:32

With Xcode 4.2 you can use the -scheme flag to do this:

xcodebuild -scheme <SchemeName> archive

After this command the Archive will show up in the Xcode Organizer.

查看更多
明月照影归
3楼-- · 2018-12-31 16:34

The xcodebuild tool can build and export archive products with the -exportArchive flag (as of Xcode 5). The export step was previously only possible via the Xcode Organizer UI.

First archive your app:

xcodebuild -scheme <scheme name> archive

Given $ARCHIVE_PATH (the path to the .xcarchive file), export the app from the archive with one of the following:

iOS .ipa file:

xcodebuild -exportArchive -exportFormat ipa -archivePath "$ARCHIVE_PATH" -exportPath "myApp.ipa" -exportProvisioningProfile "My App Provisioning profile"

Mac .app file:

xcodebuild -exportArchive -exportFormat app -archivePath "$ARCHIVE_PATH" -exportPath "myApp.app" -exportSigningIdentity "Developer ID Application: My Software Company"

In both commands the -exportProvisioningProfile and -exportSigningIdentity arguments are optional. man xcodebuild for details on the semantics. In these examples, the provisioning profile for the iOS build specified an AdHoc distribution provisioning profile, and the signing identity for the Mac app specified a Developer ID for export as a 3rd party application (i.e. not distributed via the Mac App Store).

查看更多
余生无你
4楼-- · 2018-12-31 16:37

We developed an iPad app with XCode 4.2.1 and wanted to integrate the build into our continuous integration (Jenkins) for OTA distribution. Here's the solution I came up with:

# Unlock keychain
security unlock-keychain -p jenkins /Users/jenkins/Library/Keychains/login.keychain

# Build and sign app
xcodebuild -configuration Distribution clean build

# Set variables
APP_PATH="$PWD/build/Distribution-iphoneos/iPadApp.app"
VERSION=`defaults read $APP_PATH/Info CFBundleShortVersionString`
REVISION=`defaults read $APP_PATH/Info CFBundleVersion`
DATE=`date +"%Y%m%d-%H%M%S"`
ITUNES_LINK="<a href=\"itms-services:\/\/?action=download-manifest\&url=https:\/\/xxx.xxx.xxx\/iPadApp-$VERSION.$REVISION-$DATE.plist\">Download iPad2-App v$VERSION.$REVISION-$DATE<\/a>"

# Package and verify app
xcrun -sdk iphoneos PackageApplication -v build/Distribution-iphoneos/iPadApp.app -o $PWD/iPadApp-$VERSION.$REVISION-$DATE.ipa

# Create plist
cat iPadApp.plist.template | sed -e "s/\${VERSION}/$VERSION/" -e "s/\${DATE}/$DATE/" -e "s/\${REVISION}/$REVISION/" > iPadApp-$VERSION.$REVISION-$DATE.plist

# Update index.html
curl https://xxx.xxx.xxx/index.html -o index.html.$DATE
cat index.html.$DATE | sed -n '1h;1!H;${;g;s/\(<h3>Aktuelle Version<\/h3>\)\(.*\)\(<h3>&Auml;ltere Versionen<\/h3>.<ul>.<li>\)/\1\
${ITUNES_LINK}\
\3\2<\/li>\
<li>/g;p;}' | sed -e "s/\${ITUNES_LINK}/$ITUNES_LINK/" > index.html

Then Jenkins uploads the ipa, plist and html files to our webserver.

This is the plist template:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>items</key>
    <array>
        <dict>
            <key>assets</key>
            <array>
                <dict>
                    <key>kind</key>
                    <string>software-package</string>
                    <key>url</key>
                    <string>https://xxx.xxx.xxx/iPadApp-${VERSION}.${REVISION}-${DATE}.ipa</string>
                </dict>
                <dict>
                    <key>kind</key>
                    <string>full-size-image</string>
                    <key>needs-shine</key>
                    <true/>
                    <key>url</key>
                    <string>https://xxx.xxx.xxx/iPadApp.png</string>
                </dict>
                <dict>
                    <key>kind</key>
                    <string>display-image</string>
                    <key>needs-shine</key>
                    <true/>
                    <key>url</key>
                    <string>https://xxx.xxx.xxx/iPadApp_sm.png</string>
                </dict>
            </array>
            <key>metadata</key>
            <dict>
                <key>bundle-identifier</key>
                <string>xxx.xxx.xxx.iPadApp</string>
                <key>bundle-version</key>
                <string>${VERSION}</string>
                <key>kind</key>
                <string>software</string>
                <key>subtitle</key>
                <string>iPad2-App</string>
                <key>title</key>
                <string>iPadApp</string>
            </dict>
        </dict>
    </array>
</dict>
</plist>

To set this up, you have to import the distribution certificate and provisioning profile into the designated user's keychain.

查看更多
裙下三千臣
5楼-- · 2018-12-31 16:37

For Xcode 7, you have a much simpler solution. The only extra work is that you have to create a configuration plist file for exporting archive.

(Compared to Xcode 6, in the results of xcrun xcodebuild -help, -exportFormat and -exportProvisioningProfile options are not mentioned any more; the former is deleted, and the latter is superseded by -exportOptionsPlist.)

Step 1, change directory to the folder including .xcodeproject or .xcworkspace file.

cd MyProjectFolder

Step 2, use Xcode or /usr/libexec/PlistBuddy exportOptions.plist to create export options plist file. By the way, xcrun xcodebuild -help will tell you what keys you have to insert to the plist file.

Step 3, create .xcarchive file (folder, in fact) as follows(build/ directory will be automatically created by Xcode right now),

xcrun xcodebuild -scheme MyApp -configuration Release archive -archivePath build/MyApp.xcarchive

Step 4, export as .ipa file like this, which differs from Xcode6

xcrun xcodebuild -exportArchive -exportPath build/ -archivePath build/MyApp.xcarchive/ -exportOptionsPlist exportOptions.plist

Now, you get an ipa file in build/ directory. Just send it to apple App Store.

By the way, the ipa file created by Xcode 7 is much larger than by Xcode 6.

查看更多
余生无你
6楼-- · 2018-12-31 16:39

Xcode 8:


IPA Format:

xcodebuild -exportArchive -exportFormat IPA -archivePath MyMobileApp.xcarchive -exportPath MyMobileApp.ipa -exportProvisioningProfile 'MyMobileApp Distribution Profile'

Exports the archive MyMobileApp.xcarchive as an IPA file to the path MyMobileApp.ipa using the provisioning profile MyMobileApp Distribution Profile.

APP Format:

xcodebuild -exportArchive -exportFormat APP -archivePath MyMacApp.xcarchive -exportPath MyMacApp.pkg -exportSigningIdentity 'Developer ID Application: My Team'

Exports the archive MyMacApp.xcarchive as a PKG file to the path MyMacApp.pkg using the appli-cation application cation signing identity Developer ID Application: My Team. The installer signing identity Developer ID Installer: My Team is implicitly used to sign the exported package.

Xcodebuild man page

查看更多
栀子花@的思念
7楼-- · 2018-12-31 16:39

After updating to Xcode 8, I found that enterprise ipa generate by

/usr/bin/xcrun -sdk iphoneos PackageApplication -v "${RELEASE_BUILDDIR}/${APPLICATION_NAME}.app" -o "${BUILD_HISTORY_DIR}/${APPLICATION_NAME}.ipa" --sign "${DEVELOPER_NAME}" --embed "${PROVISONING_PROFILE}" 

Command cannot be launched because of some signature issue. The log indicates that "warning: PackageApplication is deprecated, use xcodebuild -exportArchive instead.

So I switch to xcodebuild -exportArchive and everything went back normal.

查看更多
登录 后发表回答