Apple's automated binary scanner (run before any human reviewer sees the app) uses symbol analysis to detect private API calls. This check is mechanical and highly accurate — a single _-prefixed private method call on a system object causes automatic rejection before human review begins, under Apple's guideline 2.5.1. The rejection email cites the specific private symbol. Native modules in the ios/ and android/ directories of React Native apps are the most common vector — they often include private API calls that were acceptable in older OS versions but have since been flagged. Apps rejected this way go to the back of the queue, adding weeks of delay.
Critical because Apple's automated scanner detects private API usage before human review — rejection is automatic, fast, and cannot be appealed without a code fix.
Audit all native module code in ios/ and android/ for private API usage before building the submission binary.
# Search for Objective-C private method calls on system objects
grep -r '\b_UI\|\b_NS\|SpringBoardServices\|GraphicsServices' ios/
# Search for Android internal API usage
grep -r 'com\.android\.internal\|getDeclaredMethod\|getDeclaredField' android/app/src/
Replace any private call with the documented public equivalent. For _UIApplicationDelegate._statusBar, use UIApplication.shared.statusBarManager. Run Xcode's static analysis (Product > Analyze) before every App Store submission — it flags deprecated and private API usage in Swift and Objective-C.
ID: app-store-review-blockers.technical-requirements.no-private-apis
Severity: critical
What to look for: Count all relevant instances and enumerate each. Search source files for known private Apple API prefixes: _UIApplication, _UIViewController, UIApp_, SpringBoardServices, GraphicsServices, IOKit (in iOS context), MobileInstallation, _LSCopyApplicationInformation. In Swift/Objective-C files, look for method calls starting with _ on system objects (e.g., UIDevice._batteryLevel). For Android, search for android.internal, com.android.internal, android.provider.Telephony.Sms.Intents private constants, or reflection calls that access getDeclaredMethod/getDeclaredField on Android system classes. In React Native / Flutter, check native modules and plugins in ios/ and android/ directories for any of these patterns. Also search for uses of deprecated APIs removed in the minimum supported OS version.
Pass criteria: No private, undocumented, or internal APIs are called. At least 1 implementation must be verified. All system API usage is through documented, public frameworks.
Fail criteria: Any invocation of _-prefixed private Objective-C/Swift methods on system objects; any use of com.android.internal.* classes or reflection to access Android system internals.
Skip (N/A) when: Never — private API usage causes automatic binary rejection by Apple's automated scanner.
Detail on fail: "Private iOS API call found in ios/MyApp/NativeModule.m: _UIApplicationDelegate._statusBar" or "Android code uses reflection to access com.android.internal.telephony.ITelephony"
Remediation: Apple's automated binary analysis detects private API usage before human review — apps are rejected before a reviewer ever sees them.
UIDevice._batteryLevel → Public: UIDevice.current.batteryLevelios/ and android/ directories — these are the most common location for private API usage in React Native appsapi-check tool via Xcode's Organizer before submissionReview the configuration in src/ or app/ directory for implementation patterns.