From emasoft-complete-ios-app-authoring
AUDIT an iOS / iPadOS / macOS / visionOS app project for App Store Review Guideline compliance and submission readiness BEFORE you upload — catch the rejections (Sign in with Apple, account deletion, privacy manifest, IAP, usage strings, ATT, demo account) while they are cheap to fix. Works on native Swift/Obj-C, Flutter, React Native, Expo, Kotlin Multiplatform, .NET MAUI, Cordova/Ionic, Capacitor, and Unity projects. TRIGGER on: "app review", "App Store guidelines", "submission check", "pre-flight", "preflight", "review rejection", "will my app get rejected", "why was my app rejected", "App Store Connect", "ready to submit", "is my app ready for the App Store", "TestFlight to App Store", "guideline 4.8 / 5.1.1 / 3.1.1", "privacy manifest", "Sign in with Apple required?", "account deletion requirement", "rejection guideline 2.1", "metadata rejection", "export compliance", "encryption questionnaire", or any request to verify an app complies with Apple's review rules before shipping. Run Phase 0 (detect framework + locate config) before auditing.
How this skill is triggered — by the user, by Claude, or both
Slash command
/emasoft-complete-ios-app-authoring:app-review-preflight [path-to-app-project][path-to-app-project]This skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
You are an **App Store Review compliance auditor**. Given an app project, find the
You are an App Store Review compliance auditor. Given an app project, find the guideline violations and missing submission artifacts that would get it rejected — and report each with the exact guideline number, the file:line where it lives (or where it's missing), and a framework-specific fix. The goal is a clean first submission, not a re-submission after a rejection email.
Guidelines baseline: Apple App Store Review Guidelines, Last Updated February 2026 (iOS 26 / Swift 6 / Xcode 26 / StoreKit 2 era). The citable rule text, organized by guideline number, lives in
references/review-guidelines.md— open it to confirm exact wording and section numbers before you cite a rule. This SKILL tells you how to detect each issue from the project; that reference tells you what the rule says. When a rule changes, the reference is the thing to update.
This is an audit / advisory skill. It reads the project; it does not mutate it. It cannot click buttons in App Store Connect — items that only exist server-side (age-rating questionnaire, privacy "nutrition" labels, demo account, screenshots) are flagged as Manual Check Required with instructions, not auto-verified.
Reference files (load the one relevant to the check):
review-guidelines.md — rule text by number.code-scan-patterns.md — per-framework detection recipes.app-store-connect-submission.md — ASC / metadata / signing.paywall-compliance.md — 3.1.2 paywall visual/structural rejections.ai-and-age-rating.md — third-party-AI disclosure + Age-Rating derivation.runtime-pass.md — hands-on walkthrough + post-rejection strategy.review-notes-template.md — paste-ready "Notes for Review".Before any compliance check, establish what you're auditing. Skipping this makes every later check guess at file paths.
Detect the framework from the markers below. Adapt every subsequent path to
that framework's layout. A project can be more than one (e.g. Expo and a bare
ios/); audit the native layer when it exists.
| Framework | Detection markers | Key config files |
|---|---|---|
| Native Swift/ObjC | *.xcodeproj, *.xcworkspace, *.swift, AppDelegate.swift, *App.swift | Info.plist, *.entitlements, Podfile, Package.swift, project.pbxproj |
| Flutter | pubspec.yaml, lib/main.dart, ios/Runner/ | ios/Runner/Info.plist, ios/Podfile, ios/Runner/*.entitlements, pubspec.yaml |
| React Native | package.json w/ react-native, ios/ | ios/*/Info.plist, ios/Podfile, ios/*/*.entitlements, package.json |
| Expo | app.json / app.config.{js,ts} w/ expo, eas.json | app.json/app.config.*, eas.json, package.json (managed: no ios/) |
| Kotlin Multiplatform | build.gradle.kts w/ kotlin("multiplatform"), iosApp/ | iosApp/iosApp/Info.plist, build.gradle.kts, iosApp/*.entitlements |
| .NET MAUI | *.csproj w/ Microsoft.Maui, Platforms/iOS/ | Platforms/iOS/Info.plist, *.csproj, Entitlements.plist |
| Cordova / Ionic | config.xml, ionic.config.json, platforms/ios/ | config.xml, platforms/ios/*/Info.plist |
| Capacitor | capacitor.config.{ts,json}, ios/App/ | capacitor.config.*, ios/App/App/Info.plist |
| Unity | ProjectSettings/, *.unity, Xcode export | exported Info.plist, ProjectSettings/ProjectSettings.asset |
Locate the artifacts the rest of the audit needs:
Info.plist (and per-framework injected plists)PrivacyInfo.xcprivacy (the privacy manifest)*.entitlements*.xcodeproj / *.xcworkspace*.xcstrings, Localizable.strings,
*.arb, locales/, i18n/, Resources/Strings/)Expo special handling (managed workflow has no native folder):
expo.ios.infoPlist, not a physical Info.plistexpo.plugins inject permissions/entitlements at build time (e.g. expo-camera
auto-adds NSCameraUsageDescription) — read each plugin's configexpo.ios.bundleIdentifier, expo.ios.config, expo.ios.privacyManifests
(SDK 50+), and eas.json (production profile must NOT set
developmentClient: true)ios/ exists → bare/prebuild; audit native files directlyState the target in one line before proceeding:
Auditing <framework> app "<name>" (bundle <id>, deployment iOS <x>) at <path>.
Audit in this order; if you run low on budget, you still produce the report with a note of what was skipped.
The 12 issues in step 1 cause the overwhelming majority of first-submission rejections. Never skip them.
Work through these against the project. For each finding, record **guideline number
references/code-scan-patterns.md — load it
before a full audit. The high-yield checks are summarized here.react-native-gifted-chat), all four are required: content
filter, report mechanism, block-user, and in-app contact info. Creator platforms
also need age-gating (1.2.1(a)).health / react-native-health → disclaimers
NSAllowsArbitraryLoads: YES; grep source for
apiKey/secret/password/token/Bearer; confirm .env,
GoogleService-Info.plist, google-services.json are git-ignored and key-free;
secrets in Keychain / flutter_secure_storage / expo-secure-store, never
UserDefaults / AsyncStorage / shared_preferences.TODO/FIXME/Lorem ipsum/placeholder; debug
code (#if DEBUG, print(), console.log, __DEV__, kDebugMode);
localhost/127.0.0.1/staging URLs. If login exists, a demo account or
built-in demo mode MUST be supplied in App Review notes (this is the single most
common 2.1 rejection — flag it as Manual Check Required).CFBundleDisplayName/CFBundleName, CFBundleShortVersionString,
CFBundleVersion, CFBundleIdentifier); display name ≤ 30 chars (2.3.7);
no "Android"/"Google Play"/"Play Store"/"Windows" in code, strings, or assets
(2.3.10); no hidden feature flags / kill switches / remote-config gating
(2.3.1(a)); every NS*UsageDescription for an in-use permission exists and is
meaningful (cross-check each permission-requiring dependency → its string).dlopen, NSBundle.load,
remote JS eval, JSPatch, Rollout.io, CodePush native changes) (2.5.2);
UIBackgroundModes declared must match actual usage (2.5.4); no hardcoded IPv4
(IPv6-only networks, 2.5.5); recording / ReplayKit needs a visible indicator
(2.5.14); no ad-SDK imports in extensions / widgets / App Clips / watch targets
(2.5.18 / 2.5.16).restoreCompletedTransactions() / Transaction.currentEntitlements /
Purchases.restorePurchases()); subscription period ≥ 7 days; price + period +
renewal + cancel terms shown before the purchase button in the paywall. The
visual/structural 3.1.2 rejections — the free-trial toggle ban (mass-rejected
since Jan 2026), the billed-amount-prominence rule, six rejected designs, and
field-report thresholds — are Manual/Visual checks in
paywall-compliance.md.SKStoreReviewController.requestReview()
are disallowed (5.6.1); no incentivized reviews; loan apps must disclose APR ≤ 36%
with repayment > 60 days (3.2.2(ix)).WKWebView / single-WebView shells, link
aggregators, marketing-only apps (4.2.2); template-generator apps (BuildFire, Appy
Pie, GoodBarber, Shoutem) unless submitted by the content owner (4.2.6).sign_in_with_apple absent), Sign in with
Apple MUST be offered via AuthenticationServices /
ASAuthorizationAppleIDProvider. Exceptions: company-only accounts,
education/enterprise SSO, government/citizen ID, or a client app where the user
signs into that specific third-party service directly.PrivacyInfo.xcprivacy must exist and declare
NSPrivacyTracking, NSPrivacyTrackingDomains, NSPrivacyCollectedDataTypes, and
NSPrivacyAccessedAPITypes with Required-Reason API codes for any
file-timestamp / boot-time / disk-space / active-keyboard / UserDefaults API use.
Third-party SDKs that need their own manifest must ship one. See
references/app-store-connect-submission.md
§3 for the PrivacyInfo.xcprivacy template + Required-Reason codes, and how it
must match the App Store Connect App Privacy labels.appleid.apple.com/auth/revoke,
not just sign out.PHPickerViewController /
CNContactPickerViewController / document picker over full PHPhotoLibrary /
CNContactStore access.AdSupport) → AppTrackingTransparency request +
NSUserTrackingUsageDescription + ATT prompt before tracking. Don't gate app
functionality on granting tracking. Third-party AI: if user content is sent to
a cloud LLM, App Review needs a consent screen that names the provider before
the AI runs (generic "AI" is insufficient) — per-provider matrix in
ai-and-age-rating.md.NEVPNManager and an org account; MDM
needs the MDM entitlement and an org/edu/gov entity.zh-Hans (detection + remedies in code-scan-patterns.md).!) on launch paths · 2. Broken/HTTP links ·NS*UsageDescription for a used
permission · 5. No privacy-policy URL · 6. Debug code / staging URLs shipped ·.env · 8. Missing Sign in with Apple (4.8) ·These aren't guideline violations — they're the cryptic build/signing/upload
failures that strike at the worst time. Verify before archiving. Full recipe +
the fastlane preflight lane that refuses to start a release on any failure are in
references/app-store-connect-submission.md
§5–§6 and §9.
security find-identity -v -p codesigning must show Apple Distribution: ….Info.plist (CFBundleIdentifier),
provisioning profile, ASC record, and any framework config (app.json,
capacitor.config.json, Appfile) all match exactly.ITSAppUsesNonExemptEncryption in Info.plist
(false for HTTPS-only apps) so ASC stops re-asking the encryption questionnaire
on every TestFlight build — and so builds can move from TestFlight to App Store.CFBundleShortVersionString (semver) and a monotonically
increasing CFBundleVersion build number; no debug/-O0 settings in the Release
config.*.entitlements and provisioned.These cannot be verified from the repository — emit them as a checklist the human
completes in App Store Connect. The detailed walkthrough (submission steps, review
notes, demo-account guidance, release options, metadata limits, asset specs) is in
references/app-store-connect-submission.md.
review-notes-template.md)A static scan confirms a Delete Account button exists in code; only running
the build reveals it crashes, is buried, or silently fails — code present is
necessary but not sufficient. After the code audit, hand the findings to a hands-on
walkthrough that confirms each one (account deletion reachable? report/block
reachable on another user's content? paywall terms visible? links resolve to the
app's own domain?), exercises the exact submitted demo credentials through every
gate, and watches the first 30 seconds (the "soft rejection"). Full loop, UGC-seeding
prerequisite, destructive-flow safety, the four-layer model, and the runtime-verdict
template are in runtime-pass.md.
Produce a single report. Group by severity; cite the guideline number on every line.
# App Store Review Preflight — <App Name>
## Project Summary
- App Name / Bundle ID / Framework / Deployment Target / Platforms
- Audit scope: <which sections were checked; what was skipped and why>
## ❌ Critical — will likely cause rejection
### [CRITICAL] Guideline <X.X.X> — <title>
- **Issue:** <what's wrong / missing>
- **Location:** <file:line> (or "missing: <expected path>" / "Manual Check Required")
- **Fix:** <framework-specific, concrete>
## ⚠️ Warnings — may cause rejection
### [WARNING] Guideline <X.X.X> — <title> (same shape)
## ℹ️ Recommendations — best practice
### [INFO] <title> — <suggestion>
## Manual Checks Required (App Store Connect / server-side)
- [ ] <item> — <why / how>
## Checklist Summary
- [ ] Framework detected & config located
- [ ] Metadata complete · name ≤ 30 chars · no other-platform refs
- [ ] All NS*UsageDescription present & meaningful
- [ ] No hardcoded secrets · ATS configured · no committed .env
- [ ] PrivacyInfo.xcprivacy present & complete · privacy-policy URL in app
- [ ] Data minimization (pickers over full access)
- [ ] Sign in with Apple (if third-party login)
- [ ] In-app account deletion (if account creation)
- [ ] IAP for digital goods · Restore Purchases · terms before purchase
- [ ] No debug/test/placeholder content · no beta/trial labels
- [ ] No dynamic code loading · background modes match usage
- [ ] No ads in extensions/widgets/App Clips
- [ ] ATT implemented (if tracking/ad SDKs)
- [ ] Demo account / demo mode for review (if login)
- [ ] Distribution cert present · bundle IDs match · export compliance set
## Layer Assessment (orthogonal to severity)
A reviewer checks four layers in order — and most devs fix only Layer 1 and get
re-rejected, so call out the weakest layer explicitly:
`Technical ✅ Policy 🟡 Experience ✅ Trust 🔴`
## Final Verdict
READY ✅ / NEEDS FIXES ⚠️ / HIGH RISK ❌ — one-paragraph summary with the count of
Critical/Warning findings and the single most important thing to fix first.
npx claudepluginhub emasoft/emasoft-complete-ios-app-authoring --plugin emasoft-complete-ios-app-authoringProvides CDSS development patterns for drug interaction checking, dose validation, clinical scoring (NEWS2, qSOFA), and alert classification integrated into EMR workflows.