# Mac App Store (MAS) submission guide (manual steps) This repo supports a **Mac App Store build mode** (`BUILD_FOR_MAC_APP_STORE=ON`) and includes scripts to build a signed upload `.pkg`. If you’re blocked because `security find-identity` only shows **Developer ID** and not **Apple Distribution / Installer**, follow the steps below. --- ## Open Keychain Access (macOS “hidden” Utilities) Any of these work: - **Spotlight**: press `⌘ + Space` → type **Keychain Access** → Enter - **Finder**: Applications → Utilities → **Keychain Access** - **Terminal**: ```bash open -a "Keychain Access" ``` --- ## The core issue: certificate exists but is not a usable identity If you see certificates like: - `Apple Distribution: ...` - `3rd Party Mac Developer Installer: ...` but `security find-identity` does **not** list them, then the certificate is present but **the private key is missing** (or not paired / in the wrong keychain). You can confirm with: ```bash ./build_tools/macos/check_signing_identities.sh ``` --- ## Step 1 — Create the private keys on this Mac (CSR) 1. Open **Keychain Access** 2. Menu: **Keychain Access → Certificate Assistant → Request a Certificate From a Certificate Authority…** 3. Fill: - **User Email Address**: your Apple ID email - **Common Name**: e.g. `Dry Ark LLC` (any label is fine) - **CA Email Address**: leave blank - Select: **Saved to disk** 4. Save the CSR (`.certSigningRequest`) somewhere safe This CSR step is what creates the **private key** locally in your login keychain. --- ## Step 2 — Create + download the certificates (Apple Developer portal) In Apple Developer → **Certificates, Identifiers & Profiles** → **Certificates** → **+**: - Create **Apple Distribution** (use the CSR you just made) - Create **Mac Installer Distribution** (or “3rd Party Mac Developer Installer”, wording varies) (use a CSR) Download the resulting `.cer` files. --- ## Step 3 — Install certificates into your login keychain Double-click each downloaded `.cer` to install it. Then in **Keychain Access → login → My Certificates**: - Find **Apple Distribution: ...** and **expand it** - You must see a **private key** under it. - Find **... Installer ...** and expand it - You must see a **private key** under it. If there’s no private key under the certificate, it will not be usable for signing on this Mac. --- ## Step 4 — Verify identities from the CLI ### Common failure: errSecInternalComponent / chain-to-root warnings If you see errors like: - `Warning: unable to build chain to self-signed root for signer "Apple Distribution: ..."` - `errSecInternalComponent` This is almost always a **keychain search list / trust chain** issue. #### Important: do NOT “Always Trust” your Apple Distribution / Installer certs Setting your leaf signing certificates (e.g. **Apple Distribution** / **3rd Party Mac Developer Installer**) to **Always Trust** can make things worse by overriding the normal trust chain and causing codesign to fail chain building. If you changed trust settings: - In **Keychain Access → login → My Certificates** - open the cert → **Trust** - set **“When using this certificate” = “Use System Defaults”** Fix (safe, common): ensure the System keychains are included in the user search list: ```bash security list-keychains -d user security list-keychains -d user -s "$HOME/Library/Keychains/login.keychain-db" "/Library/Keychains/System.keychain" "/System/Library/Keychains/SystemRootCertificates.keychain" ``` Then re-run the build/sign script. #### Install the correct Apple intermediate certificates (WWDR) If the System keychains are already in the search list and you still get chain errors, you’re likely missing an Apple intermediate (commonly **WWDR**). Download the current Apple WWDR intermediate certificate(s) from Apple’s official Certificate Authority page: - `https://www.apple.com/certificateauthority/` Then import into the **System** keychain (recommended): - Keychain Access → **System** keychain → File → **Import Items…** → select the downloaded `.cer` Or via CLI (requires admin): ```bash sudo security add-certificates -k /Library/Keychains/System.keychain "/path/to/WWDR.cer" ``` Verify it’s visible: ```bash security find-certificate -a -c "Apple Worldwide Developer Relations" /Library/Keychains/System.keychain | head -n 10 ``` If needed, you can also verify the chain for your distribution cert: ```bash security verify-cert -c "Apple Distribution: Dry Ark LLC (7628766FL2)" 2>&1 | head -n 80 ``` ```bash security find-identity -p codesigning -v security find-identity -p basic -v ./build_tools/macos/check_signing_identities.sh ``` Expected: - `Apple Distribution: ...` shows up under **codesigning** - `... Installer ...` shows up as an **installer identity** (used to sign upload `.pkg`) --- ## Step 5 — Create + install the provisioning profile (Mac App Store) In Apple Developer → **Profiles** → **+**: - Platform: **macOS** - Type: **Mac App Store** - App ID: `com.dryark.strawberry` (or your own bundle id) - Select the **Apple Distribution** certificate - Generate + Download ### Where the `.provisionprofile` ends up (newer Xcode/macOS) Recent Xcode versions store “downloaded manual profiles” under: - `~/Library/Developer/Xcode/UserData/Provisioning Profiles/` Older tooling sometimes used: - `~/Library/MobileDevice/Provisioning Profiles/` This repo’s MAS build script does **not** require the profile to be in a specific folder — you can pass the path directly. To locate and pick the right profile, use: ```bash ./build_tools/macos/find_mas_provisioning_profile.sh --bundle-id com.dryark.strawberry ``` ### (Optional) Copy to the legacy folder If some other tools expect the legacy folder, you can copy it there: ```bash mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles" cp -f "/path/to/profile.provisionprofile" "$HOME/Library/MobileDevice/Provisioning Profiles/" ``` --- ## Step 6 — Build the signed upload package (.pkg) This repo provides: - `build_tools/macos/build_mas_pkg.sh` (build → deploy → embed profile → sign → productbuild) Example: ```bash ./build_tools/macos/build_mas_pkg.sh --run --release --clean \ --codesign-identity "Apple Distribution: Dry Ark LLC (7628766FL2)" \ --installer-identity "3rd Party Mac Developer Installer: Dry Ark LLC (7628766FL2)" \ --provisionprofile "$HOME/Library/MobileDevice/Provisioning Profiles/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.provisionprofile" ``` Outputs: - `cmake-build-macos-release-mas/strawberry.app` - `cmake-build-macos-release-mas/strawberry-mas.pkg` --- ## Architecture note — arm64 vs universal (arm64+x86_64) For Mac App Store uploads, your `.pkg` can contain either: - **arm64-only** app (Apple Silicon only), or - **universal** app (arm64 + x86_64), or - **x86_64-only** app (runs on Apple Silicon under Rosetta 2, but native Intel only otherwise) Apple does **not** require universal binaries for review. **arm64-only is allowed**, but: - Intel Macs **cannot** run an arm64-only app. - If you ship arm64-only, App Store Connect will effectively make the app available only to Apple Silicon Macs (and your listing will reflect that). ### Recommendation - If you want the broadest compatibility, aim for a **universal build**. - If you’re okay supporting only Apple Silicon Macs, arm64-only is the simplest path. ### Can I upload two different `.pkg`s (one arm64, one x86_64)? Not in the way you want. - In App Store Connect you can upload multiple builds over time, but for any given version/submission you ultimately pick **one build** to submit. - Apple will not “merge” two separate uploads (arm64-only + x86_64-only) into one app for customers. If you want both Apple Silicon and Intel supported **natively**, you need to produce a **single universal** app bundle and package that into **one** `.pkg`. If you don’t want to deal with universal yet, your practical choices are: - **arm64-only**: Apple Silicon only. - **x86_64-only**: runs on Intel natively, and on Apple Silicon under **Rosetta 2** (slower, but widely compatible). ### Practical reality for this repo This project depends on large native dependency stacks (Qt, GStreamer, plugins). If you build those via Homebrew, you typically end up with **single-architecture** libraries (arm64 under `/opt/homebrew`, x86_64 under `/usr/local`). A true universal app requires **all bundled native code** (your executable *and* all `.dylib`/plugins/frameworks you ship) to be universal as well. If you decide you want universal: - You’ll need a universal build of **Qt** and **GStreamer** (and all bundled plugins), or - Build arm64 and x86_64 bundles separately and combine *matching* binaries where possible (advanced; easy to break signing / plugin loading). --- ## Troubleshooting — `productbuild` fails with CSSM `-60008` (authorization) If you see something like: - `SignData failed ... CSSM Exception: -60008 Unable to obtain authorization for this operation` That means the **Installer** certificate is present, but macOS is not allowing `productbuild` to use the **private key** without additional authorization. ### Fix option A (recommended): set key partition list (CLI) This is the standard “allow Apple tools to sign without GUI prompts” fix: ```bash security unlock-keychain "$HOME/Library/Keychains/login.keychain-db" security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "" "$HOME/Library/Keychains/login.keychain-db" ``` Note: if your password contains characters like `!` or `$` and you paste it into a command in `zsh`, the shell can modify it (history/variable expansion) and `security ... -k` may claim it’s “incorrect”. Use **single quotes** (or the env var path shown below) to avoid this, e.g.: ```bash security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k 'p@ssw0rd!$' "$HOME/Library/Keychains/login.keychain-db" ``` Then rerun: ```bash ./build_tools/macos/build_mas_pkg.sh --run ... ``` This repo’s script also supports: - `--keychain-password ` (or env var `STRAWBERRY_KEYCHAIN_PASSWORD`) ### Fix option B: Keychain Access UI (one-time) 1. Open **Keychain Access** 2. Select **login** keychain → **My Certificates** 3. Find your installer cert (e.g. `3rd Party Mac Developer Installer: ...`) and **expand it** 4. Select the **private key** under it 5. **Get Info → Access Control** - Add `/usr/bin/productbuild` (and optionally `/usr/bin/pkgbuild`) to the allowed apps --- ## Step 7 — Upload + submit for review ### 7.1 Install Apple “Transporter” (the upload tool) Apple requires Mac App Store submissions to be uploaded using **Transporter** (a macOS app published by Apple). Where to get it: - Install **Transporter** from the **Mac App Store** (search for “Transporter”). - App Store listing name is typically **“Transporter”** by Apple. ### 7.2 Upload the `.pkg` with Transporter 1. Open **Transporter** 2. Sign in with the Apple ID that has access to **App Store Connect** 3. Click **Add App** (or **+**) and choose your signed upload package: - `cmake-build-macos-release-mas/strawberry-mas.pkg` (or your custom `--pkg-out` path) 4. Click **Deliver** 5. Wait for upload + server-side validation to complete Notes: - Uploading can take a while depending on your connection. - If Transporter reports an error, the message usually includes the exact App Store Connect requirement you violated (bundle id mismatch, missing entitlements, invalid signature, etc.). ### 7.3 Submit the build in App Store Connect 1. Open **App Store Connect** in your browser and go to **My Apps** 2. Select your app, then go to the **macOS App** platform section 3. Find your uploaded build under **TestFlight** or **Prepare for Submission** (Apple’s UI wording changes over time) 4. Wait for Apple to finish “Processing” the build 5. Select the build for your version, complete required metadata, then click **Submit for Review** ### (Optional) CLI upload (advanced): `iTMSTransporter` If you prefer uploading from the command line, Apple’s underlying uploader is **iTMSTransporter**. On most systems it’s available via Xcode command line tools as: ```bash xcrun iTMSTransporter -help ``` CLI upload requires additional credentials (App Store Connect API key or Apple ID auth) and is easier to get wrong than the Transporter GUI. For most folks, **Transporter.app is the recommended path**. --- ## Creating a universal Mac App Store upload using two Macs (arm64 + x86_64) If you have both an Apple Silicon Mac and an Intel Mac, the most reliable way to ship a universal app for this repo is: 1. Build + deploy the **unsigned** MAS app bundle on each machine (arm64 and x86_64). 2. Copy both `.app` bundles to the machine that has your signing keys. 3. Merge them with `lipo` and then **sign + package** once, producing a single universal `.pkg`. ### Step A — Build + deploy (arm64 machine) On your Apple Silicon Mac: ```bash ./build_tools/macos/build_app.sh --release --clean --mas --deploy --build-dir ./cmake-build-macos-release-mas-arm64 ``` This produces (unsigned): - `cmake-build-macos-release-mas-arm64/strawberry.app` ### Step B — Build + deploy (x86_64 machine) On your Intel Mac: ```bash ./build_tools/macos/build_app.sh --release --clean --mas --deploy --build-dir ./cmake-build-macos-release-mas-x86_64 ``` This produces (unsigned): - `cmake-build-macos-release-mas-x86_64/strawberry.app` ### Step C — Copy both app bundles to one “packaging” machine Pick the Mac that has your **Apple Distribution** and **Installer** identities (private keys) installed. Copy both `.app` bundles onto that Mac, for example: - `/path/to/inputs/strawberry-arm64.app` - `/path/to/inputs/strawberry-x86_64.app` Tip: `rsync` works well for app bundles: ```bash rsync -a "/path/to/arm64/strawberry.app" "/path/to/inputs/strawberry-arm64.app" rsync -a "/path/to/x86_64/strawberry.app" "/path/to/inputs/strawberry-x86_64.app" ``` ### Step D — Merge + sign + build the universal `.pkg` On the packaging machine: ```bash ./build_tools/macos/build_mas_universal_pkg.sh --run \ --arm-app "/path/to/inputs/strawberry-arm64.app" \ --x86-app "/path/to/inputs/strawberry-x86_64.app" \ --codesign-identity "Apple Distribution: Your Name (TEAMID)" \ --installer-identity "3rd Party Mac Developer Installer: Your Name (TEAMID)" \ --provisionprofile "/path/to/profile.provisionprofile" ``` Outputs: - `cmake-build-macos-release-mas-universal/strawberry.app` (universal) - `cmake-build-macos-release-mas-universal/strawberry-mas-universal.pkg` ### Important constraints (don’t skip) - The two input apps must be built from the **same commit** with the **same enabled features** so the app bundle layouts match. - Do **not** sign the per-arch apps first; `lipo` invalidates signatures. Sign **only after** merging.