Capacitor
40 minutes
macos

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

  1. Open the App Store on your Mac
  2. Search for Xcode
  3. Click Get (it's free, but ~12GB download)
  4. Wait for installation to complete

After installation:

bash
# Accept license agreement
sudo xcodebuild -license accept

# Install command line tools
xcode-select --install

Verify Installation

bash
xcodebuild -version
# Should show: Xcode 15.x (or higher)

Opening Your Project in Xcode

From your Capacitor project:

bash
npx 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:

  1. Build your app
  2. Launch the simulator
  3. 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

  1. In Xcode, select the App project (top of file navigator)
  2. Select the App target
  3. Go to Signing & Capabilities
  4. Check Automatically manage signing
  5. Select your Team (your Apple ID)
Note

If you see "Failed to create provisioning profile," you may need to:

  1. Change the Bundle Identifier to something unique
  2. Sign in with an Apple ID that's part of the Developer Program

Step 3: Connect Device

  1. Connect your iPhone/iPad with a USB cable
  2. On the device, tap Trust when prompted
  3. 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:

  1. Xcode installs a provisioning profile
  2. Go to Settings → General → VPN & Device Management
  3. Tap your developer certificate
  4. Tap Trust

Now the app should launch!

Configuring Your App

App Icons

Replace the placeholder icons:

  1. In Xcode, open Assets.xcassets → AppIcon
  2. Drag your icon files to each size slot
  3. 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:

typescript
const config: CapacitorConfig = {
  appName: 'My Cool App',  // This is the display name
  // ...
};

Then sync: npx cap sync ios

Splash Screen

Install the splash screen plugin:

bash
npm install @capacitor/splash-screen
npx cap sync

Configure in capacitor.config.ts:

typescript
const 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:

bash
npm install @capacitor/status-bar
npx cap sync
typescript
import { 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:

  1. Start your Next.js dev server:

    bash
    npm run dev
    
  2. 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,
      },
    };
    
  3. Find your local IP:

    bash
    ipconfig getifaddr en0
    # Or: ifconfig | grep "inet " | grep -v 127.0.0.1
    
  4. Run on device/simulator:

    bash
    npx 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

  1. Open Safari on your Mac
  2. Go to Safari → Settings → Advanced
  3. Check Show Develop menu in menu bar
  4. 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:

bash
xcrun simctl shutdown all

Then build again.

  1. Ensure you're signed in: Xcode → Settings → Accounts
  2. Try changing the Bundle Identifier to something unique
  3. 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
  1. Check Safari dev tools for JavaScript errors
  2. Ensure you ran npm run build && npx cap sync
  3. Verify your dev server URL is correct (for live reload)

Run:

bash
npx 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:

  1. Set device to "Any iOS Device"
  2. Product → Archive
  3. Follow the distribution workflow

3. Create App Store Connect Entry

Go to App Store Connect and:

  1. Create your app
  2. Fill in metadata
  3. Upload screenshots
  4. Submit for review

We cover this in detail in the deployment lesson.

Verify Your Understanding

You've completed this lesson if you can:

0/5

Next: Set up Android development with Android Studio.