"Detects unsafe safe-area overrides and hardcoded inset values that hide content behind the Dynamic Island, notch, or home indicator, violating Apple's Human Interface Guidelines for adaptive layout."
Install
npx skillscat add cruisediary/apple-app-review-skills/safe-area-compliance Install via the SkillsCat registry.
Skill: Safe Area Compliance
Purpose
Detects unsafe safe-area overrides and hardcoded inset values that hide content behind the Dynamic Island, notch, or home indicator, violating Apple's Human Interface Guidelines for adaptive layout.
Apple Guideline
- Primary: HIG — Adaptivity and Layout (Apple Human Interface Guidelines)
- Related: 2.1
- Reference:
references/hig/adaptive-layout.md
Real-World Rejection Cases
Case: Content hidden behind Dynamic Island on iPhone 14 Pro and later
Source: Apple Developer Forums
Root cause: View used.edgesIgnoringSafeArea(.all)without compensating insets, pushing interactive controls into the Dynamic Island cutout area.Case: Bottom navigation buttons unreachable behind home indicator
Source: App Store Connect rejection feedback
Root cause: Tab bar and custom buttons were positioned aty = screenHeight - 49— correct for notchless iPhones but obscured by the home indicator on Face ID devices.Case: Developer hardcoded
top: 44inset — broke on devices with different safe areas
Source: Apple Developer Forums
Root cause: The status-bar height is not a fixed constant; devices with Dynamic Island, notch, or no notch all have different top safe-area values.
Trigger
Invoke on any iOS project that targets iPhone or iPad to verify safe-area insets are respected.
Inputs
| Name | Type | Default | Description |
|---|---|---|---|
project_root |
path | cwd | iOS/macOS project root |
shared_context |
object | nil | Pre-collected context from appstore-full-audit Phase 1 |
Actions
Phase 1: Context Collection
Skip this phase if shared_context is provided.
Glob**/*.swift— collect Swift source files.Glob**/*.m— collect Objective-C source files.Glob**/*.storyboardand**/*.xib— note Interface Builder files for manual safe-area review.
Phase 2: Checks
Full safe-area suppression (SwiftUI)
Greppattern\.edgesIgnoringSafeArea\(\.all\)in**/*.swift
Every match → 🟠 HIGH. Suppressing all safe-area insets risks content being clipped by hardware features on any device.Zero-inset layout (UIKit)
GreppatternUIEdgeInsets\.zeroin**/*.swiftand**/*.m
Review each match for proximity to layout constraint setup. When used to zero out system-defined safe-area insets → 🟠 HIGH.Hardcoded safe-area constants
Greppatterntop:\s*44|bottom:\s*34|bottom:\s*83in**/*.swiftand**/*.m
Every match → 🟠 HIGH. These magic numbers match specific device safe-area heights and will be wrong on other hardware.Unscoped ignoresSafeArea (SwiftUI)
GreppatternignoresSafeArea\(\)in**/*.swift
Flag calls that do not include.keyboardas the region argument → 🟡 MEDIUM. Scoping to.keyboardis the safe pattern; bareignoresSafeArea()suppresses all regions.
Phase 3: Output
Collect all findings from Phase 2 and build the prioritised findings list below. Include file paths and line numbers. Omit tiers with no findings.
Output Format
## Safe Area Compliance — Findings
### 🔴 CRITICAL — Guaranteed rejection
- [ ] TODO: <exact actionable step> — `file:line` — HIG Adaptivity
### 🟠 HIGH — Very likely rejection
- [ ] TODO: <exact actionable step> — `file:line` — HIG Adaptivity
### 🟡 MEDIUM — Possible rejection
- [ ] TODO: <exact actionable step> — `file:line`
### 🟢 LOW — Best practice
- [ ] TODO: <exact actionable step>Tools Used
Glob, Grep, Read
Constraints
- Read-only. No file edits.
- No network calls.
- Skip Phase 1 if
shared_contextis provided by orchestrating agent. - Works on Swift, Objective-C, React Native, Flutter projects.
Quick Commands
Run these in your project root to check manually:
# Check for unsafe safe area overrides
!grep -rn "edgesIgnoringSafeArea\|ignoresSafeArea\|UIEdgeInsets\.zero" . --include="*.swift"
# Check for hardcoded inset values (44=nav bar, 34=home indicator)
!grep -rn "top:.*44\|bottom:.*34\|bottom:.*83" . --include="*.swift"Swift Anti-Pattern Reference
examples/swift/LayoutPatterns.swift
Detection Steps
Find target files
- Glob:
**/*.swift,**/*.m,**/*.storyboard,**/*.xib
- Glob:
Search for rejection patterns
- Grep
edgesForExtendedLayout = \[\]— disables safe area extension - Grep
UIEdgeInsets(top: 0\|UIEdgeInsets(top: 20\|UIEdgeInsets(top: 44— hardcoded status bar height - Grep
frame\.origin\.y = 0\|frame\.origin\.y = 20\|frame\.origin\.y = 44— hardcoded Y origin - Grep
safeAreaInsets\|safeAreaLayoutGuide— correct safe area handling (absence is the problem)
- Grep
Determine verdict
- Hardcoded
top: 20ortop: 44insets → 🟠 HIGH (content hidden behind Dynamic Island) edgesForExtendedLayout = []without safe area compensation → 🟠 HIGHsafeAreaLayoutGuideused throughout → 🟢 pass
- Hardcoded
Report
- File path + line of hardcoded inset
- Fix: Replace hardcoded insets with
view.safeAreaInsets.top; usesafeAreaLayoutGuideanchors in Auto Layout