RORK LABJP
FUNDING — Rork raises a $15M seed led by Left Lane CapitalRORK MAX — Rork Max generates native Swift apps instead of React NativePLATFORM — It targets iPhone, iPad, Watch, and Vision Pro, reaching Live Activities and Core MLGROWTH — Traffic keeps climbing at 743K monthly visits and 85% growthTEST — The Companion app lets you test on a real device without a paid Apple Developer accountSTACK — Built on React Native and Expo for true native experiences, not web wrappersFUNDING — Rork raises a $15M seed led by Left Lane CapitalRORK MAX — Rork Max generates native Swift apps instead of React NativePLATFORM — It targets iPhone, iPad, Watch, and Vision Pro, reaching Live Activities and Core MLGROWTH — Traffic keeps climbing at 743K monthly visits and 85% growthTEST — The Companion app lets you test on a real device without a paid Apple Developer accountSTACK — Built on React Native and Expo for true native experiences, not web wrappers
Articles/App Dev
App Dev/2026-07-01Advanced

Building an AlarmKit Timer in Rork Max's Native Swift — Alerts That Cut Through Silent Mode and Focus

Implementation notes on solving the 'local notifications stay silent in Silent Mode and Focus' problem with iOS 26's AlarmKit. Covers authorization, scheduling a countdown, the Live Activity for the Lock Screen and Dynamic Island, and listing active timers in Swift — plus the boundary design for Rork Max native code and bridging from Expo, with the pitfalls I actually hit.

AlarmKitRork Max196Live ActivityiOS90Timer

Premium Article

While building a small interval timer as an indie developer, a tester told me, "It doesn't ring when my phone is on silent." On my own device everything had worked, so at first I couldn't reproduce it. The cause was simple: I had built the timer with local notifications through UserNotifications. On an iPhone with the silent switch on, notification sounds don't play. For a notification whose entire point is to ring — a timer, an alarm — that's fatal.

For a long time, the only sanctioned way past this wall was the Critical Alerts entitlement. But that's a special permission meant for medical, safety, and public-safety use, it requires an application to Apple, and a small indie timer app is very unlikely to be approved. iOS 26's AlarmKit changed that. Limited to timers and alarms, it lets you cut through Silent Mode and Focus without any application. And because Rork Max now generates native Swift, AlarmKit has become something you can realistically wire into an indie app. Here is what I learned doing exactly that.

Why local notifications stay silent

Getting this precise up front makes the later design decisions much easier. Local and push notifications sent through UserNotifications obey the device's silent switch and Focus settings. If the user is on silent, no sound plays; if a Focus is suppressing alerts, even the banner is held back. That's correct behavior for not interrupting people, and it's welcome for news or marketing.

The problem is the class of notifications where ringing is the feature: timers, alarms, reminders. A three-minute cooking timer, a workout interval, a 30-minute nap alarm. These are exactly the moments where the user wants a sound because the phone is on silent — and local notifications fall silent instead. The table below captures the difference between the three options.

ApproachCuts through Silent / Focus?Application needed?Realistic for indie?
UserNotifications (local)No (stays silent)NoneHigh, but the "won't ring" problem remains
Critical Alerts entitlementYesPer-app application to AppleLow (narrow use, rarely approved)
AlarmKit (iOS 26+)YesNone (just user authorization)High (limited to timer / alarm use)

AlarmKit isn't a blank check. It's not a way to make arbitrary notifications loud — it's scoped strictly to "a timer or alarm the user set themselves." Put the other way around: for an app that fits that context exactly, a sanctioned route that never existed before is now open.

Requesting authorization

Because an AlarmKit alert plays sound and appears on screen even during a Focus, explicit user permission is a precondition. There are two steps. First, add NSAlarmKitUsageDescription to Info.plist with a one-line explanation of why your app schedules alarms. That text appears alongside Apple's standard explanation in the first authorization prompt.

Second, check the current status and, if it's still undetermined, show the system prompt with requestAuthorization(). AlarmManager.shared is the entry point.

import SwiftUI
import AlarmKit
 
struct TimerStartButton: View {
    private let manager = AlarmManager.shared
 
    var body: some View {
        Button("Start timer", systemImage: "timer") {
            Task {
                if await ensureAuthorized() {
                    await scheduleTimer()
                } else {
                    // Denied: disable the feature, point users to Settings
                }
            }
        }
    }
 
    private func ensureAuthorized() async -> Bool {
        switch manager.authorizationState {
        case .notDetermined:
            do {
                let state = try await manager.requestAuthorization()
                return state == .authorized
            } catch {
                print("Authorization error: \(error)")
                return false
            }
        case .authorized:
            return true
        case .denied:
            return false
        @unknown default:
            return false
        }
    }
}

The key detail is that the prompt fires only in the .notDetermined branch. Re-prompting a user who is already .denied shows nothing, and .authorized lets you proceed immediately. What you do on denial depends on the app's character: if the timer is the core feature, guide them to Settings; if it's a secondary feature, quietly fall back to local notifications.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
Why UserNotifications stays silent in Silent Mode and Focus, how AlarmKit cuts through without the Critical Alerts entitlement, and when to switch
A complete, working Swift flow: authorization, scheduling a countdown, and a minimal Live Activity for the Lock Screen and Dynamic Island
How to use AlarmKit in the native Swift Rork Max generates, and the boundary design for bridging it from an Expo / React Native native module
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

App Dev2026-06-30
Screening Images On Device Before They Appear — Notes on SensitiveContentAnalysis
Implementation notes on blocking inappropriate images before they render, right on the device, for apps that handle AI-generated or user-submitted photos. Covers calling Apple's SensitiveContentAnalysis framework from Swift and wiring it into Rork Max native code or an Expo native module, with the pitfalls I actually hit.
App Dev2026-06-28
Building a Live Barcode and Text Scanner in Rork Max with VisionKit's DataScanner
Add a live barcode and text scanner to your Rork Max native Swift app using VisionKit's DataScanner. Covers the SwiftUI bridge, availability handling, throttling repeated detections, and on-device verification with working code.
App Dev2026-06-16
Staging Wallpaper Packs Before the First Launch: Where Rork Max and Background Assets Fit
Content-heavy apps tend to greet new users with an empty grid. Background Assets downloads content out-of-band, ahead of the first launch. Here is how I implement it in Rork Max's native Swift, a domain Rork (Expo) cannot reach easily, plus how I decide when it is worth it.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →