s2br/nativephp-mobile-icon
Composer 安装命令:
composer require s2br/nativephp-mobile-icon
包简介
Per-platform, variant-aware app icons for NativePHP Mobile — light/dark/tinted (iOS), adaptive/themed (Android), and date-scheduled alternate icons.
README 文档
README
A NativePHP Mobile plugin for app icons that goes beyond a single icon.png: per-platform primary icons, iOS 18 light/dark/tinted appearances, Android adaptive & themed icons, and named alternate icons you can switch on a schedule (Christmas, Black Friday, …) — all driven by one config file.
⚠️ Read this first — app icons are not splash screens. The home-screen icon is owned by the OS and baked into the app at build time. Unlike a splash animation, you cannot download a new icon and apply it at runtime. Runtime switching only works among variants you bundled at build time; adding a new one needs a rebuild + app release. See Platform Constraints.
Requirements
- PHP 8.2+ with
ext-gd(image generation) - NativePHP Mobile 3.0+
- Minimum platforms: Android 8 (API 26), iOS 18.0
Installation
composer require s2br/nativephp-mobile-icon php artisan vendor:publish --tag=mobile-icon-config php artisan native:plugin:register s2br/nativephp-mobile-icon
(native:plugin:register wires it into your NativeServiceProvider; publish the provider first with php artisan vendor:publish --tag=nativephp-plugins-provider if you haven't.)
What it does
| Capability | iOS | Android |
|---|---|---|
| Per-platform primary icon | ✅ | ✅ |
| Light / dark / tinted appearances (iOS 18) | ✅ | — |
| Adaptive icon (foreground/background) | — | ✅ |
| Themed/monochrome icon (Android 13+) | — | ✅ |
| Named alternate icons (bundled) | ✅ | ✅ |
| Scheduled switching (date/season) | ✅* | ✅* |
| Remote/downloadable icons (no rebuild) | ❌ | ❌ |
* among build-time-bundled variants only — see constraints.
Where to put your icons
Save your icon files in your app's resources/icons/ directory, and reference them with a path relative to the project root (resolved via base_path() at build time — the same convention the splashscreen plugin uses for resources/animations/):
your-app/
└── resources/
└── icons/ ← create this folder
├── app-ios.png
├── app-android.png
└── christmas-ios.png …
MOBILE_ICON_IOS="resources/icons/app-ios.png" MOBILE_ICON_ANDROID="resources/icons/app-android.png"
Image requirements:
| Use | Size | Transparency |
|---|---|---|
iOS primary (default.ios) |
1024×1024 PNG | Opaque — Apple rejects transparent app icons |
| iOS dark / tinted appearance | 1024×1024 PNG | Transparency expected |
Android adaptive foreground |
1024×1024 PNG | Transparency expected (keep art in the centre safe zone) |
| Alternate variants | 1024×1024 PNG | Match the platform's primary rule |
Any location under the project root works, but resources/icons/ is the recommended spot. A missing file surfaces as a build-time warning from the plugin's validate().
Configuration
Everything lives in config/mobile-icon.php.
Primary icon (per platform)
'default' => [ 'ios' => 'resources/icons/app-ios.png', // 1024×1024 PNG, no transparency 'android' => 'resources/icons/app-android.png', ],
iOS 18 appearances
'ios_appearance' => [ 'light' => 'resources/icons/app-light.png', 'dark' => 'resources/icons/app-dark.png', 'tinted' => 'resources/icons/app-tinted.png', ],
Android adaptive / themed
'android_adaptive' => [ 'foreground' => 'resources/icons/fg.png', 'background' => '#079F3D', // hex color OR a PNG path 'monochrome' => 'resources/icons/mono.png', // optional, powers themed icons ],
Alternate icon variants
'variants' => [ 'christmas' => [ 'ios' => 'resources/icons/christmas-ios.png', 'android' => 'resources/icons/christmas-android.png', ], 'black_friday' => [ 'ios' => 'resources/icons/bf-ios.png', 'android' => 'resources/icons/bf-android.png', ], ],
Schedule
'schedule' => [ ['variant' => 'christmas', 'from' => '12-24', 'to' => '12-26'], // recurs yearly ['variant' => 'black_friday', 'from' => '2026-11-27', 'to' => '2026-11-28'], // that year only ],
Dates use MM-DD (recurs every year) or YYYY-MM-DD (specific year); a full-date entry wins over a recurring one — the same rule as the splashscreen plugin.
Runtime API
use S2BR\MobileIcon\Facades\MobileIcon; MobileIcon::set('christmas'); // switch to a bundled variant MobileIcon::reset(); // back to the primary icon MobileIcon::supported(); // is runtime switching available? MobileIcon::current(); // active variant
After applying, native dispatches S2BR\MobileIcon\Events\AppIconChanged (variant, success).
use Livewire\Attributes\On; #[On('native:'.\S2BR\MobileIcon\Events\AppIconChanged::class)] public function onIconChanged(string $variant, bool $success): void {}
JS:
import { MobileIcon } from './vendor/.../mobileIcon.js'; MobileIcon.set('christmas'); const off = MobileIcon.onChanged(({ variant, success }) => console.log(variant, success));
App Icon Badge
Show a notification count on the app icon (the red number).
use S2BR\MobileIcon\Facades\MobileIcon; MobileIcon::setBadge(3); // show "3" MobileIcon::setBadge(3, 'S2BR', '3 new messages'); // custom Android notification text MobileIcon::setBadge(0); // clear MobileIcon::clearBadge(); // clear
MobileIcon.setBadge(3); MobileIcon.clearBadge();
Platform reality — read this before relying on it:
- iOS sets the exact number via
UNUserNotificationCenter.setBadgeCount. It requires badge/notification permission (NativePHP's push enrollment requests it). iOS never decrements the badge on its own — callsetBadge()/clearBadge()as the user reads notifications to keep it in sync. - Android has no API to put an arbitrary number on the launcher icon. The badge is driven by a single quiet local notification this plugin posts, so:
- Supporting launchers (Samsung, Xiaomi, …) show the count; stock/Pixel shows a dot.
- It needs the
POST_NOTIFICATIONSruntime permission on Android 13+ (declared by the plugin; you still request it at runtime). - The badge implies a real, silent notification sits in the shade — pass
title/bodyto make it meaningful.setBadge(0)/clearBadge()cancels it.
So: iOS = exact number; Android = a dot, or a count on launchers that support it.
Platform Constraints
These are OS limitations, not plugin shortcomings — know them before designing around dynamic icons:
- Build-time only. Every variant must be compiled into the app. There is no way to download and apply a brand-new icon at runtime on either platform.
- iOS shows a system alert (“You have changed the icon for …”) on every
setAlternateIconNamecall. There is no App-Store-safe way to suppress it. Plan your UX around one deliberate switch, not frequent flips. - Android switches by enabling an
<activity-alias>, which typically restarts the app and can behave differently per launcher/OEM; pinned shortcuts may not follow.
If you need a splash that updates remotely without an app release, that's the splashscreen plugin — icons can't work that way.
How It Works
copy_assetsvalidates your source PNGs.pre_compilegenerates per-platform icons with GD, writes the iOS asset catalog / Android adaptive resources, registers alternate icons (iOSCFBundleAlternateIcons, Android<activity-alias>), and embeds the schedule for on-launch resolution.- Runtime bridge functions apply a variant via
setAlternateIconName(iOS) /PackageManageralias toggling (Android).
Status & Roadmap
This is an early, structurally complete plugin. Build-time orchestration, the runtime bridge, config, and the GD pipeline are in place; some native write-back seams (Info.plist merge, AndroidManifest alias injection, exact build paths) are marked with TODO(on-device) and need verification against a real NativePHP build.
- MVP: per-platform icons + iOS appearances + Android adaptive/themed (no runtime jank).
- Phase 2: scheduled switching among bundled variants, with the constraints above clearly surfaced.
Contributions and ideas welcome.
Running tests
composer install
composer test
Credits
License
MIT.
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 2
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-06-12