Skip to content
All essays
iOSMarch 27, 202513 min

Swift ARKit Guide: Augmented Reality Development

Create immersive AR experiences with ARKit. 3D objects, plane detection, and spatial tracking.

Ü
Ümit Uz
Mobile & Full Stack Developer

ARKit enables augmented reality experiences in iOS apps. Learn to create immersive AR applications.

ARKit Setup

Basic AR Scene

swift
import ARKit
import RealityKit
import SwiftUI

struct ARViewContainer: UIViewRepresentable {
    func makeUIView(context: Context) -> ARView {
        let arView = ARView(frame: .zero)

        // Create AR session
        let config = ARWorldTrackingConfiguration()
        config.planeDetection = [.horizontal, .vertical]

        arView.session.run(config)

        return arView
    }

    func updateUIView(_ uiView: ARView, context: Context) {}
}

struct BasicARView: View {
    var body: some View {
        ARViewContainer()
            .edgesIgnoringSafeArea(.all)
    }
}

Plane Detection

Detect Planes

swift
class PlaneDetectionManager: NSObject, ARSessionDelegate {
    private var arView: ARView?

    func setupPlaneDetection(in arView: ARView) {
        self.arView = arView

        let config = ARWorldTrackingConfiguration()
        config.planeDetection = [.horizontal, .vertical]

        arView.session.delegate = self
        arView.session.run(config)
    }

    func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) {
        for anchor in anchors {
            if let planeAnchor = anchor as? ARPlaneAnchor {
                handlePlaneAnchor(planeAnchor)
            }
        }
    }

    private func handlePlaneAnchor(_ anchor: ARPlaneAnchor) {
        // Create visualization for detected plane
        let plane = ARPlaneAnchor(anchor)
        print("Plane detected: \(anchor.alignment)")
    }
}

Visualize Planes

swift
extension ARView {
    func addPlaneVisualization(for anchor: ARPlaneAnchor) {
        // Create plane mesh
        let mesh = MeshResource(
            generatePlane(width: anchor.extent.x, depth: anchor.extent.z)
        )

        let material = SimpleMaterial(
            color: .blue.withAlphaComponent(0.5),
            isMetallic: false
        )

        let modelEntity = ModelEntity(mesh: mesh, materials: [material])

        let anchorEntity = AnchorEntity(anchor: anchor)
        anchorEntity.addChild(modelEntity)

        self.scene.addAnchor(anchorEntity)
    }
}

3D Objects

Place 3D Objects

swift
class ObjectPlacementManager {
    func placeObject(in arView: ARView, at location: CGPoint) {
        // Get raycast result
        let results = arView.raycast(from: location, allowing: .estimatedPlane, alignment: .horizontal)

        guard let result = results.first else {
            print("No plane detected")
            return
        }

        // Create 3D object
        let entity = create3DObject()

        // Place object
        let anchorEntity = AnchorEntity(world: result.worldTransform)
        anchorEntity.addChild(entity)

        arView.scene.addAnchor(anchorEntity)
    }

    private func create3DObject() -> Entity {
        // Create sphere
        let sphere = ModelEntity(
            mesh: MeshResource.generateSphere(radius: 0.1),
            materials: [SimpleMaterial(color: .red, isMetallic: false)]
        )

        // Add gesture interaction
        sphere.generateCollisionShapes(recursive: true)

        return sphere
    }
}

Object Interaction

Gesture Handling

swift
struct InteractiveARView: View {
    var body: some View {
        ARViewContainer()
            .gesture(
                TapGesture()
                    .onEnded { value in
                        handleTap(at: value.location)
                    }
            )
    }

    private func handleTap(at location: CGPoint) {
        // Handle tap to place object
        print("Tapped at: \(location)")
    }
}

Drag Objects

swift
extension Entity {
    func addDragGesture(to arView: ARView) {
        arView.installGestures([.translation], for: self)
    }
}

class ObjectInteractionManager {
    func setupInteractions(for entity: Entity, in arView: ARView) {
        // Enable gestures
        entity.generateCollisionShapes(recursive: true)
        arView.installGestures([.translation, .rotation], for: entity)
    }
}

Image Tracking

Track Images

swift
class ImageTrackingManager {
    func setupImageTracking(in arView: ARView, referenceImages: Set<ARReferenceImage>) {
        let config = ARImageTrackingConfiguration()
        config.trackingImages = referenceImages
        config.maximumNumberOfTrackedImages = 1

        arView.session.run(config)
    }

    func loadReferenceImages() -> Set<ARReferenceImage> {
        var images = Set<ARReferenceImage>()

        // Load images from assets
        if let image = UIImage(named: "referenceImage"),
           let cgImage = image.cgImage {

            let referenceImage = ARReferenceImage(
                cgImage: cgImage,
                orientation: .up,
                physicalWidth: 0.1
            )

            referenceImage.name = "Reference"
            images.insert(referenceImage)
        }

        return images
    }
}

Face Tracking

Track Faces

swift
import ARKit

class FaceTrackingManager {
    func setupFaceTracking(in arView: ARView) {
        guard ARFaceTrackingConfiguration.isSupported else {
            print("Face tracking not supported")
            return
        }

        let config = ARFaceTrackingConfiguration()
        config.isLightingEstimationEnabled = true

        arView.session.run(config)
    }

    func createFaceEntity() -> Entity {
        // Create face mask
        let faceMask = ModelEntity(
            mesh: .generateSphere(radius: 0.1),
            materials: [SimpleMaterial(color: .white.withAlphaComponent(0.5), isMetallic: false)]
        )

        return faceMask
    }
}

Light Estimation

Enable Realistic Lighting

swift
class LightEstimationManager {
    func setupLighting(in arView: ARView) {
        let config = ARWorldTrackingConfiguration()
        config.environmentTexturing = .automatic
        config.frameSemantics = .sceneDepth

        arView.environment.lighting.intensity = 1000
        arView.environment.lighting.usesImageBasedLighting = true

        arView.session.run(config)
    }
}

ARKit with SwiftUI

Combine ARKit and SwiftUI

swift
struct SwiftUIARView: View {
    @State private var showAR = false

    var body: some View {
        VStack {
            if showAR {
                ARViewContainer()
                    .edgesIgnoringSafeArea(.all)
            } else {
                Button("Start AR Experience") {
                    showAR = true
                }
                .padding()
                .background(Color.blue)
                .foregroundColor(.white)
                .cornerRadius(10)
            }
        }
    }
}

Best Practices

  1. 1Performance: Optimize for 60 FPS
  2. 2Lighting: Use light estimation
  3. 3Anchors: Use appropriate anchor types
  4. 4Interaction: Provide clear interaction
  5. 5Testing: Test on real devices
  6. 6Compatibility: Check device compatibility
  7. 7UX: Provide user guidance
  8. 8Feedback: Give visual feedback

ARKit creates immersive AR experiences in iOS apps!

Related essays

Next essay
Swift Haptic Feedback: Engaging User Experience