Skip to content

Instantly share code, notes, and snippets.

@pratikbutani
Created August 5, 2026 10:12
Show Gist options
  • Select an option

  • Save pratikbutani/d2d2ea92070964b44ccf6020ff41c475 to your computer and use it in GitHub Desktop.

Select an option

Save pratikbutani/d2d2ea92070964b44ccf6020ff41c475 to your computer and use it in GitHub Desktop.
Target SDK 36 (Android 16) upgrade checklist — for Flutter & native Android apps

Target Android API 36 (Android 16) Upgrade — Engineering Prompt

By Pratik Butani

Context

Google Play requires app updates to target API level 36 (Android 16) by August 31, 2026 (an extension to Nov 1, 2026 is requestable). This applies identically to native Android and Flutter apps — Flutter builds through the same Android Gradle project under android/.

Goal: raise the target/compile SDK, confirm the toolchain actually supports it, identify and fix any API-36-specific behavior changes that affect this app, and ship a verified working release — not just a version number that happens to compile. A clean build proves almost nothing here; several of the real risks below compile perfectly and only fail on specific device configurations at runtime.

Step 1 — Baseline

  • Find current compileSdk/targetSdk (native: app/build.gradle; Flutter: android/app/build.gradle).
  • Find current AGP version, Gradle wrapper version, and (Flutter only) flutter --version / Flutter Gradle plugin version.
  • Don't assume compatibility from a table — try compiling against SDK 36 and see whether it's a clean success, a soft "untested compileSdk" warning, or a hard failure. All three are possible depending on the AGP version in use, and it's cheap to just check.

Step 2 — Toolchain

  • Install platforms;android-36 (latest point release) and matching build-tools via sdkmanager/Android Studio's SDK Manager.
  • If the compile check in Step 1 hard-fails, upgrade AGP + the paired Gradle wrapper version per Google's compatibility matrix — as its own commit, separate from the SDK bump, so a toolchain-upgrade regression is easy to isolate from an SDK-bump regression.

Step 3 — Bump and verify with a real release build

  • Set compileSdk 36 / targetSdkVersion 36 (or Flutter equivalent).
  • Build release, not just debug: ./gradlew bundleRelease / flutter build appbundle --release. R8/minification, resource shrinking, and signing only get exercised in a release build.
  • A soft "untested compileSdk" warning with an otherwise clean build is fine to ship (pending device testing below); a hard error means resolve Step 2 first.

Step 4 — Audit API-36 behavior changes

Read https://developer.android.com/about/versions/16/behavior-changes-16 directly before acting — don't implement from memory or from a checklist someone wrote months ago; Google revises these lists. As of this writing, the ones most likely to actually bite:

  1. Large-screen orientation/resizability restrictions are ignored on displays with smallest width ≥ 600dp (tablets, unfolded foldables, desktop windowing). android:screenOrientation, android:resizeableActivity="false", and aspect-ratio declarations all stop being honored there once you target 36.

    • If the app is genuinely phone-only and untested on large screens, don't let this slide silently into "resizable on tablets we never designed for." Two real options: a. Temporary opt-out: <property android:name= "android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY" android:value="true" /> in <application> (or a specific <activity>). Removed entirely once the app targets API 37 — this buys time, it isn't a permanent fix. b. Real adaptive-layout work — schedule as its own effort, don't fold it into "just bump the SDK."
    • Test on an actual tablet/foldable or a large-screen emulator (pixel_tablet device profile) before shipping either way. A phone simulated via adb shell wm size/wm density can substitute in a pinch, but some OEM skins block those commands outside root — verify the override actually took effect before trusting the test.
  2. Edge-to-edge enforcement (started at API 35, re-verify at 36). Apps without enableEdgeToEdge() + WindowInsetsCompat/ ViewCompat.setOnApplyWindowInsetsListener handling on top-level screens can end up with content under system bars. Grep for legacy colorPrimaryDark-based status bar tinting, android:statusBarColor/ navigationBarColor theme attributes, and setSystemUiVisibility/ SYSTEM_UI_FLAG_* — these are what Play Console's "deprecated APIs for edge-to-edge" warning is actually about.

  3. 16 KB memory page size support — only relevant if the app ships native code (NDK, or a dependency that does). Zero native libraries = automatically fine; otherwise every native .so needs 16 KB alignment (NDK r27+ defaults to this).

  4. Predictive back gesture — if android:enableOnBackInvokedCallback= "true" is set, re-verify custom back-handling (fragment stacks, WebView history, fullscreen player exits) still behaves correctly.

  5. Whatever else the official page calls out at the time you do this — read it, don't skip straight to a checklist.

Step 5 — Dependency audit

Don't assume "no library upgrades needed" from one project applies to another — check explicitly:

  • Google Play Services / Firebase BOM — old versions can have hard compileSdk ceilings or lack API-36 behavior fixes.
  • AndroidX (androidx.core, androidx.activity, androidx.window especially) — the edge-to-edge/large-screen APIs above live here; old versions may not have them.
  • Gradle-plugin-dependent tooling (Crashlytics, Google Services plugin, etc.) — recheck compatibility if AGP/Gradle got bumped in Step 2.
  • Native/NDK dependencies — re: 16 KB pages, above.
  • Flutter only: native-Android plugins can pin their own compileSdk floor/ceiling in android/build.gradle and block the whole app's bump even when your own code is fine. Run flutter pub outdated, and if the build fails, check plugins with native Android code individually before assuming it's your code.

Step 6 — ProGuard/R8 hygiene (do alongside, don't skip)

A major SDK bump is a good moment to audit proguard-rules.pro:

  • Remove -keep rules for packages that don't exist anywhere in the current dependency graph (verify with a grep + ./gradlew dependencies dump — don't delete on assumption).
  • Remove rules duplicating what a library's own bundled consumer-rules.pro already provides (most modern libraries ship these — AndroidX, Retrofit, Gson, Glide).
  • Leave anything protecting your own data-model classes accessed reflectively (Firestore/Gson/Moshi/Room) strictly alone.
  • Verify with an actual on-device smoke test of the release build after any ProGuard change — a successful build proves nothing about runtime reflection paths.

Step 7 — Version numbers

  • Bump versionCode/versionName for every build you intend to actually upload, even a small follow-up fix to the same release attempt. Play rejects re-uploading an already-consumed versionCode, and it's cheaper to over-increment than to guess whether a prior build was actually uploaded.
  • Do this work on its own branch, isolated from whatever's currently shipping — don't mix an SDK-target bump with unrelated feature work.
  • Confirm the release build is actually signed correctly (jarsigner -verify) — a build that compiles but isn't properly signed won't upload.

Step 8 — Test before calling it done

In order of value for time spent:

  1. Full release-mode build succeeds (not debug-only).
  2. Install on a real device (or an emulator matching the app's actual minSdk floor) and smoke-test: launch, primary content flow, any screen with heavy AppCompat/Material form widgets (first thing a ProGuard regression breaks), and platform-integration features (deep links, notifications, downloads, sign-in, purchases).
  3. If any screen is orientation-locked: test on a large-screen device or emulator specifically. This is the step most likely to get skipped and most likely to actually break something.
  4. After a real Play Console upload, re-check its "App quality"/pre-launch warnings — several of these (edge-to-edge, bitmap/R8 optimization, PiP suggestion) only surface there, not in local testing.

What NOT to do

  • Don't treat "it compiles" as "it works" — the large-screen and edge-to-edge risks above are both silent at compile time.
  • Don't guess manifest property names or behavior-change specifics from memory — confirm against current official docs at the time of the work.
  • Don't bundle this into an already-in-flight urgent release branch if avoidable.
  • Don't skip large-screen testing because your user base is "mostly phones" — Play Console's compliance check doesn't know your user distribution, and a broken tablet layout is worse than a slightly overdue targetSdk.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment