It will hurt some Texas users, but not the rest of the world, which is very important.
I agree – one of my main concerns is how these laws will impact on all my other users.
Should we terminate the app ?
You could do that, but it's not a very good user experience. I plan to present some simple messaging that directs users to an Apple support article.
Here's a quick sketch of how I'm currently planning to handle this across a few different apps (in SwiftUI). I would appreciate any feedback on this approach, from either a technical or legal standpoint.
In my main App struct, I will branch into a new ContentViewWithAgeGate view for iOS 26.2+.
WindowGroup {
if #available(iOS 26.2, *) {
ContentViewWithAgeGate()
} else {
ContentView()
}
}
ContentViewWithAgeGate acts as a wrapper around ContentView and perfoms the checks:
import SwiftUI
@preconcurrency import DeclaredAgeRange
@available(iOS 26.2, *)
struct ContentViewWithAgeGate: View {
@Environment(\.requestAgeRange) var requestAgeRange
@State private var isAgeRestricted: Bool = false
var body: some View {
if isAgeRestricted {
AgeRestrictedView()
} else {
ContentView()
.task {
isAgeRestricted = await determineIfUserIsAgeRestricted()
}
}
}
private func determineIfUserIsAgeRestricted() async -> Bool {
let isEligibleForAgeFeatures = try? await AgeRangeService.shared.isEligibleForAgeFeatures
guard let isEligibleForAgeFeatures, isEligibleForAgeFeatures == true else { return false }
guard let ageRangeResponse = try? await requestAgeRange(ageGates: 18) else { return true }
switch ageRangeResponse {
case .sharing(let range):
guard let lowerBound = range.lowerBound, let ageRangeDeclaration = range.ageRangeDeclaration else {
// No lower bound or no declaration information; prevent access
return true
}
if lowerBound >= 18 {
// User is an adult
switch ageRangeDeclaration {
case .selfDeclared, .guardianDeclared:
// Insufficient level of evidence; prevent access
return true
case .checkedByOtherMethod, .guardianCheckedByOtherMethod, .governmentIDChecked, .guardianGovernmentIDChecked, .paymentChecked, .guardianPaymentChecked:
// Sufficient level of evidence; permit access
return false
@unknown default:
// Unknown AgeRangeDeclaration value; prevent access
return true
}
} else {
// User is not old enough; prevent access
return true
}
case .declinedSharing:
// User declined to share age info; prevent access
return true
@unknown default:
// Unknown response value; prevent access
return true
}
}
}
Then, AgeRestrictedView just presents some general information:
struct AgeRestrictedView: View {
var body: some View {
VStack(alignment: .center, spacing: 30) {
Text("Access to this app is age-restricted due to local laws in your state or territory.")
Text("Please verify your age with Apple and allow this app to access your age information.")
Text("For further information, please refer to the following Apple support article: https://support.apple.com/en-us/122770")
}
.multilineTextAlignment(.center)
.padding()
}
}
Topic:
App Store Distribution & Marketing
SubTopic:
General
Tags: