Building for iOS
Set up Xcode, configure signing, and build your Capacitor app for iOS devices and simulators.
What you'll accomplish
Run your Capacitor app on an iOS Simulator and understand device deployment.
Prerequisites
- A Mac (required for iOS development)
- Xcode 15+ installed
- Completed Next.js + Capacitor setup
Requirements
Warning
Mac Required: iOS development requires macOS. This is an Apple restriction, not a Capacitor limitation. If you don't have a Mac, skip to the Android lesson or use a cloud Mac service.
Install Xcode
- Open the App Store on your Mac
- Search for Xcode
- Click Get (it's free, but ~12GB download)
- Wait for installation to complete
After installation:
bash# Accept license agreement sudo xcodebuild -license accept # Install command line tools xcode-select --install
Verify Installation
bashxcodebuild -version # Should show: Xcode 15.x (or higher)
Opening Your Project in Xcode
From your Capacitor project:
bashnpx cap open ios
This opens the Xcode workspace. Always open the .xcworkspace file, not the .xcodeproj.
Project Structure
In Xcode, you'll see:
App/
├── App/
│ ├── AppDelegate.swift # App lifecycle
│ ├── public/ # Your web files (synced)
│ │ ├── index.html
│ │ └── ...
│ ├── Info.plist # App configuration
│ └── Assets.xcassets # App icons, images
├── Pods/ # Dependencies
└── App.xcworkspace # Open this!
Running on Simulator
Step 1: Select a Simulator
In Xcode's toolbar, click the device dropdown (next to the Play button).
Choose a simulator:
- iPhone 15 (or similar) for general testing
- iPhone SE for smaller screen testing
- iPad if you support tablets
Step 2: Build and Run
Click the Play button (▶) or press Cmd + R.
Xcode will:
- Build your app
- Launch the simulator
- Install and run your app
The first build takes several minutes because Xcode is compiling all the native code and dependencies. Subsequent builds are much faster.
Step 3: Debug
While running:
- Console: View → Debug Area → Activate Console
- Safari Dev Tools: Safari → Develop → Simulator → Your App
Running on a Physical Device
Step 1: Apple Developer Account
For device testing, you need an Apple account:
Free Apple ID (limited):
- Test on your own devices
- No App Store distribution
- Apps expire after 7 days
Apple Developer Program ($99/year):
- Unlimited device testing
- App Store distribution
- TestFlight beta testing
Step 2: Configure Signing
- In Xcode, select the App project (top of file navigator)
- Select the App target
- Go to Signing & Capabilities
- Check Automatically manage signing
- Select your Team (your Apple ID)
Note
If you see "Failed to create provisioning profile," you may need to:
- Change the Bundle Identifier to something unique
- Sign in with an Apple ID that's part of the Developer Program
Step 3: Connect Device
- Connect your iPhone/iPad with a USB cable
- On the device, tap Trust when prompted
- The device appears in Xcode's device dropdown
Step 4: Build and Run
Select your device and click Play (▶).
First time on a new device:
- Xcode installs a provisioning profile
- Go to Settings → General → VPN & Device Management
- Tap your developer certificate
- Tap Trust
Now the app should launch!
Configuring Your App
App Icons
Replace the placeholder icons:
- In Xcode, open Assets.xcassets → AppIcon
- Drag your icon files to each size slot
- Or use a tool like AppIcon Generator to generate all sizes
Icon requirements:
- 1024x1024 for App Store
- PNG format
- No transparency
Display Name
Edit capacitor.config.ts:
typescriptconst config: CapacitorConfig = { appName: 'My Cool App', // This is the display name // ... };
Then sync: npx cap sync ios
Splash Screen
Install the splash screen plugin:
bashnpm install @capacitor/splash-screen npx cap sync
Configure in capacitor.config.ts:
typescriptconst config: CapacitorConfig = { plugins: { SplashScreen: { launchShowDuration: 2000, backgroundColor: '#ffffff', showSpinner: false, }, }, };
For custom images, edit in Xcode's Assets.xcassets.
Status Bar
Control status bar appearance:
bashnpm install @capacitor/status-bar npx cap sync
typescriptimport { StatusBar, Style } from '@capacitor/status-bar'; // Set style StatusBar.setStyle({ style: Style.Dark }); // Hide status bar StatusBar.hide();
Info.plist Configuration
The Info.plist file controls iOS permissions and behaviors.
Common Configurations
Open ios/App/App/Info.plist and add:
Camera usage description (required if using camera):
xml<key>NSCameraUsageDescription</key> <string>We need camera access to take photos</string>
Photo library access:
xml<key>NSPhotoLibraryUsageDescription</key> <string>We need photo access to select images</string>
Location access:
xml<key>NSLocationWhenInUseUsageDescription</key> <string>We need location to show nearby stores</string>
Warning
iOS requires usage descriptions for any permission. Without them, your app will crash when requesting access.
Live Reload Development
For faster development, use live reload:
-
Start your Next.js dev server:
bashnpm run dev -
Configure Capacitor for live reload:
typescript// capacitor.config.ts const config: CapacitorConfig = { server: { url: 'http://YOUR_LOCAL_IP:3000', // e.g., 192.168.1.100 cleartext: true, }, }; -
Find your local IP:
bashipconfig getifaddr en0 # Or: ifconfig | grep "inet " | grep -v 127.0.0.1 -
Run on device/simulator:
bashnpx cap run ios
Now changes to your web code appear instantly!
Note
Your Mac and device must be on the same network for live reload to work.
Debugging
Safari Developer Tools
- Open Safari on your Mac
- Go to Safari → Settings → Advanced
- Check Show Develop menu in menu bar
- With your app running, go to Develop → [Device/Simulator] → [Your App]
You get full web developer tools (console, elements, network, etc.)!
Xcode Console
View native logs in Xcode's debug area (View → Debug Area → Activate Console).
Common Debug Commands
typescript// Log to Safari console console.log('Debug message'); // Check if running in Capacitor import { Capacitor } from '@capacitor/core'; console.log('Platform:', Capacitor.getPlatform()); console.log('Is native:', Capacitor.isNativePlatform());
Common Issues
Frequently Asked Questions
The simulator may be stuck. Try:
bashxcrun simctl shutdown all
Then build again.
- Ensure you're signed in: Xcode → Settings → Accounts
- Try changing the Bundle Identifier to something unique
- Check that "Automatically manage signing" is enabled
Check the Xcode console for errors. Common causes:
- Missing Info.plist usage descriptions
- Invalid JavaScript (check Safari console)
- Missing assets or files
- Check Safari dev tools for JavaScript errors
- Ensure you ran
npm run build && npx cap sync - Verify your dev server URL is correct (for live reload)
Run:
bashnpx cap sync ios cd ios && pod install
Preparing for App Store
When ready to submit:
1. Remove Development Settings
typescript// capacitor.config.ts - REMOVE or comment out: // server: { // url: 'http://localhost:3000', // cleartext: true, // },
2. Build for Release
In Xcode:
- Set device to "Any iOS Device"
- Product → Archive
- Follow the distribution workflow
3. Create App Store Connect Entry
Go to App Store Connect and:
- Create your app
- Fill in metadata
- Upload screenshots
- Submit for review
We cover this in detail in the deployment lesson.
Verify Your Understanding
You've completed this lesson if you can:
Next: Set up Android development with Android Studio.