RORK LABJP
ENGINE — Rork Max is powered by Claude Code and Claude Opus 4.6, generating native Swift apps directlyCORE ML — Rork Max reaches on-device Core ML inference alongside HealthKit, HomeKit, NFC, and App ClipsSEED — Rork raised a $15M seed led by Left Lane Capital in April 2026, joined by Peak XV and a16z SpeedrunM&A — Rork acquired the app builder Paperline and says it will stay acquisitive to bring in engineering talentMARKET — Gartner expects 75% of new applications to be built with low-code or no-code tools by the end of 2026GROWTH — The no-code AI platform market is projected to grow from $4.9B in 2024 to $24.8B by 2029ENGINE — Rork Max is powered by Claude Code and Claude Opus 4.6, generating native Swift apps directlyCORE ML — Rork Max reaches on-device Core ML inference alongside HealthKit, HomeKit, NFC, and App ClipsSEED — Rork raised a $15M seed led by Left Lane Capital in April 2026, joined by Peak XV and a16z SpeedrunM&A — Rork acquired the app builder Paperline and says it will stay acquisitive to bring in engineering talentMARKET — Gartner expects 75% of new applications to be built with low-code or no-code tools by the end of 2026GROWTH — The no-code AI platform market is projected to grow from $4.9B in 2024 to $24.8B by 2029
Articles/App Dev
App Dev/2026-07-01Advanced

Making the Block Screen Feel Like Your Own App — ShieldConfiguration and Button Handling in Rork Max

Replace the plain gray shield that screen-time apps show with something that speaks in your app's voice. This walks through swapping the UI with a ShieldConfiguration extension and controlling the buttons with ShieldAction, wired into a Rork Max native setup.

Rork Max219Family Controls2ManagedSettings2Screen TimeiOS107

Premium Article

As an indie developer building a focus-time app in Rork Max, I kept hitting the same wall: the block would fire on schedule, but what appeared was Apple's default gray screen — nothing that told the user it was still my app. After a carefully made onboarding flow, users were suddenly dropped onto a cold system screen.

That "shield" screen can be replaced. But you can't touch it from your main app code. The screen shown during a block is drawn by a separate process, so reshaping it means adding two dedicated App Extensions: a ShieldConfiguration extension that swaps the appearance, and a ShieldAction extension that decides what happens when its buttons are pressed.

I'll assume you already have the Family Controls entitlement and are applying shields through ManagedSettingsStore. This article focuses on the step after that: rebuilding the screen itself.

Why you can't draw the shield from the main app

When you hand tokens to store.shield.applications, the system slides a shield screen in the moment the target app is opened. That screen isn't drawn by your app — it's a separate process running inside the ManagedSettingsUI framework. Neither React Native nor your main Swift target can touch it directly.

The one entry point is ShieldConfigurationDataSource. Right before the system shows the shield, it asks this class, and builds the screen from the ShieldConfiguration you return. So what you control is "which parts, in which colors" — not an arbitrary SwiftUI view. Miss this and you'll get stuck trying to render an elaborate layout that the API simply won't accept.

What you wantPossible?How
Change background color / blurYesbackgroundColor / backgroundBlurStyle
Use your own iconYes (only images bundled in the extension)icon as a UIImage
Title / subtitle text and colorYestitle / subtitle (Label)
Two buttonsYes (max two — label and color only)primaryButtonLabel / secondaryButtonLabel
Render an arbitrary SwiftUI viewNo
Fetch a remote image on the spotEffectively noBundle it, or pass via App Group

Step 1: Add the ShieldConfiguration extension

In Xcode, add a new "Shield Configuration" extension target. When you build through Expo like Rork Max does, re-adding the target by hand on every eas build isn't realistic, so inject the extension target, its Info.plist, and entitlements through a config plugin. I keep this in the same config plugin as my main native module so the extension never gets forgotten.

In the extension's Info.plist, set NSExtensionPointIdentifier to com.apple.ManagedSettingsUI.shield-configuration-service and NSExtensionPrincipalClass to your class name. Get this wrong and the build still succeeds, but the system never calls you — you stay on the default screen, with no error to explain why.

import ManagedSettings
import ManagedSettingsUI
import UIKit
 
class FocusShieldConfiguration: ShieldConfigurationDataSource {
  override func configuration(shielding application: Application) -> ShieldConfiguration {
    return ShieldConfiguration(
      backgroundBlurStyle: .systemThinMaterialDark,
      backgroundColor: UIColor(red: 0.08, green: 0.10, blue: 0.16, alpha: 1),
      icon: UIImage(named: "ShieldLeaf"),
      title: ShieldConfiguration.Label(
        text: "This is your focus time",
        color: .white
      ),
      subtitle: ShieldConfiguration.Label(
        text: "You chose to close this app during this window. Give it a few more minutes.",
        color: UIColor(white: 0.75, alpha: 1)
      ),
      primaryButtonLabel: ShieldConfiguration.Label(
        text: "Back to focus",
        color: .white
      ),
      primaryButtonBackgroundColor: UIColor(red: 0.20, green: 0.55, blue: 0.90, alpha: 1),
      secondaryButtonLabel: ShieldConfiguration.Label(
        text: "Open for 5 minutes",
        color: UIColor(white: 0.65, alpha: 1)
      )
    )
  }
 
  // Return this too when you block by category
  override func configuration(shielding application: Application,
                              in category: ActivityCategory) -> ShieldConfiguration {
    return configuration(shielding: application)
  }
}

Set secondaryButtonLabel to nil and you get a single button. Specific wording pays off. Rather than announcing "blocked," a line that reminds users "this was your own promise" changes how the screen lands. Just swapping "Access is blocked" for the line above visibly warmed up my review sentiment.

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
A full ShieldConfiguration extension that replaces the default gray shield — background, icon, title, and up to two buttons — in your app's tone
The ShieldAction code that decides what the block-screen buttons do: close, grant a timed pass, or ignore, with a clean state-sharing design
Practical notes on the out-of-process, low-memory constraints of these extensions: bundling images, passing state via App Group, and what review looks at
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-07-03
Making Your Rork Max App Resilient to Dropped and Restored Connections: Offline Detection and Retry with NWPathMonitor
Build networking that survives a lost signal in your Rork Max native Swift app with NWPathMonitor. Detect offline states, respect Low Data Mode and cellular, and auto-resend queued work on reconnect — all with working Swift code.
App Dev2026-07-03
Keeping Downloads Alive After Your Rork Max App Is Killed: Background URLSession Design and Relaunch Handling
How to design downloads in a Rork Max native Swift app so transfers continue in the OS daemon even after the app is suspended or terminated. Covers relaunch wiring, resumeData recovery, and measured isDiscretionary behavior with working code.
App Dev2026-07-01
Building SharePlay in Rork Max's Native Swift — Keeping Two Screens in the Same State
Implementation notes on building SharePlay with GroupActivities in Rork Max's native Swift — moving two screens through the same state over FaceTime. Covers declaring the GroupActivity, joining a GroupSession, syncing state with GroupSessionMessenger, handling latency and conflicts, catching up late joiners, and the boundary for bridging from React Native, with the pitfalls I actually hit.
📚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 →