Why Source Code Checks Miss What App Stores Actually Review
18 Feb 2026 · 5 min read · Erik van Kammen
When your app gets reviewed by Apple or Google, they don't look at your Git repository. They look at the compiled binary you uploaded. The IPA, the APK, the AAB.
This distinction creates blind spots.
Source code analysis and binary analysis answer different questions. If you're only doing one of them, you have blind spots.
Your source code represents intent. It's what you wrote, what you chose to include, and how you structured your logic.
Your binary represents reality. It's the compiled result after build tools, dependency resolution, code generation, resource bundling, and optimization have all done their work.
These two views can diverge significantly.
A dependency you removed from your lockfile might still be present in the binary because of caching or transitive inclusion. A font you never explicitly added might be bundled by an SDK. A privacy manifest might exist in your project directory but not be included in the final bundle.
The stores evaluate the binary. Your compliance checks should too.
Source-level scanning has real value. It operates on the code you control directly.
Strengths:
Typical coverage:
This catches a lot. But it misses everything that only exists in the compiled output.
Your Podfile lists 12 frameworks. The compiled IPA contains 31. The difference is transitive dependencies pulled in at build time. Source analysis sees your direct dependencies. Binary analysis sees what actually ships.
If you use xcframeworks, static libraries, or vendored binaries, the source-level view has no visibility into their contents. They're opaque blobs until you analyze the compiled output.
This is common in enterprise environments where teams consume internal SDKs as precompiled artifacts.
Tools like protocol buffers, code generators, and build plugins create source files during compilation. These generated files can introduce API usage, permissions, or resource references that don't exist in your version-controlled code.
Build configurations (debug vs release, product flavors, targets) determine which resources end up in the binary. A source scan sees all resources in your project directory. A binary scan sees only what's included in the specific build variant.
Compilers and build tools embed metadata in the binary: SDK versions, build flags, architecture information, entitlements. This metadata is visible to app store review but invisible to source analysis.
On Android, R8 shrinking can remove or retain code in ways that differ from what the source tree suggests. Code that exists in source may be tree-shaken away, and conversely, R8 keep rules from dependencies can preserve code you assumed was stripped. The binary is the only reliable view of what survived the optimization pass.
App store compliance is about what you ship, not what you wrote.
Both Apple and Google evaluate the binary, but differently:
If your privacy manifest claims you don't use file timestamp APIs, but a framework embedded in your binary does, the store sees the contradiction. Your source code is irrelevant at that point.
Here's a scenario that plays out regularly.
A team runs source-level dependency scanning. It reports 20 known dependencies, all licensed correctly, all with current privacy manifests.
They submit the IPA. Apple flags a privacy manifest violation for NSPrivacyAccessedAPICategorySystemBootTime. The team is confused because none of their declared dependencies use that API.
Turns out: a transitive dependency of their analytics SDK includes a performance monitoring library that calls mach_absolute_time(). It's not in the lockfile. It's not in the source tree. But it's in the binary.
This is the gap. Source analysis said everything was fine. Binary analysis would have caught it.
| Aspect | Source analysis | Binary analysis |
|---|---|---|
| When it runs | Before or during build | After build |
| What it sees | Declared dependencies, source files | Actual compiled output |
| Transitive deps | Partial (lockfiles list them, but precompiled/vendored deps are opaque) | Complete |
| Precompiled SDKs | No visibility | Full visibility |
| Build variants | All at once | Specific build |
| Speed | Fast | Depends on binary size |
| False positives | Higher (may flag unused code) | Lower (only what ships) |
Use both. They're complementary.
Source analysis during development and code review. It gives fast feedback at the point where changes happen.
Binary analysis after the build, in CI, and before submission. It gives the ground truth about what you're shipping.
If you have to pick one for compliance purposes, pick binary analysis. It's what the stores evaluate, and it catches the issues that matter most for submission.
A practical setup:
The first catches issues early. The second catches issues accurately.
AppCompliance focuses on binary analysis. You upload the IPA, APK, or AAB, and the scan evaluates what's actually in the compiled artifact: SDK inventory, privacy manifest coverage, embedded font detection, permission usage, and target API levels.
No tool replaces manual review entirely, and no tool can guarantee store approval. But binary-level visibility eliminates the class of surprises that comes from not knowing what's in your build artifact.
Everything technical in this post is checkable from the build itself, and that is exactly what AppCompliance does: upload an iOS or Android build, and minutes later you have every issue that would get it rejected, with the exact fix next to it.
One email when we open the doors. No spam, just the launch.