Skip to content

Fix iOS extraction of emoji-named files (Livewire 4 ⚡️ components)#138

Merged
simonhamp merged 1 commit into
mainfrom
ios-emoji-php-files
May 19, 2026
Merged

Fix iOS extraction of emoji-named files (Livewire 4 ⚡️ components)#138
simonhamp merged 1 commit into
mainfrom
ios-emoji-php-files

Conversation

@simonhamp
Copy link
Copy Markdown
Member

@simonhamp simonhamp commented May 19, 2026

Summary

PHP files with non-ASCII names — most visibly Livewire 4 components prefixed with ⚡️ — were unusable on iOS. The extracted Laravel app on the simulator contained files named e.g. ΓÜí∩╕Åcounter.blade.php instead of ⚡️counter.blade.php, so autoloading and view resolution silently failed.

Root cause: ZIPFoundation 0.9.19's entry.path ignores the archive's preferredEncoding and falls back to CP437 whenever the entry's EFS bit (general-purpose bit 11) is unset. macOS zip often omits that flag even when the bytes are valid UTF-8, so every non-ASCII filename came out mojibake'd.

Changes

resources/xcode/NativePHP/AppUpdateManager.swift

  • Force UTF-8 decode via entry.path(using: .utf8), with a fallback to entry.path only if the bytes aren't valid UTF-8.
  • NFC-normalize entry paths before writing, so NFD filenames coming from macOS sources don't land on iOS APFS in a form PHP autoloaders can't look up.

src/Commands/BuildIosAppCommand.php

  • Surface the actual zip stderr when createAppZip() fails, instead of throwing a bare "Failed to create ZIP file".

src/Commands/SimCommand.php + src/NativeServiceProvider.php (new command)

  • php artisan native:sim data — opens the booted simulator's data container in Finder
  • php artisan native:sim app — opens the parent of the .app bundle (so app.zip is visible next to NativePHP.app)
  • php artisan native:sim uninstall — uninstalls the app from the booted simulator (with confirmation)
  • --bundle-id= overrides the configured NATIVEPHP_APP_ID
  • Friendly errors for the common "no sim booted" / "app not installed" cases

The native:sim command was built to diagnose this bug, but it's broadly useful for inspecting simulator state during development, so it's included here.

Heads-up for reviewers

Changes under resources/xcode/ only reach consumer projects via php artisan native:install, which snapshots the template into nativephp/ios/. Anyone iterating on this fix locally needs to re-run native:install (or --force) for the Swift changes to actually get compiled.

Test plan

  • Add a file with emoji in the name to a Laravel app (e.g. a Livewire 4 component named ⚡️counter.blade.php)
  • Run php artisan native:install --force to copy the updated Swift into the iOS project
  • Run php artisan native:sim uninstall to clear any stale extraction
  • Run php artisan native:run ios
  • php artisan native:sim data → confirm the file name shows with the real emoji, and that xxd of the filename shows e2 9a a1 ef b8 8f (UTF-8 for ⚡️)
  • Confirm Livewire/autoload can resolve the component at runtime
  • php artisan native:sim app opens Finder at the .app parent dir
  • php artisan native:sim uninstall prompts for confirmation and successfully removes the app

🤖 Generated with Claude Code

ZIPFoundation 0.9.19's `entry.path` ignores the archive's preferredEncoding
and falls back to CP437 whenever the entry's EFS bit is unset — which macOS
`zip` often omits even for UTF-8 names. The result was that files like
`⚡️counter.blade.php` (Livewire 4 components) were extracted into the iOS
data container as `⚡️counter.blade.php`, and PHP autoloaders couldn't
find them.

- Force UTF-8 filename decode via `entry.path(using: .utf8)` with a fallback
  to `entry.path` if the bytes aren't valid UTF-8.
- Normalize entry paths to NFC before writing, so NFD filenames coming from
  macOS sources don't end up on iOS APFS in a form PHP can't look up.
- Surface zip stderr in BuildIosAppCommand instead of a bare "Failed to
  create ZIP file" exception.
- Add `native:sim {data|app|uninstall}` to open the booted simulator's
  data/app containers in Finder, or uninstall the app (with confirmation).
  This was the tool that made the bug diagnosable.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@simonhamp simonhamp marked this pull request as ready for review May 19, 2026 12:08
@simonhamp simonhamp merged commit 0d6d373 into main May 19, 2026
5 checks passed
@simonhamp simonhamp deleted the ios-emoji-php-files branch May 19, 2026 12:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant