iOS 16 Features Every Developer Should Implement

iOS 16 has been in the hands of users for several months now, and adoption rates are climbing steadily. Apple reported that over 70% of all iPhones are running iOS 16 as of late 2022. For developers, this adoption rate means the new APIs and features are no longer “nice to have” — they are expected by your users.

After shipping iOS 16 updates across multiple client apps, here are the features that deliver the most impact for user engagement and app quality. These are not experimental novelties. They are practical enhancements that users notice and appreciate.

Lock Screen Widgets with WidgetKit

The redesigned Lock Screen is the most visible change in iOS 16, and Lock Screen widgets give your app prime real estate on the most-viewed screen of any iPhone. Users glance at their Lock Screen dozens of times daily, and your widget can be right there alongside the time and date.

Lock Screen widgets come in three sizes: circular, rectangular, and inline (above the clock). They use the same WidgetKit framework introduced for Home Screen widgets, but with a few key differences.

Implementation Approach

Lock Screen widgets use the accessoryCircular, accessoryRectangular, and accessoryInline widget families. They render in a limited colour space — essentially monochrome with some opacity variations — so your designs need to work without colour:

struct StepCountWidget: Widget {
    let kind: String = "StepCountWidget"

    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: StepCountProvider()) { entry in
            StepCountWidgetView(entry: entry)
        }
        .configurationDisplayName("Step Count")
        .description("Track your daily steps")
        .supportedFamilies([
            .accessoryCircular,
            .accessoryRectangular,
            .accessoryInline
        ])
    }
}

struct StepCountWidgetView: View {
    var entry: StepCountEntry

    @Environment(\.widgetFamily) var family

    var body: some View {
        switch family {
        case .accessoryCircular:
            Gauge(value: Double(entry.steps), in: 0...Double(entry.goal)) {
                Image(systemName: "figure.walk")
            } currentValueLabel: {
                Text("\(entry.steps)")
            }
            .gaugeStyle(.accessoryCircularCapacity)

        case .accessoryRectangular:
            VStack(alignment: .leading) {
                Text("Steps Today")
                    .font(.headline)
                Text("\(entry.steps) / \(entry.goal)")
                    .font(.body)
                ProgressView(value: Double(entry.steps), total: Double(entry.goal))
            }

        case .accessoryInline:
            Text("\(entry.steps) steps today")

        default:
            Text("Unsupported")
        }
    }
}

Design Tips

The Gauge view is particularly effective for circular widgets. Use it for any metric that has a clear progress toward a goal: fitness targets, budget tracking, project completion. The rectangular format works well for brief text summaries with a supporting visual element.

Keep updates reasonable. Lock Screen widgets refresh on a timeline you define, but battery impact matters. For most apps, updates every 15-30 minutes strike the right balance between freshness and efficiency.

Live Activities and the Dy

namic Island

Live Activities are the standout feature for apps with real-time information. They display ongoing events on the Lock Screen and, on iPhone 14 Pro models, in the Dynamic Island. Think delivery tracking, sports scores, ride-sharing status, or workout timers.

Setting Up Live Activities

Live Activities require the ActivityKit framework and a specific configuration in your app’s Info.plist:

// Define your activity attributes
struct DeliveryActivity: ActivityAttributes {
    public struct ContentState: Codable, Hashable {
        var status: String
        var estimatedArrival: Date
        var driverName: String
    }

    var orderNumber: String
    var restaurantName: String
}

Starting a Live Activity from your app:

func startDeliveryTracking(order: Order) throws {
    let attributes = DeliveryActivity(
        orderNumber: order.id,
        restaurantName: order.restaurant
    )

    let initialState = DeliveryActivity.ContentState(
        status: "Preparing your order",
        estimatedArrival: order.estimatedArrival,
        driverName: ""
    )

    let content = ActivityContent(state: initialState, staleDate: nil)

    let activity = try Activity.request(
        attributes: attributes,
        content: content,
        pushType: .token
    )
}

Updating via push notifications is the recommended approach for server-driven updates. You receive an Activity push token when the activity starts, which you send to your backend. Updates arrive through a dedicated APNs channel with minimal latency.

Dynamic Island Presentation

For iPhone 14 Pro users, Live Activities automatically appear in the Dynamic Island. You define three presentations: compact leading, compact trailing, and expanded:

struct DeliveryActivityWidget: Widget {
    var body: some WidgetConfiguration {
        ActivityConfiguration(for: DeliveryActivity.self) { context in
            // Lock Screen presentation
            DeliveryLockScreenView(context: context)
        } dynamicIsland: { context in
            DynamicIsland {
                // Expanded presentation
                DynamicIslandExpandedRegion(.leading) {
                    Image(systemName: "bicycle")
                }
                DynamicIslandExpandedRegion(.trailing) {
                    Text(context.state.estimatedArrival, style: .timer)
                }
                DynamicIslandExpandedRegion(.bottom) {
                    Text(context.state.status)
                        .font(.caption)
                }
            } compactLeading: {
                Image(systemName: "bicycle")
            } compactTrailing: {
                Text(context.state.estimatedArrival, style: .timer)
            } minimal: {
                Image(systemName: "bicycle")
            }
        }
    }
}

Live Activities are a significant differentiator for apps with real-time data. If your app tracks anything over time — deliveries, workouts, travel, cooking timers — implement Live Activities now.

SwiftUI 4 Improvements

SwiftUI received substantial improvements in iOS 16 that address many pain points from earlier versions.

The new NavigationStack and NavigationSplitView replace the aging NavigationView with a programmatic, type-safe navigation system:

struct ProductListView: View {
    @State private var navigationPath = NavigationPath()

    var body: some View {
        NavigationStack(path: $navigationPath) {
            List(products) { product in
                NavigationLink(value: product) {
                    ProductRow(product: product)
                }
            }
            .navigationDestination(for: Product.self) { product in
                ProductDetailView(product: product)
            }
            .navigationDestination(for: Category.self) { category in
                CategoryView(category: category)
            }
        }
    }

    func navigateToProduct(_ product: Product) {
        navigationPath.append(product)
    }

    func popToRoot() {
        navigationPath.removeLast(navigationPath.count)
    }
}

This is a game-changer for complex navigation flows. Deep linking, programmatic navigation, and state restoration all become straightforward.

Swift Charts

Charts are one of the most common UI requirements in mobile apps, and Apple now provides a first-party solution:

import Charts

struct SalesChartView: View {
    let data: [SalesData]

    var body: some View {
        Chart(data) { item in
            BarMark(
                x: .value("Month", item.month),
                y: .value("Revenue", item.revenue)
            )
            .foregroundStyle(by: .value("Category", item.category))
        }
        .chartYAxis {
            AxisMarks(format: .currency(code: "AUD"))
        }
    }
}

Swift Charts supports bar, line, point, area, rule, and rectangle marks with composable modifiers. For most app charting needs, it eliminates the dependency on third-party libraries.

Transferable Protocol

The new Transferable protocol simplifies drag-and-drop, copy-paste, and sharing operations:

struct Photo: Transferable {
    let image: Image
    let caption: String

    static var transferRepresentation: some TransferRepresentation {
        ProxyRepresentation(exporting: \.image)
    }
}

This dramatically reduces the boilerplate needed for data transfer between apps and within your app’s interface.

Passkeys

Apple is pushing passkeys as the future of authentication, and iOS 16 provides the framework to implement them. Passkeys use public-key cryptography to replace passwords entirely. They are phishing-resistant, cannot be reused across sites, and sync securely via iCloud Keychain.

For apps that handle authentication, implementing passkey support positions you ahead of the curve:

let provider = ASAuthorizationPlatformPublicKeyCredentialProvider(
    relyingPartyIdentifier: "example.com"
)

let registrationRequest = provider.createCredentialRegistrationRequest(
    challenge: serverChallenge,
    name: "[email protected]",
    userID: userId
)

let controller = ASAuthorizationController(
    authorizationRequests: [registrationRequest]
)
controller.delegate = self
controller.performRequests()

The backend requirements are standard WebAuthn, so if your server already supports FIDO2, passkey integration is straightforward.

Focus Filters

Focus Filters allow your app to present different content based on the user’s active Focus mode. A productivity app could show work tasks during the Work focus and personal tasks during Personal:

struct WorkFocusFilter: SetFocusFilterIntent {
    static var title: LocalizedStringResource = "Work Filter"
    static var description: IntentDescription = "Show only work-related content"

    @Parameter(title: "Account")
    var account: AccountEntity?

    func perform() async throws -> some IntentResult {
        // Configure app to show work content
        return .result()
    }
}

This is a subtle feature, but it demonstrates awareness of how users actually interact with their devices throughout the day.

Priority Implementation Order

If you are planning your iOS 16 adoption roadmap, here is the order I recommend based on user impact and implementation effort:

  1. Lock Screen widgets — High visibility, moderate effort, works on all iOS 16 devices
  2. NavigationStack migration — Improves code quality and enables deep linking
  3. Swift Charts — Eliminates third-party dependencies for charting
  4. Live Activities — High impact for apps with real-time data, higher effort
  5. Passkeys — Forward-looking investment in authentication
  6. Focus Filters — Nice enhancement for power users

Each of these features signals to your users that your app is actively maintained and takes advantage of the latest platform capabilities. In a competitive App Store, that signal matters.


Building or updating an iOS app? Our team at eawesome helps Australian businesses leverage the latest Apple technologies to create standout mobile experiences.