-
Notifications
You must be signed in to change notification settings - Fork 20
Application code change behavior
This page explains what happens across the whole platform (SDK, backend, and message delivery) when the application code configured for an app changes on a device that was previously registered with a different application code.
Application code should ideally never change for a given application. It's tied to the application, not to which Infobip plugin/SDK you use. If you migrate your mobile integration from one framework to another (for example, from Cordova to React Native, or from a native integration to Flutter) while keeping the same bundle ID, the existing application code continues to work unchanged — there is no need to create a new one. Treat an application code change as a deliberate, rare operation, not a routine step of a plugin migration.
- Fresh install vs. application code change
- What the iOS SDK does locally
- What happens on the backend
- Effect on sending and targeting
- Practical guidance
A brand-new installation that has never had an application code stored in the Keychain is unaffected by anything on this page — it simply registers normally against whichever application code it's configured with. Everything described below only applies to an existing installation whose application code changes from a previously stored value to a different one (e.g., a client build is repointed from an old application to a new one).
On SDK init, applicationCodeChanged() compares the newly-provided application code against the one persisted in the Keychain. If it differs, doStart() runs a partial cleanup (doCleanUp(false)) before registering:
- Core Data storages (installation, user, message data) are dropped and recreated.
- The shared Notification Service Extension message cache and the APNs registration-health flag are reset.
- In-memory/archived installation, user, and internal SDK state are reset.
- The Keychain itself is not cleared as part of this — only the application code field in it is set to the new value. The old push registration ID stored in the Keychain survives this step.
The SDK then proceeds exactly as if starting fresh: it re-registers for remote notifications and performs a normal installation-create call under the new application code.
Because the old push registration ID survives in the Keychain while the local installation record is reset, a generic stale-ID reconciliation check in the SDK notices the mismatch between the just-created new registration ID and the leftover old one in the Keychain, and attempts to delete the old registration. However, by the time this fires, the new application code is already active, so the delete request is sent with the new application code but targets a registration ID that belongs to the old application. The backend rejects this, and you'll see something like:
[DeleteInstanceOperation] sync request failed with error: Error Domain=com.mobile-messaging.backend Code=0
"Application code does not match with push registration ID" ... messageId=APP_CODE_MISMATCH
This is expected and benign — it is not a sign of misconfiguration or a bug. It simply means the SDK tried (and, by construction, could not succeed) to clean up the stale old registration on the backend. The practical consequence is that the old registration is not deleted server-side (see below).
- A push registration ID is permanently bound to a single application code on the backend. The device's next registration under the new application code always creates a brand-new registration ID — there is no way to move an existing registration ID to a different application.
- That new registration always creates a brand-new anonymous LEAD person profile. Registration alone doesn't carry any user identity (external user ID, phone, email), so there's nothing to automatically link the new profile to the one that existed under the old application code.
- The old registration and its old person profile are not deleted or deactivated. As described above, the SDK does attempt a delete for the old registration, but it fails with
APP_CODE_MISMATCHby construction, so the old registration is left orphaned — it stays live until it naturally expires from inactivity, or until it's explicitly deleted through some other means. - The new registration only converges with the old person profile if the app explicitly re-personalizes with the same external user ID/phone/email as before — that's the normal personalize/merge flow, and it does not happen automatically just because it's the same physical device.
Sending to the new application only reaches devices that have already completed a fresh registration under the new application code — practically, that means users who have opened the updated app at least once after the change (registration happens automatically on next SDK init).
Sending to the old application can, in principle, still reach the orphaned old registration, since it isn't actually cleaned up server-side (the SDK's attempt to delete it fails, as explained above). This is an easy-to-miss edge case when auditing delivery numbers after an application code change — a stale registration may continue to receive old-application sends for a while after the device has effectively moved to the new application.
- Avoid changing application code unless truly necessary. Migrating between Infobip mobile plugins/SDKs with the same bundle ID does not require it.
- If a clean cutover is required (e.g., for compliance or to stop stale sends to old-application registrations), don't rely on automatic cleanup alone — plan the migration so old-application registrations are retired intentionally as part of the rollout, rather than expecting the SDK to clean them up for you.
- Encourage end users to open the updated app so their device completes the fresh registration under the new application code.
- If you see
APP_CODE_MISMATCHin your logs immediately after an application code change, this is expected — no action is needed on your part.
If you have any questions or suggestions, feel free to send an email to support@infobip.com or create an issue.