If your app got rejected this morning with a Guideline 2.5.2 letter pointing at CodePush, you are reading a familiar pattern. The wording usually mentions a method named downloadAndReplaceCurrentBundle, the phrase 'change features or functionality after App Review approval', and a warning about future submissions taking longer. The rejection targets a category of behavior Apple has flagged since the App Store launched, and the bar moved again after Microsoft retired App Center.
Short answer
Guideline 2.5.2 rejects builds that can download or execute code which adds or changes app functionality after review. Apple cites the rule whenever a binary contains the React Native CodePush SDK methods like downloadAndReplaceCurrentBundle, regardless of whether the developer ships JavaScript-only updates in practice. Microsoft retired Visual Studio App Center on 31 March 2025, so the CodePush client now talks to self-hosted or third-party servers, but the SDK itself is still what triggers the rejection per the App Review Guidelines.
What you should know
- 2.5.2 has been on the books since the App Store launched. The wording was not added because of CodePush. It exists because Apple wants the binary that gets reviewed to match the binary that runs on users' devices.
- Microsoft retired App Center on 31 March 2025. The hosted CodePush service stopped delivering updates that day, and the Microsoft team released the server as open source for self-hosting.
- The rejection text names the SDK method. The standard letter cites a specific Objective-C symbol such as
downloadAndReplaceCurrentBundle, plus dynamic resolution calls likedlopen,dlsym, orperformSelector:with a remote argument. - EAS Update is the modern Expo alternative. Expo's documentation states JavaScript bundle, image, font, and config updates are within scope, while native code changes still require an App Store binary submission.
- A repeat 2.5.2 letter can escalate. Section 3.3.2 of the Apple Developer Program License Agreement is the contractual hook that allows Apple to act at the account level, not only on the individual build.
What does Guideline 2.5.2 actually say?
Section 2.5.2 of the App Review Guidelines reads that apps should be self-contained in their bundles, may not read or write data outside the designated container area, and may not download, install, or execute code which introduces or changes features or functionality of the app, including other apps. There is a narrow educational exception for apps that teach, develop, or allow students to test executable code, provided the source code is fully viewable and editable by the user.
The phrase that matters in practice is 'introduces or changes features or functionality'. That is the criterion Apple uses to draw the line between a JavaScript update that fixes a typo (which it tolerates in practice) and a JavaScript bundle that adds a new screen, a new permission flow, or a new in-app purchase path (which it explicitly does not). The Apple Developer Program License Agreement, section 3.3.2, is the contractual backstop and the clause that allows action at the account level rather than the build level.
Why does CodePush trigger a 2.5.2 rejection?
CodePush is a JavaScript bundle delivery system for React Native originally built by Microsoft. The SDK ships native iOS code that fetches a new JavaScript bundle from a server, writes it to the app's container, and loads it on next launch. From the reviewer's perspective, that is a textbook case of an app that can change its own features after the review has finished, regardless of what the developer actually uses it for.
The rejection letter names the method. Developers on the react-native-code-push tracker have posted Apple letters that point at downloadAndReplaceCurrentBundle:, at dynamic symbol resolution like dlopen() and dlsym(), and at performSelector: calls where the selector name comes from a remote source. The reviewer is not reading the JavaScript bundle; they are reading the iOS binary's symbol table. If the symbol is there, the rejection follows.
Did App Center retiring change anything for App Review?
App Center retired on 31 March 2025, ending the hosted CodePush delivery service that powered most React Native deployments. Microsoft published the server code as open source so teams could self-host, and third-party providers like AppsOnAir, Revopush, and Shipper picked up the SDK contract. None of that changed the position of Apple App Review.
The SDK is the trigger, not the server. A self-hosted CodePush instance produces the same iOS symbols inside the binary, which means the same 2.5.2 rejection. Teams that hoped the retirement would quietly defuse the policy issue learned the opposite: with App Center gone, the developers most likely to keep using the original CodePush SDK are also the ones with the highest exposure to a fresh review letter on their next submission.
Are EAS Update and Expo OTA updates safe under 2.5.2?
EAS Update is the over-the-air pipeline Expo maintains for managed and bare React Native projects. Expo's documentation states that updates need to follow App Store and Play Store guidelines, that JavaScript bundle, image, font, and translation changes are within scope, and that native code changes require a new binary. Apps using EAS Update have shipped through App Review without 2.5.2 letters being the norm.
The qualifier matters. Expo can move JavaScript at runtime and App Review tolerates JavaScript updates that fix bugs or adjust copy. Expo cannot ship a new permission, a new entry in the Privacy Manifest, or a new native module after review. The moment an OTA update is used to introduce a feature that did not exist in the reviewed build, the developer is back inside 2.5.2 regardless of which vendor delivered the bundle.
Can a 2.5.2 rejection escalate to a developer account ban?
A first 2.5.2 letter is a build-level rejection. The standard wording asks the developer to remove the remote update capability and resubmit, sometimes adding that future submissions may face extended review. That extended review is the early warning sign. It signals that Apple has flagged the account, and that subsequent builds will be looked at more carefully.
The legal hook is section 3.3.2 of the Apple Developer Program License Agreement, which forbids running, loading, or interpreting code not embedded in the binary outside the narrow exceptions in the Guidelines. Repeat or willful violations are grounds for termination under the License Agreement's general termination clauses. Apple does not publish the exact threshold, so the cautious reading is that the second or third letter on the same SDK puts the account at material risk, not only the build. The rejection text itself is consistent across letters: clause citation, a sentence describing the offending capability, the bracketed Objective-C symbol, a request to remove the capability and resubmit, and sometimes a note that future submissions may face extended review.
| Approach | What Apple Review sees | 2.5.2 risk | Typical outcome |
|---|---|---|---|
| React Native CodePush SDK (App Center) | downloadAndReplaceCurrentBundle in binary symbol table | High | Build rejected, account flagged |
| Self-hosted CodePush server with original SDK | Same binary symbols, different backend | High | Rejection on the SDK, not the server |
| Expo EAS Update for JS, images, copy | Expo update client, tolerated in practice | Low when updates stay non-functional | Approved |
| EAS Update used to add new screens or permissions | New functionality absent at review | High | Rejection under 2.5.2 or 4.3 |
| Bundle-resident JavaScriptCore scripting | No remote download, all assets in IPA | Low | Approved when the runtime is documented |
What to watch out for
The most common mistake is treating 2.5.2 as a server problem and moving CodePush to a self-hosted instance. The iOS binary is what review reads, so the rejection repeats. A second mistake is assuming that any OTA tool will be approved because Expo's is tolerated; that tolerance is conditional on the content of the updates, not on the brand of the pipeline.
A third mistake is appealing without removing the SDK. Reviewers see the same arguments often and have a short tolerance for them. The path that works is to strip the offending native symbol, rebuild, submit a clean binary, and only then add a more conservative update mechanism that respects the 'no new functionality' line. For builders who want an external read of what their iOS bundle actually contains before they submit again, PTKD.com (https://ptkd.com) is one of the platforms that scans compiled IPAs for OWASP MASVS gaps and also surfaces the kind of remote-update SDK symbols that App Review flags.
Key takeaways
- 2.5.2 is read at the binary level. App Review inspects the iOS symbol table, not the server URL, so changing hosting providers does not change the verdict.
- The Microsoft CodePush SDK is the symbol most often named in rejection letters; self-hosting or migrating to AppsOnAir, Revopush, or Shipper keeps that symbol in the binary.
- EAS Update is the safer modern pipeline, but only when updates are limited to bug fixes, copy, and assets. New features still require a new App Store build.
- Section 3.3.2 of the Apple Developer Program License Agreement is the contractual hook for account-level action, so a repeated 2.5.2 letter on the same SDK carries real account risk.
- Some teams outsource the pre-submission read entirely to platforms like PTKD.com (https://ptkd.com), which flag remote-update SDK symbols inside an IPA before the App Review queue does.




