BuildNot yet confirmed elsewhere1 publisher3 min readPublished
Plugin-heavy Capacitor apps built on the default template fail Google Play's 2027 DEX rule
Google Play will require apps with more than 10 MB of DEX code to score at least 25% on obfuscation, optimisation and shrinking from February 2027. Capacitor's Android template ships with R8 switched off, so plugin-heavy apps built from it have to turn on minification and test the result before that date.
The Engineer · Build desk

What happened
- Capawesome's production app, which uses about 40 plugins, showed 1% obfuscation in Play Console on the default build settings.
- Play Console's requirements say missing a threshold "can affect an app's visibility and publishing capabilities on Google Play".
- Capawesome's fix sets minifyEnabled true in the release build and switches to the optimizing default ProGuard rules file.
- Without one extra keep rule for Capacitor's annotation types, the minified build passes and the app crashes on startup.
Why it matters
- exposure Any project generated with npx cap add android starts with minifyEnabled false, so an app that grew past 10 MB of DEX without anyone editing build.gradle misses the requirement by default.
- cost Most Capacitor plugins ship no consumer rules, so for each plugin that uses reflection or serialization, the team has to find the rule in its README and add it.
- decision The same rules-file swap moves the project off proguard-android.txt, whose -dontoptimize line AGP 9 rejects by default, so the Play fix and the AGP 9 upgrade can land as one change.
Play scores every uploaded bundle on three percentages: obfuscation, optimisation and shrinking [3]. For bundles built with AGP 8.10 or later, it reads them from an r8.json file inside the bundle, and any shrinker counts [8]. According to Capawesome, a Capacitor app on the default template scores close to zero on all three [3]. Capawesome's own app sat 24 percentage points under the 25% floor [22].
The rule does not reach every Capacitor app. The threshold is 10 MB of DEX code for apps and 50 MB for games [1][7]. According to Capawesome, the Capacitor, Firebase and Play Services dependencies together are enough to push an app with many plugins past 10 MB [23]. A lean app on the default template will also score near zero, but it falls outside the rule [3][1]. The post does not give a DEX size for a bare template build, so a team with only a few plugins has to measure its own bundle against the threshold.
The startup crash happens where two defaults meet. R8 has run in full mode by default since AGP 8.0 [11]. Capacitor's consumer rules keep every class annotated with @CapacitorPlugin and its public @PluginMethod methods. They also keep its @PermissionCallback and @ActivityCallback methods, even private ones [12]. They do not keep the annotation types themselves [12]. In Capawesome's logcat, the first launch of the minified build died in the CapacitorPlugins thread with a NullPointerException [20]. The fix is `-keep @interface com.getcapacitor.** { *; }` in proguard-rules.pro. The post marks that line as required in full mode and links it to ionic-team/capacitor issue #8589 [14].
We think the rest of Capacitor's consumer rules are careful work. Capacitor looks up permission and activity callbacks by method name at runtime, and its rules keep those methods, so permission requests and activity results survive R8 without any rule in the app [21]. AGP's defaults keep the @JavascriptInterface methods that Capacitor's MessageHandler uses to receive calls from JavaScript [16]. Firebase and Play Billing ship consumer rules of their own [17].
Capawesome's figures come from one production app on Capacitor 8.5.0 and AGP 8.13.2 [5]. Its steps assume Capacitor 8 and AGP 8.x [19]. For the result to carry over to another app, that app's plugins have to need nothing beyond what the post lists. The annotation rule applies to every Capacitor app, according to the post [14]. The plugin-specific lines do not carry over. Capawesome's -dontwarn entries cover optional database backends that its plugins probe for at runtime. For other apps, the post points to the missing_rules.txt file to find the equivalents [18]. In our view, any team near the 10 MB line should turn R8 on now and refuse to ship until a minified build launches cleanly. The Play threshold takes effect in February 2027 [1].
What to watch
- Whether ionic-team/capacitor#8589 ends with @capacitor/android keeping its own annotation types in its consumer rules, which would make the app-level keep line unnecessary.
- Whether Capacitor's Android template changes its release build to minifyEnabled true before the February 2027 threshold applies.
- How Play Console applies the visibility and publishing effects to apps still under 25% once February 2027 arrives.
Clarity's read
What the record supports and how the coverage leans. The claims behind it follow.
Reality
- Evidence55
- Adoption
- Insufficient
- Hype gap+10
- Incentives30
- Confidence60
Claim ledger
Ranked by verification strength, evidence, and original report placement.
- [1]
From February 2027, Google Play requires at least 25% obfuscation, optimization and shrinking for every app with more than 10 MB of DEX code.
ReportedSupportedSource: Capawesome, citing Play Console technical quality requirementsView cited source - [2]
The Android project that npx cap add android generates sets minifyEnabled false in the release build type, so R8 never touches the app's DEX code; the Capacitor Android template ships with R8 turned off.
- [3]
Google Play measures three percentages for every app bundle uploaded: obfuscation, optimization and shrinking. A Capacitor app built from the default template scores close to zero on all three.
- [4]
Capawesome's production app, which uses about 40 plugins, showed 1% obfuscation in Play Console with the default template settings.
- [5]
Capawesome's production app runs on Capacitor 8.5.0 with AGP 8.13.2.
- [6]
"not meeting a requirement can affect an app's visibility and publishing capabilities on Google Play"
ReportedSupportedSource: Play Console technical quality requirements, as quoted by CapawesomeView cited source - [7]
The thresholds apply to games with more than 50 MB of DEX code.
- [8]
For apps built with AGP 8.10 or higher, Play reads the optimization percentages from the r8.json file inside the bundle; any shrinker counts.
ReportedSupportedSource: Capawesome, citing the Android vitals page on DEX code optimizationView cited source - [9]
The fix sets minifyEnabled true in the release build type of android/app/build.gradle and switches the default rules file to proguard-android-optimize.txt.
- [10]
The Capacitor template points to proguard-android.txt, which contains -dontoptimize, blocking most of what R8 could do; AGP 9 no longer accepts it by default.
- [11]
R8 has run in full mode by default since AGP 8.0.
- [12]
Capacitor's consumer rules keep every class annotated with @CapacitorPlugin, its public @PluginMethod methods, and its @PermissionCallback and @ActivityCallback methods, even private ones, but not the annotation types themselves.
- [13]
Without the @interface keep rule, the minified build passes and the app crashes on startup.
- [14]
Every Capacitor app needs the rule -keep @interface com.getcapacitor.** { *; } in proguard-rules.pro; the post's comment says it is required in R8 full mode and references ionic-team/capacitor#8589.
- [15]
Most Capacitor plugins ship no consumer rules; a plugin that relies on reflection or serialization documents its rule in its README.
- [16]
AGP's defaults keep @JavascriptInterface methods, which is how Capacitor's MessageHandler receives calls from JavaScript.
- [17]
Firebase and Play Billing ship consumer rules of their own.
- [18]
The -dontwarn lines cover optional backends that plugins probe for at runtime and depend on which plugins an app uses; missing_rules.txt shows which are needed.
- [19]
The steps require a Capacitor 8 Android app and Android Gradle Plugin 8.x.
- [20]
Logcat from the first launch of Capawesome's minified build showed FATAL EXCEPTION: CapacitorPlugins, a RuntimeException caused by InvocationTargetException, caused by a NullPointerException.
- [21]
Capacitor resolves permission and activity callbacks by method name at runtime, and its consumer rules keep those methods, so permission requests and activity results survive R8 without any app-level rule.
- [22]
Capawesome's 1% obfuscation score sits 24 percentage points below Google Play's 25% threshold.
- [23]
Capacitor, Firebase and Play Services dependencies put a plugin-heavy app over the 10 MB DEX line.
Sources
1 independent publisher whose own reporting we read for this story.
- dev.toGoogle Play DEX Code Optimization in Capacitor Apps
1 article · October 10, 2026
Topics and entities
Follow any of these and your For You feed starts watching them — no settings page required.
Topics
- Android app distributionFollow
- Code shrinking and obfuscationFollow
- Cross-Platform Mobile DevelopmentFollow