appuploader-cli CI/CD Integration: Auto-Uploading IPA

When your build pipeline runs on a machine without a Mac (a Windows/Linux CI runner, say), having to manually click a button for the final upload step is rather awkward. appuploader-cli turns that step into a single command: it is the command-line tool bundled with AppUploader, and uploading depends on neither Xcode nor macOS.

Step 1: Locate the Executable

Once the main app is installed, the command-line tool is already in the installation directory:

  • macOS: AppUploader.app/Contents/Resources/appuploader-cli
  • Windows: appuploader-cli.exe in the same directory as the main AppUploader.exe

cd into that directory to run it directly, or add the directory to your CI runner’s PATH environment variable so scripts can call it directly.

Step 2: Upload the IPA/PKG

1appuploader-cli upload -f <IPA/PKG path> -u <Apple ID> -p <app-specific password> [--type ios]
Parameter Description
-f, --file Path to the IPA / PKG file to upload (required)
-u, --username Apple ID email (required)
-p, --password App-specific password, in the format xxxx-xxxx-xxxx-xxxx (required; this is not your login password)
--type Package type: ios / osx / appletvos / xros; defaults to ios

Example:

1appuploader-cli upload -f Payload.ipa -u dev@example.com -p abcd-efgh-ijkl-mnop

The upload prints progress and result logs in real time. On failure, the log includes the specific reason (duplicate package, version number conflict, signature mismatch, etc.), so you can pinpoint the problem directly in the CI log.

Step 3 (Optional): Generate the App Store Resource Description File Locally

If you only want to validate the package contents locally before uploading, or you need an AppStoreInfo.plist for another upload tool, use the info command. It performs local analysis only and never actually uploads:

1appuploader-cli info -u <Apple ID> <file path> [-o output file] [--format xml|binary]

The --deterministic flag pins fields that would otherwise change, such as the UUID, process ID, and timestamp, making it easy to compare output byte-for-byte in CI — handy for writing automated tests.

How to Wire It Into a CI/CD Pipeline

Whether you use Jenkins, GitHub Actions, or any other CI system, the integration is the same: after the build produces the IPA, add a step that runs the appuploader-cli upload command, and inject the credentials through the pipeline’s secret / environment-variable mechanism instead of hardcoding them in the script. Because appuploader-cli itself does not depend on macOS, your CI runner does not need to be a Mac either.

When an upload fails, the command’s exit code is non-zero, so the pipeline can simply use the exit code to decide whether this step succeeded — no log parsing required:

1set -e
2appuploader-cli upload -f "$WORKSPACE/build/App.ipa" -u "$APPLE_ID" -p "$APP_SPECIFIC_PASSWORD"

Using an API Key Instead of a Personal Account

Hardcoding someone’s Apple ID and password into the pipeline means the automation breaks as soon as that person leaves or the password changes. For teams, an App Store Connect API key is the better fit — it belongs to the team and can be revoked independently:

1appuploader-cli upload -f build/App.ipa \
2  --api-key "$ASC_KEY_ID" \
3  --api-issuer "$ASC_ISSUER_ID" \
4  --private-key AuthKey.p8

Generate the key at https://appstoreconnect.apple.com/access/api; the .p8 private key can only be downloaded once. In CI, store the contents of the .p8 as a secret, write it to a temporary file when needed, and delete it afterward. These three parameters and -u/-p are two different methods — you can only use one set.

Note that the API key method supports only .ipa, and the bundle ID must already have an app created in App Store Connect; for .pkg on macOS, still use -u/-p.