npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-alternate-app-icon

v1.1.0

Published

High-performance React Native library to change app icon at runtime. Dynamic app icon changer for iOS and Android, built with Nitro Modules.

Readme

npm version Downloads GitHub stars License

React Native Alternate App Icon | App Icon Changer

react-native-alternate-app-icon is a high-performance App Icon Changer for React Native that allows you to dynamically change your app's icon at runtime on iOS and Android. Built with Nitro Modules, it provides a type-safe JavaScript API backed by native Swift and Kotlin implementations.

Use it as a dynamic app icon changer for seasonal themes, event-based branding, user personalization, or any scenario where you want to switch icons without shipping a new build.

📖 Full documentation — guides, API reference, and platform setup.

For AI agents (Cursor, Claude Code, Copilot, …)

Install the agent skill so coding agents follow correct iOS/Android setup and API usage:

npx skills add rutvik24/react-native-alternate-app-icon -g -y

Docs: For AI agents · Install skill (per-provider Add to Cursor and other agents)

Key Features

  • Alternate App Icon Management — Change your app icon at runtime on iOS and Android.
  • Cross-Platform API — Same JavaScript functions work on both platforms.
  • Nitro-Powered — Fast native bindings via react-native-nitro-modules.
  • New Architecture Ready — Works with React Native's New Architecture (Fabric & TurboModules).
  • Event-Based Switching — Change icons based on holidays, promotions, user preferences, and more.

Compatibility

| Requirement | Version | | --- | --- | | react-native-alternate-app-icon | 0.8.0+ (latest recommended) | | react-native-nitro-modules | 0.32.0 (peer dependency; pin this version) | | React Native | 0.76.0 or higher | | Node.js | 18.0.0 or higher |

Native bindings in this library are generated with Nitrogen 0.32.0 for the Nitro Modules 0.32.x Android/iOS APIs. Use a matching react-native-nitro-modules version in your app—mixing Nitro 0.35+ with a build targeting 0.32.x can cause native compile errors.

See the compatibility guide for details.

Installation

Install the package along with its peer dependency (pin Nitro to 0.32.0):

bun add react-native-alternate-app-icon [email protected]

For iOS, install CocoaPods dependencies:

bundle exec pod install --project-directory="ios"                                                                                                                                                                

iOS Setup

1. Directory Structure

Add your primary and alternative icons inside Images.xcassets:

Images.xcassets
├── AppIcon.appiconset
│   ├── Contents.json
│   └── ... (icon images)
└── AlternativeIcon.appiconset
    ├── Contents.json
    └── ... (icon images)

Each alternative icon needs its own .appiconset folder. The folder name (e.g. AlternativeIcon) is the name you pass to setIcon().

Tip: You can use Xcode's asset catalog to generate all required sizes, or provide a single 1024×1024 universal icon:

{
  "images": [
    {
      "filename": "alternate.png",
      "idiom": "universal",
      "platform": "ios",
      "size": "1024x1024"
    }
  ],
  "info": {
    "author": "xcode",
    "version": 1
  }
}

2. Update Info.plist

Add CFBundleIcons to define your primary and alternate icons:

<key>CFBundleIcons</key>
<dict>
  <key>CFBundlePrimaryIcon</key>
  <dict>
    <key>CFBundleIconFiles</key>
    <array>
      <string>AppIcon</string>
    </array>
  </dict>
  <key>CFBundleAlternateIcons</key>
  <dict>
    <key>AlternativeIcon</key>
    <dict>
      <key>CFBundleIconFiles</key>
      <array>
        <string>AlternativeIcon</string>
      </array>
    </dict>
  </dict>
</dict>
  • Primary icon: The key under CFBundleIconFiles must match your primary .appiconset name (e.g. AppIcon).
  • Alternative icons: Add one entry per alternate icon under CFBundleAlternateIcons. The key (e.g. AlternativeIcon) is the name passed to setIcon().

3. Configure Xcode

  1. Open your project in Xcode.
  2. Go to General → App Icons and Launch Screen.
  3. Set App Icon to your default icon set (e.g. AppIcon).
  4. Under App Icons Source, enable Include all app icon assets.

The Include all app icon assets checkbox bundles every icon set from your asset catalog so alternate icons are available at runtime.

Demo


Android Setup

Android uses activity-alias entries in AndroidManifest.xml. Each alias maps to a launcher icon and corresponds to an icon name used in JavaScript.

1. Add Icon Assets

Place launcher icons in your mipmap-* resource folders. Use consistent naming across all density folders:

app/src/main/res/
├── mipmap-mdpi/
│   ├── ic_launcher_alternate.png
│   └── ic_launcher_alternate_round.png
├── mipmap-hdpi/
│   ├── ic_launcher_alternate.png
│   └── ic_launcher_alternate_round.png
├── mipmap-xhdpi/
│   ├── ic_launcher_alternate.png
│   └── ic_launcher_alternate_round.png
├── mipmap-xxhdpi/
│   ├── ic_launcher_alternate.png
│   └── ic_launcher_alternate_round.png
├── mipmap-xxxhdpi/
│   ├── ic_launcher_alternate.png
│   └── ic_launcher_alternate_round.png
└── mipmap-anydpi-v26/
    ├── ic_launcher_alternate.xml
    └── ic_launcher_alternate_round.xml

Tip: Use Android Studio's Image Asset Studio (File → New → Image Asset) to generate all required sizes.

2. Configure AndroidManifest.xml

Add activity-alias entries for each icon variant. The suffix after MainActivity in the alias name becomes the icon name in JavaScript:

| Alias name | Icon name for setIcon() | | ------------------------------ | ------------------------- | | .MainActivityDefault | "Default" | | .MainActivityAlternativeIcon | "AlternativeIcon" |

<application
  android:name=".MainApplication"
  android:label="@string/app_name"
  android:icon="@mipmap/ic_launcher"
  android:roundIcon="@mipmap/ic_launcher_round"
  ...>

  <activity
    android:name=".MainActivity"
    android:label="@string/app_name"
    android:launchMode="singleTask"
    android:exported="true">
    <intent-filter>
      <action android:name="android.intent.action.MAIN" />
      <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
  </activity>

  <activity-alias
    android:name="${applicationId}.MainActivityDefault"
    android:targetActivity=".MainActivity"
    android:icon="@mipmap/ic_launcher"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:label="@string/app_name"
    android:enabled="false"
    android:exported="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="${applicationId}.MainActivityAlternativeIcon"
    android:targetActivity=".MainActivity"
    android:icon="@mipmap/ic_launcher_alternate"
    android:roundIcon="@mipmap/ic_launcher_alternate_round"
    android:label="@string/app_name"
    android:enabled="false"
    android:exported="true">
    <intent-filter>
      <action android:name="android.intent.action.MAIN" />
      <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
  </activity-alias>

</application>

Note: On Android, icon changes are applied when the app moves to the background. The library handles this automatically and defers the switch if OAuth or other overlay activities are active.

ProGuard / R8 (release builds)

The library ships consumer ProGuard rules in its AAR (android/consumer-rules.pro). When you enable minifyEnabled true for release, those rules merge automatically — you do not need to copy Nitro keep rules into your app.

Use proguard-android-optimize.txt and avoid redundant -keep rules for Activity or activity-alias (manifest components are kept by R8).

Full guide: ProGuard / R8

Demo


Usage

Import the functions you need:

import {
  getActiveIcon,
  setIcon,
  getAllAlternativeIcons,
  resetIcon,
} from 'react-native-alternate-app-icon'

You can also access the underlying Nitro hybrid object directly:

import { AlternateAppIcon } from 'react-native-alternate-app-icon'

setIcon(iconName: string): Promise<string>

Sets the app icon to the specified name. Pass "Default" to revert to the primary icon.

await setIcon('AlternativeIcon')
// => "Icon changed to AlternativeIcon" (iOS)
// => "Your icon will change to AlternativeIcon" (Android — applied on background)

await setIcon('Default')

getActiveIcon(): Promise<string>

Returns the name of the currently active icon. Returns "Default" when the primary icon is active.

const activeIcon = await getActiveIcon()
console.log('Current active icon:', activeIcon)

getAllAlternativeIcons(): Promise<string[]>

Returns all available icon names configured in your project.

const icons = await getAllAlternativeIcons()
console.log('Available icons:', icons)
// => ["Default", "AlternativeIcon"]

resetIcon(): Promise<string>

Resets the app icon to the primary/default icon.

const message = await resetIcon()
console.log(message)
// => "Icon reset to default."

Full Example

import React, { useEffect, useState } from 'react'
import { Button, Text, View } from 'react-native'
import {
  getActiveIcon,
  getAllAlternativeIcons,
  resetIcon,
  setIcon,
} from 'react-native-alternate-app-icon'

export default function App() {
  const [activeIcon, setActiveIcon] = useState('')
  const [icons, setIcons] = useState([])

  useEffect(() => {
    ;(async () => {
      setActiveIcon(await getActiveIcon())
      setIcons(await getAllAlternativeIcons())
    })()
  }, [])

  return (
    <View>
      <Text>Active icon: {activeIcon}</Text>
      {icons.map((icon) => (
        <Button
          key={icon}
          title={`Set ${icon}`}
          onPress={() => setIcon(icon)}
        />
      ))}
      <Button title="Reset icon" onPress={resetIcon} />
    </View>
  )
}

See the example app for a complete working project.


Platform Notes

iOS

  • Alternate icons require a physical device or simulator running iOS 10.3+.
  • iOS shows a system alert when the icon changes — this is expected behavior.
  • The icon name must match a key in CFBundleAlternateIcons, or use "Default" for the primary icon.

Android

  • Icon names are derived from activity-alias names: everything after MainActivity in the alias class name.
  • The icon switch is deferred until the app is backgrounded for a smoother UX.
  • The library automatically waits if sign-in, OAuth, or other overlay activities are in the foreground.

Contributing

Contributions are welcome! Please read:

For major changes, open an issue first so we can discuss the approach.

License

MIT