Guideline 2.1 rejection: App Completeness
How the rejection usually reads: "We discovered one or more bugs in your app" / "Information Needed" / "the app crashed on launch"
Why it happens
2.1 is the single most common rejection because it is a catch-all: crashes, dead links, placeholder content, a demo account that does not work, a feature the description promises but the build does not have. The reviewer runs the app on a real device for a few minutes and reports whatever breaks. The frustrating part is that most 2.1 rejections are mechanical and visible in the build before you upload: a framework that was not embedded (crash on launch), a support URL that returns 404, a leftover localhost address from development. Fix what they named, then look for what they did not name — on the next round they only re-check the diff.
What can be checked before you submit
12 of RejectProof’s checks map to Guideline 2.1. Each one reads your .ipa — no upload — and reports the evidence with a fix.
- Development server references left in the build
PB-30 · guideline 2.1 · likely rejection
This build still points at a local Metro / Expo dev server. Build a release binary: Expo → `eas build --profile production`; bare RN → Release configuration with a bundled JS file; make sure no exp:// or localhost:8081 URLs remain. Reviewers cannot reach your machine, so the app fails to load and is rejected under 2.1.
- Dead links inside the app
PB-33 · guideline 2.1 · probable
Every link the reviewer can tap must open a working page (support, privacy policy, terms, help, in-app WebView pages). Fix or remove the URLs listed in the evidence, then rebuild — App Review opens them in Safari and rejects under 2.1 (App Completeness) when they 404. For links only visible inside a WKWebView, load that page on a device with the production build before submitting.
- Embedded framework missing — crash on launch
PB-34 · guideline 2.1 · likely rejection
The executable links a dynamic framework that is not inside the .app bundle, so dyld aborts before your code runs ("Library not loaded: @rpath/…" in the crash log) and App Review rejects under 2.1 (App Completeness). Xcode: select the target → General → Frameworks, Libraries, and Embedded Content → set the framework to "Embed & Sign" (not "Do Not Embed"); for CocoaPods run `pod install` again and make sure use_frameworks! matches how the pod is built. Expo/EAS: remove the framework from any manual `ios/` edits or config plugin, run `npx expo prebuild --clean`, then `eas build --platform ios --profile production`. Static libraries (.a) and XCFrameworks marked static do not need embedding; only dynamic frameworks listed in the evidence do.
- Missing arm64 slice / unsupported architecture
PB-35 · guideline 2.1 / 2.5.1 · likely rejection
App Store builds must contain a device (arm64) slice built for the iOS platform. A simulator build (x86_64, or arm64 with the iOS Simulator platform) fails to install on devices and is rejected under 2.1 / 2.5.1. Xcode: Product → Archive with destination "Any iOS Device (arm64)", not a simulator; check Build Settings → Architectures = Standard, Excluded Architectures does not exclude arm64, and Build Active Architecture Only = No for Release. Expo/EAS: use `eas build --platform ios --profile production` (a device build); never upload a build made with `"simulator": true` in eas.json, and do not submit `.app` folders from `npx expo run:ios`.
- Minimum iOS in Info.plist does not match the binary
PB-36 · guideline 2.1 · warning
Info.plist MinimumOSVersion, the executable's deployment target (LC_BUILD_VERSION minos) and every embedded framework's MinimumOSVersion must agree. When a framework requires a newer iOS than the app declares, the app installs on older devices and dies at launch with "Symbol not found" / "Library not loaded"; App Review tests on the oldest iOS you declare and rejects under 2.1. Xcode: set one iOS Deployment Target at the project level and let all targets inherit it; for CocoaPods add `platform :ios, 'X.Y'` to the Podfile and re-run `pod install`; for SPM packages check their minimum platform. Expo/EAS: set `expo-build-properties` → ios.deploymentTarget in app.json (or `ios.deploymentTarget` in Podfile.properties.json), then `npx expo prebuild --clean` and rebuild.
- WKWebView links open in a new window but nothing handles the popup
PB-42 · guideline 2.1 · warning
In a WKWebView, a link with target="_blank" (or window.open) does nothing unless the app implements WKUIDelegate's webView(_:createWebViewFor:navigationAction:windowFeatures:) — the tap silently fails and App Review reports it as a broken feature under 2.1. Either implement that delegate method (load the request in the same web view or open it in Safari), or strip target="_blank" from the web content. react-native-webview: set setSupportMultipleWindows={false} or handle onOpenWindow.
- Localized resources shipped but CFBundleLocalizations not declared
PB-43 · guideline 2.1 / 2.3.3 · warning
iOS picks the app language from CFBundleLocalizations (and CFBundleDevelopmentRegion) in Info.plist, not from the .lproj folders you ship. Without the key, a reviewer's device can open the app in the wrong language and the rejection reads like a vague 2.1 'does not match' note. Declare every shipped language: Expo: app.json → expo.ios.infoPlist.CFBundleLocalizations: ["en", "ar"] (or expo-localization's config plugin); Xcode: project → Info → Localizations. Also read the device language at first launch instead of hardcoding one.
- Sign in with Apple code present but the entitlement is missing
PB-46 · guideline 2.1 · probable
ASAuthorizationAppleIDProvider is referenced but the provisioning profile has no com.apple.developer.applesignin entitlement, so the Apple button fails at runtime (error 1000) — the reviewer taps it, sees an error, and rejects under 2.1. Xcode: Signing & Capabilities → + Sign in with Apple, then regenerate the profile. Expo: set expo.ios.usesAppleSignIn: true in app.json and rebuild with EAS so the entitlement is added.
- Google Sign-In SDK without its URL scheme — sign-in cannot return to the app
PB-47 · guideline 2.1 · probable
GIDSignIn needs a CFBundleURLTypes entry whose scheme is the reversed client id (com.googleusercontent.apps.<id>); without it the Google flow opens Safari and never comes back, which the reviewer reports as a 2.1 bug. Xcode: Info → URL Types → add the reversed client id from GoogleService-Info.plist. Expo: @react-native-google-signin config plugin with iosUrlScheme in app.json.
- Facebook SDK without FacebookAppID — crashes at launch
PB-48 · guideline 2.1 · probable
FBSDKCoreKit throws on startup when Info.plist has no FacebookAppID / FacebookClientToken, and a crash at launch is an automatic 2.1 rejection. Add FacebookAppID, FacebookClientToken, FacebookDisplayName and a CFBundleURLSchemes entry fb<APP_ID> to Info.plist — or remove the SDK if you do not use Facebook login/analytics.
- Native Firebase without GoogleService-Info.plist — crashes at launch
PB-49 · guideline 2.1 · probable
FirebaseApp.configure() aborts with "Could not locate configuration file GoogleService-Info.plist" when the file is not in the app bundle; the reviewer sees a crash on first launch (2.1). Download GoogleService-Info.plist from the Firebase console for this bundle id and add it to the target (Xcode: check 'Copy Bundle Resources'; Expo: expo.ios.googleServicesFile in app.json). If you only use the Firebase JS SDK, the native FIRApp reference means a native module is linked — remove it or configure it.
- Placeholder text (Lorem ipsum) shipped in the build
PB-52 · guideline 2.1 / 2.3.3 · warning
"Lorem ipsum" in a screen the reviewer reaches reads as an unfinished app (2.1 Completeness) and, if it appears in screenshots, a metadata rejection (2.3.3). Replace the placeholder copy, or remove the unfinished screen from the build.
What a scan cannot tell you
Static checks read the build; they do not run it. Whether a reviewer likes your design, agrees with your content, or considers the app “sufficiently different” is their call. Fix the mechanical layer first so the human review is about your product, not about a missing plist key.