feat(android): add WebP image format + fix uncompressed PNG output - #399
Open
PrestaEdit wants to merge 1 commit into
Open
feat(android): add WebP image format + fix uncompressed PNG output#399PrestaEdit wants to merge 1 commit into
PrestaEdit wants to merge 1 commit into
Conversation
Currently `Concerns/InstallsAppIcon::resizePng()` writes bitmaps via
`imagepng($resized, $dst, 0)` — compression level 0, i.e. essentially
uncompressed. A 1280×1920 splash lands at ~9 MB instead of ~2 MB, and
the equivalent icons pay the same tax. On real production apps this
alone triggers Play Console's "optimize your app's images" warning
before the AAB ever leaves the build.
Fix that (level 9), and add opt-in WebP output for both launcher icons
and splash screens — Android supports WebP natively at AAPT level since
API 14 (lossless: API 18), well below every real NativePHP minSdk.
Changes
- New config `android.image_format` (`png` default, `webp` opt-in),
driven by `NATIVEPHP_ANDROID_IMAGE_FORMAT`.
- `Concerns/InstallsAppIcon`: `resizePng()` renamed to `resizeImage()`
with a `$format` param; `imagepng(…, 0)` → `imagepng(…, 9)`; new
`imagewebp(…, IMG_WEBP_LOSSLESS)` branch; `readImage()` helper that
accepts either PNG or WebP source; `androidImageFormat()` reads the
config and falls back to PNG when GD has no WebP support.
- `Concerns/InstallsAndroidSplashScreen`: detects `public/splash.webp`
and `public/splash-dark.webp` in addition to `.png`; output filename
becomes `splash.{png,webp}`; `validateSplashImage()` accepts WebP;
stale-file cleanup before writing so switching formats does not
leave two entries for the same drawable resource.
Backwards compatibility
- Default `image_format` is `png` — every existing project builds
byte-identical output except for the PNG-compression fix (smaller
bundle, same pixels).
- Opting into `webp` on a host whose GD lacks WebP silently downgrades
to PNG rather than failing the build.
Real-world impact (Alys, com.prestaedit.alys)
- Splash resources today: ~38 MB across 10 files (day+night × 5 densities)
- After `image_format=png` (compression fix only): ~11 MB
- After `image_format=webp` (lossless): ~3.8 MB
- Play Console bitmap-optimization warning cleared.
PrestaEdit
added a commit
to PrestaEdit/alys
that referenced
this pull request
Aug 27, 2026
…ientation, bitmap) Fixes the three actionable Play Console warnings on release 0.5.1: - Orientation: allow all 4 orientations in config/nativephp.php so NativePHP strips android:screenOrientation from MainActivity at build. Android 16 (targetSdk 36) ignores portrait locks on large screens anyway; this clears the large-screen compatibility warning. - Bitmap optimization: opt into WebP output via NATIVEPHP_ANDROID_IMAGE_FORMAT (default 'webp' here), gated behind a patched nativephp/mobile trait. Cuts splash resources from ~38 MB to ~4 MB in the AAB. - Fallback: scripts/optimize-splash.sh reruns the PNG→WebP conversion after a build if a composer update ever wipes the vendor patch. Edge-to-edge fixes (removed deprecated statusBarColor/navigationBarColor from MainActivity and themes.xml) are applied locally but live inside the gitignored nativephp/ tree. Upstream PR filed as NativePHP/mobile-air#399. docs/nativephp-webp-pr/ carries the patch, the ready-to-drop files, and the PR description for reference until it's merged. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add WebP output for Android bitmap resources + fix uncompressed PNGs
Motivation
Google Play Console flags apps that ship large, unoptimized bitmap resources under
"Optimize your app's images". On a real production app (Alys,
com.prestaedit.alys)the 5 splash-density PNGs alone weighed ~24 MB in the AAB — enough to trigger
the warning by themselves. Two root causes:
resizePng()inConcerns/InstallsAppIcon.phpcallsimagepng($resized, $dst, 0)— compression level 0, i.e. essentially uncompressed. A1280×1920splash lands at 9.4 MB instead of ~2 MB. Icons pay the same tax.aaptlevel since API 14 (lossless: API 18). NativePHP'sminSdksits well above that in every real-world project. Emitting WebP shrinks the same splash to ~1 MB losslessly — same visual output, ~90% smaller.Together these are Google's #1 bitmap-optimization suggestion in Play Console.
Changes
Config —
config/nativephp.phpgets a new opt-in toggle:Default
'png'keeps behavior identical for existing projects (zero BC break).Set
'webp'(orNATIVEPHP_ANDROID_IMAGE_FORMAT=webpin.env) to opt in.Concerns/InstallsAppIcon.phpresizePng()→resizeImage(), add$formatparameter ('png'|'webp').imagepng($dst, 0)→imagepng($dst, 9)— max compression. Applies to both PNG and WebP branches and shrinks PNG icons/splashes by 60-70% on its own (this is arguably a bug fix that could stand alone).imagewebp($dst, IMG_WEBP_LOSSLESS)branch.readImage()helper reads either PNG or WebP source (usesimagecreatefromwebpwhen available).androidImageFormat()helper reads the config and gracefully falls back to'png'if PHP GD was compiled without WebP support (imagewebpnot available).installAndroidIcon(): destination filename now derived from$format, and any stale opposite-extension file in the same folder is deleted first (avoids AAPT duplicate-resource errors on repeated builds when the toggle changes).Concerns/InstallsAndroidSplashScreen.phppublic/splash.webp/public/splash-dark.webpin addition to.png(WebP wins when both exist).splash.{png,webp}following the config.validateSplashImage()accepts WebP sources too.Backwards compatibility
'png'— no change for existing projects.'webp', if the host's PHP GD was built without WebP support (imagewebpmissing),androidImageFormat()transparently downgrades to'png'rather than crash the build.resizePng→resizeImage) has no external surface — both traits/concerns are consumed together viaPreparesBuild.Impact (real data from a shipping app)
Before (default settings today):
After,
image_format=png(just the compression fix):After,
image_format=webp(lossless):~34 MB shaved off the AAB, Play Console's bitmap warning cleared.
Test plan
InstallsAndroidSplashScreenTest,InstallsAndroidTest) still passes with default config.image_format=webpcode path..webpsource detection.NATIVEPHP_ANDROID_IMAGE_FORMAT=webp, unzip the AAB, verifydrawable-*/splash.webppresent anddrawable-*/splash.pngabsent; run app, splash renders correctly.Related
Play Console → App → Overview → "4 recommended actions" → "Improve your app's performance with bitmap image optimization".