Google Play Requires API 35 by August 2025. Here Is What Breaks
16 Apr 2026 · 9 min read · Erik van Kammen
Update, July 2026: the API 35 deadline passed on August 31, 2025. The current requirement is Android 15 (API 35); from August 31, 2026, new apps and updates must target Android 16 (API 36). See the current target API deadline guide.
Arrays.asList().toArray() and String.format.Every Android app declares a targetSdkVersion in its manifest. This tells the OS which behavior changes the app has been tested against. When you raise this value, Android stops applying backward-compatibility shims and enforces modern security, privacy, and performance defaults.
Google uses this requirement as a lever. By mandating a minimum target API level for Play Store distribution, they push the entire ecosystem forward. Older behavior gets phased out, new privacy protections apply uniformly, and users on recent devices get a consistent experience.
The alternative would be a fragmented ecosystem where apps opt out of security improvements indefinitely. Google prevents that by raising the bar every year.
| Milestone | Date | Applies to |
|---|---|---|
| New apps and app updates must target API 35 | August 31, 2025 | All Google Play apps |
| Extension deadline (with Play Console request) | November 1, 2025 | Existing apps only |
| Wear OS, Android TV, and Android Automotive OS apps | August 31, 2025 | Must target API 34 (not 35) |
| Visibility reduction for outdated apps | Rolling | Apps targeting below the current requirement |
The visibility threshold is the critical one teams miss. If your app's target API level falls below Google Play's current requirement and a user's device runs a newer Android version, Google Play will hide your app from that user. It will not appear in search results or recommendations. Existing installs still work, but organic discovery drops to zero for new users on modern devices.
These changes only apply when your app sets targetSdkVersion to 35. If you target 34 or lower, Android continues applying the old behavior. But the moment you raise the target, all of these kick in.
Apps targeting API 35 render behind the system bars by default. The status bar and navigation bar become transparent overlays on top of your content. The deprecated setStatusBarColor, setNavigationBarColor, and R.attr#enforceStatusBarContrast APIs are ignored.
If your layouts assume the system bars are opaque blocks, you will see content hidden behind them. You need to handle window insets explicitly using WindowInsetsCompat.
ViewCompat.setOnApplyWindowInsetsListener(rootView) { view, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
view.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
Android 15 adds a cumulative timeout for certain foreground service types. Both of the following use the same mechanism: roughly six hours of cumulative execution within any rolling 24-hour window, not per instance and not per 30-day period:
dataSync: roughly six hours of cumulative foreground service time within any 24-hour window. This is a total across all dataSync service instances, not a per-instance limit, and the window is 24 hours, not 30 days.mediaProcessing: roughly six hours of cumulative foreground service time within any 24-hour window. This is also a cumulative total across instances, not a per-instance limit that resets when you start a new one.If your app relies on long-running background work, migrate to WorkManager for deferrable tasks or use the new dataTransfer foreground service type where applicable.
Broadcast receivers that listen for BOOT_COMPLETED can no longer start foreground services for certain types. If your app starts a dataSync or mediaProcessing foreground service from a boot receiver, the system will throw an exception. Use WorkManager to schedule the work instead.
String.format() now validates format strings more aggressively when the default locale uses a numbering system other than ASCII digits. Code like String.format("%02d", value) works fine with English locales but throws IllegalFormatException under locales such as bn-BD (Bengali) because the format specifier conflicts with the locale's digit set. Always pass Locale.US or Locale.ROOT explicitly for format strings that produce machine-readable output.
This change did not arrive with API 35: it shipped with Android 14's move to the OpenJDK 17 core libraries, but it keeps tripping up teams as they raise targetSdkVersion. Arrays.asList("a", "b").toArray() now reliably returns Object[]. Code that casts the result to String[], or otherwise assumes a typed array, still compiles but throws ClassCastException at runtime.
// Android 14+ (OpenJDK 17 core libraries): toArray() returns Object[]
String[] arr = (String[]) Arrays.asList("a", "b").toArray();
// throws ClassCastException: java.lang.Object[] cannot be cast to java.lang.String[]
Review any code that calls .toArray() on an Arrays.asList() result and assumes a typed (e.g. String[]) return type.
The Kotlin standard library added removeFirst() and removeLast() extension functions for MutableList. Android 15 adds methods with the same signature to the java.util.List interface. If your Kotlin code calls these methods on a Java ArrayList, the runtime may resolve to the Java platform method instead of the Kotlin extension, which has a different return type. Recompile with Kotlin 2.0+ and the latest Android SDK to resolve the ambiguity.
Several locale codes have been updated to align with IANA standards. Hebrew changes from iw to he, Yiddish from ji to yi, and Indonesian from in to id. If your app stores locale codes persistently or uses them in API calls, verify that both old and new codes are handled.
These changes affect every app running on an Android 15 device, regardless of targetSdkVersion. You cannot opt out by keeping a lower target.
Android 15 removes support for TLS 1.0 and TLS 1.1 at the platform level. Any app that connects to a server requiring TLS 1.0 or 1.1 will fail with a connection error. This is not gated on your target SDK version. If the device runs Android 15, TLS 1.0/1.1 are gone.
Audit your backend endpoints and third-party API integrations. Any endpoint that has not upgraded to TLS 1.2 or 1.3 will become unreachable for users on Android 15 devices. Use tools like nmap --script ssl-enum-ciphers -p 443 yourdomain.com to verify supported protocol versions.
Apps that play audio without requesting audio focus through AudioManager.requestAudioFocus() will have their audio output automatically muted when another app holds focus. This applies to all apps on Android 15, regardless of target API.
Apps that previously set DND rules can no longer create certain AutomaticZenRule types without explicit user permission. If your app manages DND settings, test the behavior on Android 15 devices to ensure rules are applied correctly.
Set compileSdk and targetSdkVersion to 35 in your module-level build.gradle:
android {
compileSdk 35
defaultConfig {
targetSdkVersion 35
}
}
Apply window insets to your root layouts. If you use Jetpack Compose, use Modifier.windowInsetsPadding(). For Views, use ViewCompat.setOnApplyWindowInsetsListener. Test every screen, especially ones with bottom navigation or floating action buttons.
List every foreground service in your manifest. For each one:
- Check if it uses dataSync or mediaProcessing and verify your cumulative usage stays well under six hours within any 24-hour window.
- Migrate deferrable work to WorkManager.
Search your codebase for String.format( calls that do not pass an explicit Locale parameter. Add Locale.US or Locale.ROOT to any format string that produces machine-readable output (timestamps, identifiers, file names).
// Before
String result = String.format("%02d:%02d", hours, minutes);
// After
String result = String.format(Locale.ROOT, "%02d:%02d", hours, minutes);
Create an Android 15 (API 35) AVD in Android Studio and run your full test suite. Pay attention to: - Layout clipping behind system bars - Background services being terminated unexpectedly - Network calls failing due to TLS 1.0/1.1 removal (this affects all devices, not just your target) - Locale-dependent formatting crashes
Upload your updated APK or AAB to a closed testing track and review the pre-launch report. Google runs automated tests on real devices and flags crashes, accessibility issues, and security warnings. Fix any flagged issues before promoting to production.
compileSdk and targetSdkVersion set to 35String.format calls use explicit locale for machine-readable outputArrays.asList().toArray() usage reviewed for typed-array assumptionsiw/he, ji/yi, in/id)If you use AppCompliance for binary scanning, the SDK inventory and target API checks will flag outdated configurations before you submit to the Play Store.
What happens if I miss the August 31 deadline?
You cannot publish new apps or updates until you raise targetSdkVersion to 35. Existing installs continue to work, but you are locked out of the Play Store until you comply. You can request an extension through Play Console that pushes the deadline to November 1, 2025.
Does this affect apps distributed outside of Google Play?
No. The target API requirement is a Google Play policy, not an Android OS restriction. Sideloaded apps and apps distributed through alternative stores are unaffected. However, the platform-wide changes like TLS 1.0/1.1 removal still apply on Android 15 devices.
Can I target API 35 but keep my minSdkVersion low?
Yes. targetSdkVersion and minSdkVersion are independent. You can target API 35 while supporting devices as old as API 21 (Android 5.0). The target determines which behavior changes apply on modern devices. The minimum determines the oldest device that can install your app.
What about Wear OS and Android TV apps?
Wear OS, Android TV, and Android Automotive OS apps must target API 34, not 35. The deadline is the same (August 31, 2025), but the required level is one version behind.
How do I check which API level my app currently targets?
Open your module-level build.gradle or build.gradle.kts and find the targetSdkVersion (Groovy) or targetSdk (Kotlin DSL) value. You can also inspect a compiled APK with aapt dump badging yourapp.apk | grep targetSdkVersion.
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.