A Swift package for managing and working with age ranges in iOS applications, specifically designed to work with iOS 26.0's new DeclaredAgeRange feature.
This package includes a demo iOS app for testing and development. See AgeRangeServiceKitDemo/README.md for setup instructions.
Important
Apple Developer Account Required: To run the demo app and test the age range service, you must have an Apple Developer account. The age range service capability must be enabled in your app's capabilities section. Without an Apple Developer account, you will not be able to test the age range service capabilities at this time.
Quick Start with Demo App:
- Open Xcode and create a new iOS App project in the
DemoAppfolder - Add this package as a local dependency
- Enable the Age Range Service capability in your app's signing & capabilities
- Run the app to see AgeRangeServiceKit in action
DeclaredAgeRangeKit helps you implement age-based restrictions in your iOS app using Apple's native age verification system. The package provides:
- Design-agnostic views - Bring your own UI/design system
- Simple age checking - Easy-to-use manager with computed properties
- Environment-based - Uses Apple's
@Environment(\.requestAgeRange) - No persistence needed - Age data managed by the system
β
Age verification using Apple's native API
β
Customizable blocking views via @ViewBuilder
β
Teen (13-17) checkout restrictions
β
Underage (<13) app blocking
β
Thread-safe with proper @MainActor handling
β
No UserDefaults or custom storage needed
- iOS 26.0+
- Swift 5.9+
- Xcode 26.0+
- Apple Developer account (required for age range service capability)
Warning
The age range service capability is only available to apps with a valid Apple Developer account. You must enable this capability in your app's signing & capabilities to use this package's features.
Add DeclaredAgeRangeKit to your project:
dependencies: [
.package(url: "https://github.com/alokc83/AgeRangeServiceKit.git", from: "1.0.0")
]Or in Xcode:
- File β Add Package Dependencies...
- Enter the repository URL
- Select version and add to your target
import DeclaredAgeRangeKit
import DeclaredAgeRangestruct ContentView: View {
@StateObject private var ageManager = AgeRangeManager.shared
@Environment(\.requestAgeRange) private var requestAgeRange
var body: some View {
TabView {
// Your app content
}
.task {
await ageManager.checkAgeRange(using: requestAgeRange)
}
.overlay {
if ageManager.isUnder13 {
UnderageBlockerView {
MyCustomBlockerDesign()
}
}
}
}
}struct CheckoutView: View {
@StateObject private var ageManager = AgeRangeManager.shared
@Environment(\.requestAgeRange) private var requestAgeRange
@State private var showTeenWarning = false
var body: some View {
// Checkout UI...
.fullScreenCover(isPresented: $showTeenWarning) {
TeenCheckoutWarningView {
MyTeenWarningDesign()
}
}
.onAppear {
Task {
await ageManager.checkAgeRange(using: requestAgeRange)
if ageManager.isTeen {
showTeenWarning = true
}
}
}
}
}The package views accept custom content via @ViewBuilder, so you provide the design:
struct MyUnderageBlocker: View {
var body: some View {
ZStack {
Color(hex: "F5F5F5")
.ignoresSafeArea()
VStack(alignment: .leading, spacing: 16) {
Text("Age Requirement Not Met")
.font(.system(size: 28, weight: .bold))
Text("Per local laws, users under 13 may not use this app.")
.font(.system(size: 17))
.foregroundColor(.gray)
}
.padding(.horizontal, 40)
}
}
}
// Use it:
UnderageBlockerView {
MyUnderageBlocker()
}struct MyTeenWarning: View {
var body: some View {
ZStack {
Color.black.opacity(0.4)
.ignoresSafeArea()
VStack(spacing: 30) {
Image(systemName: "exclamationmark.triangle.fill")
.font(.system(size: 80))
.foregroundColor(.orange)
Text("Checkout Not Available")
.font(.title)
Text("Users under 18 cannot complete purchases.")
.foregroundColor(.gray)
}
.padding()
.background(Color.white)
.cornerRadius(16)
}
}
}
// Use it:
TeenCheckoutWarningView {
MyTeenWarning()
}The main manager for age checking:
@available(iOS 26.0, *)
public class AgeRangeManager: ObservableObject {
public static let shared: AgeRangeManager
// Current age range from system
@Published public private(set) var currentAgeRange: AgeRangeService.AgeRange?
// Loading state
@Published public private(set) var isLoading: Bool
// Check age using environment value
public func checkAgeRange(using requestAgeRange: DeclaredAgeRangeAction) async
// Computed properties
public var isUnder13: Bool // User is under 13
public var isTeen: Bool // User is 13-17
public var isAdult: Bool // User is 18+
}View for blocking users under 13:
public struct UnderageBlockerView<Content: View>: View {
public init(@ViewBuilder content: () -> Content)
}- Automatically prevents dismissal (
.interactiveDismissDisabled()) - Accepts custom content for your design
View for warning teen users at checkout:
public struct TeenCheckoutWarningView<Content: View>: View {
public init(@ViewBuilder content: () -> Content)
}- Automatically prevents dismissal (
.interactiveDismissDisabled()) - Accepts custom content for your design
Check out the USAGE.md file for detailed examples and patterns.
- No Storage: Age data is retrieved from the system via
@Environment(\.requestAgeRange) - Computed Properties: Age range is checked against your thresholds (13, 18)
- Custom UI: You provide all UI via
@ViewBuilderclosures - Thread-Safe: All
@Publishedupdates happen onMainActor
Separation of Concerns: The package handles age verification logic, you handle the design.
- β Package provides the "what" (age checking, blocking logic)
- β Your app provides the "how" (colors, fonts, layouts)
This allows:
- Using your design system/tokens
- Supporting dark mode with your colors
- Localizing text in your app
- A/B testing different designs
- Complete brand control
// The package gracefully handles unavailable API
// Returns nil for currentAgeRange on older iOS
// Defaults to safe behavior (treats unknown as under 13)
if ageManager.currentAgeRange == nil {
// API not available or declined
}- Add support for custom age gates
- Localization helpers
- Example designs library
- Unit tests
- CI/CD setup
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Built on Apple's Declared Age Range API
- Inspired by clean architecture principles
- Design-agnostic approach from component library best practices
- π Issues: GitHub Issues
- π Docs: Full Documentation
Alok Choudhary - @alokc83
Note: This package requires iOS 26.0+ and Xcode 26.0+.