Skip to content

Repository files navigation

Tauri Plugin App Icon

Runtime selection of bundled alternate launcher icons for Tauri 2 iOS and Android apps.

Install

[dependencies]
tauri-plugin-app-icon = "0.1"
pnpm add tauri-plugin-app-icon-api
tauri::Builder::default()
  .plugin(tauri_plugin_app_icon::init())

All plugin commands are blocked until a capability grants them, so add the default permission set to src-tauri/capabilities/default.json. app-icon:default allows all three commands; permissions/autogenerated/reference.md lists the individual allow-* and deny-* identifiers.

{
  "permissions": ["app-icon:default"]
}
import { availableIcons, currentIcon, setIcon } from 'tauri-plugin-app-icon-api'

const icons = await availableIcons()
await setIcon(icons[0])
await setIcon(null) // Restore the primary icon.
console.log(await currentIcon())

The plugin switches only icons already compiled into the application. It does not accept image files or remote URLs. iOS does not permit changing to an arbitrary runtime image.

iOS setup

Create an asset catalog icon set for every alternative and register each set under CFBundleIcons > CFBundleAlternateIcons in the app's Info.plist. The dictionary key is the ID exposed by availableIcons and accepted by setIcon.

<key>CFBundleIcons</key>
<dict>
  <key>CFBundleAlternateIcons</key>
  <dict>
    <key>midnight</key>
    <dict>
      <key>CFBundleIconFiles</key>
      <array>
        <string>AppIconMidnight</string>
      </array>
    </dict>
  </dict>
</dict>

Use Xcode's Alternate App Icon Sets build setting when possible so it generates this entry. iOS icon files must be opaque and include all required device sizes.

Android setup

Android has no runtime icon API. Each icon is an activity-alias carrying a tauri-plugin-app-icon-id metadata value; the plugin enables the selected alias and disables every other one. The aliases own the launcher entries, so the target activity must not declare a launcher intent filter itself, otherwise the launcher shows both the activity and the enabled alias. The alias marked with tauri-plugin-app-icon-default metadata is the primary icon restored by setIcon(null), and is excluded from availableIcons.

Generation

The included generator turns source PNGs into Android density resources and maintains a marked alias block in the generated manifest. The host app owns the configuration because it owns its Android activity and native project:

{
  "android": {
    "mainActivity": ".MainActivity",
    "resourcesDirectory": "gen/android/app/src/main/res",
    "manifest": "gen/android/app/src/main/AndroidManifest.xml"
  },
  "ios": {
    "assetsDirectory": "icons/ios/AppIcons.xcassets",
    "infoPlist": "Info.plist"
  },
  "icons": [{ "id": "midnight", "source": "icons/app-icons/midnight.png" }]
}

All paths are relative to the configuration file. The resources must reach a directory the Android app compiles: write straight into the generated app's res directory, as above, or into a directory you copy or link into it. Icon IDs must match ^[a-z][a-z0-9_]*$; default is reserved for the primary icon.

Run it from the host application so the Tauri CLI resolves from that app:

node node_modules/tauri-plugin-app-icon-api/scripts/generate-android.mjs --config src-tauri/app-icons.json

The generator writes one adaptive icon plus its background colour per ID, rewrites the marked alias block, and removes the launcher intent filter from android.mainActivity. Re-running it is idempotent. It calls tauri icon through the package manager that invoked it, defaulting to pnpm. The source images must be square PNGs. Run generation before an Android build whenever the configuration, the source images, or the generated Android project change.

For iOS, run generate-ios.mjs with the same configuration. It creates alternate app-icon sets in the configured asset catalog and maintains CFBundleAlternateIcons in the configured Info.plist.

Declaring aliases by hand

Skip the generator by declaring the aliases yourself. Every alias needs a unique tauri-plugin-app-icon-id, an icon resource, and a launcher intent filter; exactly one alias is enabled and marked as the default:

<activity
    android:name="com.example.app.MainActivity"
    android:exported="true" />

<activity-alias
    android:name=".AppIconDefault"
    android:targetActivity=".MainActivity"
    android:icon="@mipmap/ic_launcher"
    android:enabled="true"
    android:exported="true">
    <meta-data
        android:name="tauri-plugin-app-icon-id"
        android:value="default" />
    <meta-data
        android:name="tauri-plugin-app-icon-default"
        android:value="true" />
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity-alias>

<activity-alias
    android:name=".AppIconMidnight"
    android:targetActivity=".MainActivity"
    android:icon="@mipmap/ic_launcher_midnight"
    android:enabled="false"
    android:exported="true">
    <meta-data
        android:name="tauri-plugin-app-icon-id"
        android:value="midnight" />
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity-alias>

Provide a complete Android adaptive icon resource set for each ID, and reference only resources that exist in the app; an alias pointing at a missing drawable fails the Android build.

Platform support

The API is supported on iOS and Android. Calls on desktop return an unsupported-platform error.

Validation

Run the cross-platform checks from the plugin root:

pnpm test
pnpm build
cargo test
cargo check

Native launcher changes require platform validation before release:

# Android, from the host Tauri app's generated project.
./gradlew :tauri-plugin-app-icon:testDebugUnitTest

# iOS, on macOS after Tauri has generated the iOS project.
pnpm tauri ios dev

On each platform, install the app, select every alternate icon, restore the primary icon, restart the launcher, and confirm exactly one launcher entry remains. Android builds also require the NDK version configured by the host app.

License

MIT or Apache-2.0, at your option.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages