Build a Unity game for iOS on Windows and test it on your iPhone
Unity on Windows can export an Xcode project for iOS, but building, installing and packaging it usually means moving to a Mac. This tutorial shows how to take the exported project on the same Windows PC, build it into an app, test it on your iPhone and produce an .ipa. You need an Apple Developer account, an iPhone and a USB cable, and you need to have installed KXBuild.
Switch to the iOS platform
Open the project in Unity and go to File > Build Profiles (File > Build Settings in Unity 2022 and earlier). Select iOS on the left and click “Switch Platform”. The first switch reimports assets, which takes a while for large projects.
“Build And Run” calls Xcode on the local machine, so it doesn’t work on Windows. This tutorial uses only “Build”.
Configure Player Settings
Click “Player Settings” in the Build Profiles window, or go to Edit > Project Settings > Player, and switch to the iOS tab. The settings below directly affect installing on a device and submitting to the App Store. In Unity 6, check Override Default Bundle Identifier before you can edit Bundle Identifier.
| Location | Setting | Recommended value |
|---|---|---|
| Other Settings > Identification | Bundle Identifier | Matches the App ID registered in your developer account, for example com.example.mygame |
| Other Settings > Identification | Version | The version shown on the App Store, for example 1.0.0 |
| Other Settings > Identification | Build | The build number. Each upload to App Store Connect needs a higher one than the last |
| Other Settings > Identification | Signing Team ID | Your developer account’s Team ID |
| Other Settings > Configuration | Scripting Backend | IL2CPP, the only one iOS supports |
| Other Settings > Configuration | Architecture | ARM64 |
| Other Settings > Configuration | Target SDK | Device SDK. A project exported with Simulator SDK can’t be installed on a device |
| Other Settings > Configuration | Target minimum iOS Version | The oldest iOS version you want to support. The default is fine too |
| Other Settings > Configuration | Camera Usage Description | Required if you use the camera |
| Other Settings > Configuration | Microphone Usage Description | Required if you use the microphone |
| Other Settings > Configuration | Location Usage Description | Required if you use location |
Usage descriptions are written into the exported project’s Info.plist. If the game uses the camera, microphone or location without a description, it crashes as soon as it makes the call, and App Review rejects it.
Put the .p12 certificate and .mobileprovision provisioning profile for signing in the keychain folder. During development, use an Apple Development certificate and a Development provisioning profile that includes this iPhone’s UDID. For how to get and place them, see Certificates and signing.
Export the Xcode project
Click “Build” in the Build Profiles window and choose an empty folder, such as D:\u\mygame. Use a short path for the export folder. The project Unity exports nests deeply, and a deep path easily runs into path-too-long errors on Windows.
While testing, you can check “Development Build” for more complete logs on errors and a connection to the Unity Profiler. Remember to uncheck it before your production build.
After the export, the folder contains Unity-iPhone.xcodeproj. If the project uses plugins with iOS dependencies, such as Firebase or Google Mobile Ads, the folder also has a Podfile. Run pod install once in the export folder, which creates Unity-iPhone.xcworkspace.
1cd D:\u\mygame
2pod install
For more on CocoaPods, see Develop iOS apps with CocoaPods on Windows.
Open in VS Code and run doctor
In VS Code, open the export folder D:\u\mygame with File > Open Folder…. The KXBuild view lists its project and targets. The app target is Unity-iPhone. The other one, UnityFramework, is a framework it depends on and is compiled along with it.
The first time you open it, run doctor. It checks what the build needs and fixes anything missing. Use either of these.
- VS Code extension. In the title bar of the KXBuild view, open the ··· menu and run Doctor (fix environment).
- Command line. Run the command below in the export folder.
1kxbuild doctor .\Unity-iPhone.xcodeproj
Test on your iPhone
Connect the iPhone with a cable, unlock it and tap Trust in the Trust This Computer prompt, then turn on Developer Mode in Settings > Privacy & Security > Developer Mode. The iPhone restarts once. For drivers and iPhone settings, see Set up your device.
Select the iPhone in the KXBuild view and press F5. KXBuild builds, signs, installs and launches the game, then attaches the debugger. The first compile of the C++ code generated by IL2CPP takes a while, and later builds are incremental. The first time you debug on a given iOS version, KXBuild also downloads its device symbols. It’s a few GB, but only once.
While the game runs, output from Debug.Log and the like appears in the KXBuild Console channel of the VS Code Output panel, and the build log in the KXBuild channel. Open the Output panel with Ctrl+Shift+U and switch channels from the dropdown at the top right.
Each kind of code uses its own debugger.
- Native code (Objective-C plugin code in the export folder). Set breakpoints in VS Code. See Run and debug.
- C# scripts. Use Unity’s own debugger. Write them in Unity as usual and export again after changes.
To reinstall without recompiling, use KXBuild: Run in the title bar of the KXBuild view. It installs the output of the last build and launches it.
Export again after C# changes
After changing C# scripts, scenes or assets, Build again in Unity to the same folder. When the folder exists, Unity asks whether to Append or Replace.
| Choice | When to use it |
|---|---|
| Append | Day-to-day iteration. Updates what Unity generates and keeps your changes to the exported project |
| Replace | After upgrading Unity, or when the exported project has build errors you can’t explain. The whole folder is regenerated and manual changes are lost |
After Replace, run pod install again if there’s a Podfile, then run doctor once more. After exporting, go back to VS Code and press F5. KXBuild recompiles only what changed.
For native changes you want to keep, such as extra Info.plist keys or build settings, write them in at export time with a Unity PostProcessBuild script so Replace doesn’t lose them. For one-off changes, edit the exported project directly with the Property List Editor and Project Settings Editor.
Check performance
Sample frame rate, CPU and memory on the device with kxdevice to get numbers close to what players see. Install a Release build before measuring.
1kxbuild build .\Unity-iPhone.xcodeproj -c Release -t Unity-iPhone --install
2kxdevice instruments sysmon -i 1
sysmon prints CPU usage continuously. For dropped frames, memory growth and hot functions, use fluidity, allocations and stackshot. See Performance profiling for the full table and usage. Unity’s built-in Profiler is better for script and rendering timings, and the two work well together.
Build a Release .ipa
Before submitting, make sure Build in Player Settings is higher than in your last upload, and that the keychain folder has an Apple Distribution certificate and an App Store provisioning profile. If you changed Player Settings, export again.
Use either of these.
- VS Code extension. Switch the configuration to Release in the Build configuration node of the KXBuild view, then run
KXBuild: Buildfrom the Command Palette. - Command line. The target is always Unity-iPhone. Run the command that fits your export folder.
For an export folder without a Podfile, run this.
1kxbuild build .\Unity-iPhone.xcodeproj -c Release -t Unity-iPhone
For an export folder with a Podfile where you’ve already run pod install, run this.
1kxbuild build .\Unity-iPhone.xcworkspace -c Release -t Unity-iPhone
If the project’s Release configuration doesn’t specify a distribution certificate, add -D CODE_SIGN_IDENTITY="Apple Distribution" on the command line to override it for this build.
When the build finishes, the .ipa is in the build folder of the export folder. Upload it to App Store Connect with Appuploader on Windows. When processing finishes, it appears on the TestFlight page. Send it to testers first, then submit it for review. See Release and App Store submission.
FAQ
scheme or target not found. The app target in a Unity export is Unity-iPhone. On the command line, pass -t Unity-iPhone.
File name too long or file not found. Move the export folder to a short path such as D:\u\mygame and Build again.
The build can’t find Firebase or other dependencies. Run pod install in the export folder and build Unity-iPhone.xcworkspace.
The game quits right after launch. First check that the usage descriptions are filled in, then look at device logs and crash reports. See Run and debug and Troubleshooting.