EEltaCrew
HomeBlog

Why I put forced in-app updates (IMMEDIATE) into 17 apps: users on old versions earned nothing after the ad SDK swap

Published 2026-09-16Measured 2026-09-11About 3 min readelta · EltaCrew

When I replaced the ads SDK in July 2026, users who had not updated produced zero revenue. No fix, policy or consent form reaches an old version. How I added Play In-App Update in IMMEDIATE mode to every app, why it can only be verified on a Play-installed build, and what shipped alongside it.

Why forced

In mid-July 2026 every app I run dropped to zero real ad impressions. It was not an account issue or invalid traffic; the legacy ads SDK (play-services-ads) had broken. I moved every app to the next-generation SDK (ads-mobile-sdk) and re-released. Then, for weeks afterwards, the reports showed users who had not updated still earning nothing.

That changed the standard. Whether it is an ads SDK, a policy fix or a consent form, a fix you ship never reaches users who stay on the old version. A FLEXIBLE update can simply be postponed. So on 11 September 2026 I added IMMEDIATE (forced) in-app updates to all 17 apps and released them together. When a newer version exists on Play, Google's full-screen update UI appears at launch and the app cannot be used until it updates.

Implementation

One dependency: com.google.android.play:app-update:2.1.0. Each app gets a class with a single static method, called from the entry activity's onResume.

That is all there is to it:

  1. Request appUpdateInfo from AppUpdateManagerFactory.create(context)
  2. If updateAvailability() == UPDATE_AVAILABLE and isUpdateTypeAllowed(IMMEDIATE)
  3. startUpdateFlowForResult(info, activity, AppUpdateOptions.newBuilder(IMMEDIATE).build(), REQUEST_CODE)
  4. In onResume, if DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS, do step 3 again (resumes when the user backed out mid-way)

No result callback, no strings, no snackbar. IMMEDIATE is handled entirely by Google's UI, so the app needs none. Apps with several entry points (the remote apps have main, Bluetooth and Wi-Fi activities) call it from every one of them. The one FLEXIBLE implementation I had was replaced with IMMEDIATE.

Verify only on a Play-installed build

On a debug build or a sideloaded APK, getAppUpdateInfo fails and nothing appears. That is why "I added it but nothing shows" is such a common report; usually the test method is wrong.

The check goes:

  1. Upload a lower-versionCode build to the internal testing track and install it via Play
  2. Upload a higher-versionCode build to the same track
  3. Launch the app on the device; the forced update screen must appear

In practice I also confirmed, after production release, that the Play-installed build showed the forced update screen and the EEA consent form on a physical phone.

What shipped with it

Two more things rode the same release:

Building, signing and uploading 17 apps in a day produced incidents. I split the builds across agents and 9 came out unsigned, because the signing-key environment variable was not in the instructions. A pre-upload check that compares the versionName and signer inside the AAB with the source caught it. File timestamps cannot. One app was signed with an old keystore and Play rejected it as "wrong key"; it was re-signed with the shared keystore.

Version scheme

While releasing everything I also unified the versionCode rule: versionCode is versionName with the dots removed. 1.2.3 is 123, the next release is 1.2.4 / 124, one patch per release. Four apps were using values like 12 and 13 and were brought in line. Play never lets versionCode decrease, so apps that already had one extra digit (for example 10018) keep that width and only bump the patch.

Summary

AndroidGoogle Playin-app updateapp operations

Related

R8 on, build green, app broken: five runtime traps that actually hit across 15 appsI enabled R8 in 15 apps for Play's 2027 code-optimization requirement. Every build passed, but 2 of the first 7 I installed broke at runtime. Gson deserialization, getIdentifier resource lookups, Room _Impl classes, and debuggable builds that silently disable R8: the kinds of failure that never show up in a crash log.One merchant account blocked releases for all 21 of my apps: Korean individual developers and Play Console's "additional information required"Right after I set up a merchant account to test a donation in-app product, Play Console demanded a business registration number and an e-commerce license number and blocked every release on the account. Deleting the products did not help, deleting the payout account did not help, and support's final answer was "this cannot be reversed". How an individual developer avoids this trap.Data safety forms with zero declarations are getting caught: auditing 21 apps and fixing them with CSV and the APIA phone number the user types in by hand, belonging to someone else, still counts as "phone number collection" to Google. After one rejection I compared all 21 apps' data-safety declarations against their source: 11 were wrong, and 3 had declared nothing at all. Why ad-only apps cannot declare zero, and how to fix the form with CSV and the API instead of the five-step wizard.