51

Previously, with Xcode 10, we were using altool to upload to App Store:

ALTOOL="/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Support/altool"
"$ALTOOL" --upload-app --file "$IPA_PATH" --username "$APP_STORE_USERNAME" --password @keychain:"Application Loader: $APP_STORE_USERNAME"

But with Xcode 11, "Application Loader.app" doesn't exist anymore, as part of the Xcode 11 changes:

Xcode supports uploading apps from the Organizer window or from the command line with xcodebuild or xcrun altool. Application Loader is no longer included with Xcode. (29008875)

So how do we upload from command line to TestFlight or App Store now?

Cœur
  • 37,241
  • 25
  • 195
  • 267

5 Answers5

68

With Xcode 11 as command line tools, to validate or upload an ipa, replace altool with xcrun altool:

xcrun altool --validate-app --file "$IPA_PATH" --username "$APP_STORE_USERNAME" --password @keychain:"Application Loader: $APP_STORE_USERNAME"

xcrun altool --upload-app --file "$IPA_PATH" --username "$APP_STORE_USERNAME" --password @keychain:"Application Loader: $APP_STORE_USERNAME"

Get more help with xcrun altool --help.

Cœur
  • 37,241
  • 25
  • 195
  • 267
  • 4
    You may need to run `sudo xcode-select -r` at the command line one time before `xcrun altool` will work, in order to select the version of XCode to use. You don't have to manually provide the version, just that line should work. I learned this from a [github issue](https://github.com/electron/electron-notarize/issues/5) – IowaEric Sep 23 '19 at 17:46
  • 4
    The **password** is not your Apple account password, but the One-Time (Application) password from https://appleid.apple.com/account/manage – boweidmann Oct 08 '19 at 09:45
  • 8
    You may also want to create an API key -> then you don't need username & password at all, just the private key inside the *AuthKey_$APIKEY.p8* file – boweidmann Oct 08 '19 at 09:47
  • 1
    For reference, as non-command line solutions, you have either Xcode or [Transporter](https://apps.apple.com/app/transporter/id1450874784?mt=12). – Cœur Oct 16 '19 at 12:00
  • @boweidmann are there instructions somewhere on how to do this? – fullStackChris Nov 09 '22 at 10:24
  • 1
    @fullStackChris just posted a full answer below, hope it helps – boweidmann Nov 14 '22 at 14:10
32

Use command line tools,

xcrun altool --upload-app -f path -u username -p password

If your apple account use TWO-FACTOR Authentication , your password would be wrong , you need to go to https://appleid.apple.com/account/manage "Security - Generate Password" to get the password

If you get other wrong , you could add --verbose to print detail errors log, just like

xcrun altool --upload-app -f path -u username -p password --verbose

And , get more help with xcrun altool --help

forgot2015
  • 490
  • 5
  • 12
  • 2
    This helped me, but the page at that link has a different format now. You need to click on App Specific Passwords and create one there and use that. – Andy Weinstein May 24 '22 at 14:48
12

At least as of of Xcode 11, this can be done very easily and directly with xcodebuild, as part of the export workflow. Just create an exportOptions.plist file that specifies "upload" for the "destination" key and "app-store" for the "method" key. Here's an example, but of course tune to your needs:

<?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>compileBitcode</key>
        <true/>
        <key>destination</key>
        <string>upload</string>
        <key>method</key>
        <string>app-store</string>
        <key>provisioningProfiles</key>
        <dict>
                <key>YOUR_BUNDLE_ID</key>
                <string>YOUR_PROFILE_NAME</string>
        </dict>
        <key>signingCertificate</key>
        <string>YOUR_CERT_NAME</string>
        <key>signingStyle</key>
        <string>manual</string>
        <key>stripSwiftSymbols</key>
        <true/>
        <key>teamID</key>
        <string>YOUR_TEAM_ID</string>
        <key>thinning</key>
        <string>&lt;none&gt;</string>
</dict>
</plist>

Once you have that, the command to upload an archive to app store connect is very simple, using the xcodebuild exportArchive command:

    xcodebuild -exportArchive \
               -archivePath PATH_TO_APP_ARCHIVE \
               -exportPath OUTPUT_PATH \
               -exportOptionsPlist exportOptions.plist

If you're wondering where your PATH_TO_ARCHIVE is, first just use the xcodebuild archive command, e.g.:

    xcodebuild -sdk iphoneos \
               -workspace myWorkspace.xcworkspace \
               -scheme myScheme \
               -configuration Release \
               -archivePath PATH_TO_ARCHIVE archive
Cœur
  • 37,241
  • 25
  • 195
  • 267
biomiker
  • 3,108
  • 1
  • 29
  • 26
  • 2
    I set this up recently but now am getting `Failed to log in.` I think I need to get a new app-specific password, but I can't for the life of me remember where you stick the password... Not in `exportOptions.plist`... Where does the password go? – mgalgs Oct 02 '20 at 18:19
  • @mgalgs I've always assumed that the credentials are inherited from XCode by way of the keychain, but I don't know how to solve this problem. The only think I'd think to try on my own is to restart XCode and make sure that I could upload to app store manually. – biomiker Oct 03 '20 at 15:54
  • @mgalgs I am facing exactly the same issue (Failed to log in) when executing the command from our CI server. When I run it locally everything works fine so I could only assume that someone should create a temp keychain and import his/her appleId & credentials there. Did you find a solution? (I guess altool would be the plan B in our case) – Petros Mitakos Mar 10 '21 at 08:06
  • Check if the appleId is has logged in the XCode: https://stackoverflow.com/a/55699898/1999185 – clarkttfu Apr 15 '21 at 17:09
6

You can now also use a new app from Apple called "Transporter" that is a replacement for Xcode application loader.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Serdar Mustafa
  • 835
  • 2
  • 9
  • 20
2

Another way to validate/upload the .ipa without having to generate one time password every time:

To validate run:

xcrun altool --validate-app -f {YOURAPP}.ipa -t ios --apiKey {YOUR KEY ID} --apiIssuer {YOUR ISSURE ID}

To upload to App Store run:

xcrun altool --upload-app -f {YOURAPP}.ipa -t ios --apiKey {YOUR KEY ID} --apiIssuer {YOUR ISSURE ID}
boweidmann
  • 3,312
  • 2
  • 20
  • 27
  • 2
    To add to this, you'll need to put your newly downloaded .p8 file in one of these locations ~/{PATH_TO_PROJECT_FOLDER}/private_keys', '~/private_keys', '~/.private_keys', '~/.appstoreconnect/private_keys' – marcus.salinas Feb 18 '23 at 23:58