Publish to the App Store on Windows, from .ipa upload to review
This tutorial walks through an iOS App Store release in the order you’ll actually do it, from enrolling in the Apple Developer Program until the app appears on the App Store, all on Windows. It’s for developers whose app already runs on a device and who are releasing for the first time. Account review and App Review each take one to several days. You can do everything else in an afternoon.
The process has six parts.
- Enroll in the Apple Developer Program.
- Register the bundle ID and create the app in App Store Connect.
- Get a distribution certificate and provisioning profile.
- Build Release with KXBuild to get an .ipa and upload it.
- Test on a device with TestFlight.
- Fill in the store listing and submit for review.
Enroll in the Apple Developer Program
To publish on the App Store you must join the Apple Developer Program. It costs US$99 per year (local pricing varies) and renews yearly. If it lapses, your apps are removed from the store. Turn on two-factor authentication for your Apple ID before you enroll.
There are two account types, individual and organization. You can’t simply switch between them after enrolling, so pick based on whose name should appear on the store.
| Account type | What you need | Developer name on the App Store |
|---|---|---|
| Individual | Your government-issued photo ID and Apple ID | Your legal name |
| Organization | A D-U-N-S Number, a company website, and someone with the authority to sign agreements for the company | Your company name |
The smoothest way to enroll is the Apple Developer app on iPhone. Sign in, tap “Enroll Now”, and follow the prompts to scan your ID and pay. For an organization account, request a free D-U-N-S Number through Apple’s page first. It usually takes one to two weeks. After payment Apple reviews the account, typically within a day or two, and occasionally asks for more documents.
Register the bundle ID
Sign in at developer.apple.com and go to Certificates, Identifiers & Profiles. On the Identifiers page, click “+”, choose App IDs, choose type App, select Explicit and enter the bundle ID from your project, for example com.yourname.mytodo. If the app uses capabilities such as push notifications, iCloud or Sign in with Apple, check them under Capabilities on the same page.
The bundle ID must match the project exactly. If you’re not sure what the project uses, check Bundle Identifier on the General page of the Project Settings Editor.
Create the app in App Store Connect
Sign in at appstoreconnect.apple.com, go to Apps, click “+” in the top-left corner and choose “New App”. Fill in these fields.
- Platforms. Choose iOS.
- Name. The name shown on the store, up to 30 characters and unique across the store. If it’s taken, choose another.
- Primary Language. The store falls back to this language when there’s no localized listing for a region.
- Bundle ID. Select the bundle ID you registered in the previous step.
- SKU. An internal reference for your own use that isn’t shown to anyone, for example
mytodo001.
Don’t fill in the store listing yet. Do it together once the build has uploaded.
Get a distribution certificate and provisioning profile
You need two files, an Apple Distribution certificate (.p12, with its private key) and an App Store provisioning profile (.mobileprovision). App Store profiles aren’t tied to devices, so there are no UDIDs to register.
On Windows you can sign in to your developer account in Appuploader to create the certificate and profile, export them from the keychain on a Mac, or generate a CSR with OpenSSL and request the certificate on the developer website. See Certificates and signing for all three, and Get iOS certificates and provisioning profiles on Windows for the full OpenSSL steps. Put the files in the keychain folder in the project root and add one line in the form file=password to password.properties.
1distribution.p12=123456
Each account can only have a limited number of Distribution certificates. Share one across the team instead of creating one per person.
Build the Release .ipa
Update the version
App Store Connect tells builds apart by two numbers. The version number (Marketing Version) is the 1.0 or 1.1 shown on the store. The build number (Current Project Version) must be higher than the last one on every upload, including when you resubmit the same version after a rejection. Change both on the General page of the Project Settings Editor.
Check two more things on the same page. If the app is iPhone-only, set the device family under Deployment to iPhone only. Otherwise it gets tested on iPad in review and you need a set of iPad screenshots too. The app icon must be complete. Put a 1024×1024 image into AppIcon in the Asset Catalog Editor. A package with missing icons is rejected at upload.
Build
Use either of these.
- VS Code extension. Switch the Build configuration node in the KXBuild view to Release (or run
KXBuild: Select Build Configurationfrom the Command Palette), then runKXBuild: Build. - Command line. Run the command that matches your project type.
For a project that uses an .xcodeproj, run this.
1kxbuild build .\MyApp.xcodeproj -c Release
For a project that uses an .xcworkspace (for example with CocoaPods), run this.
1kxbuild build .\MyApp.xcworkspace -c Release
When it’s done, you’ll find build\MyApp.ipa in the project folder, with the same layout as an Xcode export. If the build can’t find a Distribution certificate, the project’s Release configuration still points at the development certificate. Add -D CODE_SIGN_IDENTITY="Apple Distribution" on the command line to override it for now. The lasting fix is to change it under Signing in the Project Settings Editor. For more build options, see Build and configure.
Upload the .ipa
On Windows, upload with Appuploader. Sign in with your developer account, select build\MyApp.ipa on the upload page and wait for the progress to finish. If you have a Mac at hand, you can also drag the .ipa into Apple’s Transporter. The app record must already exist in App Store Connect with a matching bundle ID. See Release and App Store submission.
During upload Apple automatically checks the signature, provisioning profile, icons and Info.plist. A package that fails is rejected with a reason. Common ones are a duplicate build number, the wrong type of provisioning profile, or a missing icon size. Fix what it says, then build and upload again.
After a successful upload, Apple needs anywhere from a few minutes to tens of minutes to process the build. You’ll get an email when it’s done, and the build appears on the TestFlight tab in App Store Connect.
Test with TestFlight
Before submitting, install the release build on a device through TestFlight. A Release build doesn’t behave exactly like the Debug build you debug with, and this step catches problems that only show up in Release.
Once the build is processed, the TestFlight tab shows “Missing Compliance”. If the app only uses HTTPS and the encryption built into the system, answer the questionnaire that it doesn’t use non-exempt encryption. To skip this on every upload, and if the project has an Info.plist file, add a Boolean ITSAppUsesNonExemptEncryption set to NO with the Property List Editor.
There are two kinds of testers.
- Internal testers are members of your App Store Connect team, up to 100 people. They can install as soon as the build is processed, with no review.
- External testers can be anyone, invited by email or through a public link, up to 10,000 people. The first build of each version must pass a TestFlight review, usually within a day.
Testers install the TestFlight app on their iPhone, accept the invitation and install your app. Each build can be tested for 90 days. If the app crashes during testing, connect the phone to your PC and pull the crash reports with kxdevice. The reports show the failing function and the call stack.
1kxdevice crash pull .\crashes MyApp*
Fill in the store listing
Go back to the App Store tab in App Store Connect. Every section on the left must be complete before you can submit.
App information
Fill in the subtitle (up to 30 characters) and primary category, complete the age rating questionnaire, and set content rights as appropriate. If the app will be sold in mainland China, enter its ICP filing number as required. Apps without one can’t be offered in mainland China.
Screenshots
For iPhone, provide at least one set at 6.9-inch or 6.5-inch size. Apple scales that set for the other sizes. If the app supports iPad, you also need a set of 13-inch iPad screenshots. Each set has 1 to 10 images, in portrait or landscape.
| Display | Portrait size (pixels) |
|---|---|
| iPhone 6.9-inch | 1320×2868, 1290×2796, 1260×2736 |
| iPhone 6.5-inch | 1284×2778, 1242×2688 |
| iPad 13-inch | 2064×2752, 2048×2732 |
You can take them without a simulator. Connect the phone to your PC, leave the app on the screen you want, and run the command below. The image is saved to the current folder. Screenshots from a Pro Max or Plus model can be used as they are. For other models, extend them to one of the sizes above in an image editor.
1kxdevice screenshot -o shot1.png
Screenshots must show the app’s real UI. You can add captions and backgrounds, but not the names or device frames of other platforms, such as Android phones.
Description, keywords and URLs
- Description. Up to 4,000 characters. Say clearly what the app does. Reviewers will look for every feature you mention.
- Keywords. Up to 100 characters, separated by commas. Don’t use competitor names or words already in your app name.
- Support URL. It must open. A page with contact details is enough.
- Promotional Text. Optional. You can change it at any time without a new review.
App privacy
Every app needs a privacy policy URL. The page should say what data you collect, what it’s used for and how to contact you. Then answer the data collection questionnaire on the App Privacy page, stating for each item whether you collect contact info, location, identifiers, usage data and so on, including data collected by third-party SDKs you use. The answers appear under App Privacy on your store page and must match what the app actually does.
If your code uses APIs such as UserDefaults (including @AppStorage), file timestamps or free disk space, Apple requires you to declare the reasons in the app’s privacy manifest, PrivacyInfo.xcprivacy. Without it you’ll get an ITMS-91053 email after upload, and in serious cases the build can’t be submitted. Third-party SDKs you use must include their own privacy manifests. Double-click an .xcprivacy file to edit it in the Property List Editor.
Submit for review
In the version information on the App Store tab, click “+” under Build and select the build you uploaded. Then fill in App Review Information.
- Sign-in information. If the app requires sign-in, provide a demo account and password for review, with data already in it. If sign-in needs an SMS code, explain in the notes how to get past it, or give that account a fixed code.
- Contact information. The person App Review contacts if there’s a problem.
- Notes. If a feature is buried deep, needs specific hardware or only works in certain regions, explain how to test it here.
Finally choose how to release the version once it’s approved, automatically, manually or on a scheduled date. For a first release, manual is recommended so you can check everything before releasing. Click “Add for Review” in the top-right corner, then “Submit for Review”.
The status changes to “Waiting for Review”, then “In Review”, and you’ll be notified of the result by email. Most apps get a result within a day or two.
Common rejection reasons
After a rejection, the App Review message in App Store Connect shows the guideline number and an explanation, sometimes with screenshots or crash logs. Fix the issue, increase the build number, upload again, then select the new build in the same version and resubmit. If the problem is only in the metadata, there’s no need to upload a new build. Make the change, reply to the review message and resubmit. If you disagree with the decision, reply in the message to explain first. If that doesn’t resolve it, appeal to the App Review Board.
2.1 App completeness, crashes and bugs
Reviewers test on physical devices running the latest iOS. Crashing at launch, buttons that do nothing and leftover placeholder content all get rejected. The crash log attached to the review message shows where it failed. Before submitting, go through the main flows with a Release build on a phone running the latest iOS. That’s what TestFlight is for.
2.1 Information needed, can’t sign in
No demo account, a wrong password, an expired account, or a sign-in that depends on a verification code only a phone number from one country can receive will all get a request for more information. Provide an account that stays valid and explain how to sign in in the notes. Under guideline 4.8, an app that only offers third-party sign-in (Google, Facebook, WeChat and so on) must also offer a privacy-focused sign-in option. Sign in with Apple meets this requirement.
4.2 Minimum functionality
Apps with too few features, apps that just wrap a website in a WebView, or apps whose content is identical to the website are often rejected under 4.2. Review wants to see value in the app itself. Common fixes are adding native capabilities such as offline use, push notifications, the system share sheet or widgets, or building the core features as native screens.
5.1.1 Data collection and storage
A few common cases. The privacy policy link doesn’t open or is incomplete. The purpose strings for camera, photos, location and other permissions are too vague. They must state the specific use, for example “Used to scan package tracking numbers”, and live in the NS…UsageDescription keys in Info.plist. Features that don’t need an account force the user to register or sign in. The app lets users create an account but not delete it inside the app.
2.3 Accurate metadata
Screenshots that aren’t the app’s real UI, a description of features the app doesn’t have, competitor names stuffed into keywords, or words like “Android” or “beta” in the app or screenshots all get rejected under 2.3. You don’t need to upload a new build for these. Fix the metadata and resubmit.
Will a package built without Xcode pass review?
App Review is based on the App Store Review Guidelines. It looks at the app’s features, stability, privacy handling and store listing, and doesn’t treat an app differently based on which computer or tool built it. A build that passes the upload checks goes through the same review as any other, and the .ipa KXBuild produces has the same layout as an Xcode export.
Whether an app passes review is ultimately Apple’s decision under the guidelines, and no tool can guarantee it.