expo-alternate-app-icons

repository·main·Indexed 42 days ago

https://github.com/pchalupa/expo-alternate-app-icons

A library for Expo projects (SDK 51+) that allows developers to implement and switch between multiple app icons. It includes an Expo Config Plugin to automate the addition of alternative icons to native iOS and Android projects, supporting iOS appearance modes (light, dark, tinted) and Android adaptive icons. Key APIs include setAlternateAppIcon(), getAppIconName(), and resetAppIcon().

Tokens
4.5K
Snippets
22
Records
24
Agent score
52%

What's inside expo-alternate-app-icons

  1. Icon asset requirements

    main

    Alternative icons must follow the same format as your default app icon:

    • Format: .png
    • Dimensions: Square, 1024x1024 px resolution
    • iOS: Should not have a transparency layer.
    • Android (Adaptive Icon): Requires a foregroundImage and a backgroundColor for the background fill.
  2. Configure the Expo Config Plugin in app.json

    main

    The package uses an Expo Config Plugin to copy alternative icons to your native projects.

    1. Add expo-alternate-app-icons to the plugins array in your app.json.
    2. The plugin configuration is an array of icon objects.
    3. Run npx expo prebuild --clean to apply the changes to your native projects.

    Icon Naming: Icon names are automatically converted to PascalCase. For example, providing "icon-a" will result in the icon being identified as "IconA" in the API.

    // app.json
    {
      // ...
      plugins: [
        // ...
        [
          'expo-alternate-app-icons',
          [
            {
              name: 'IconA',
              ios: {
                light: './assets/icon-a.png',
                dark: './assets/icon-a-dark.png',
                tinted: './assets/icon-a-tinted.png',
              },
              android: {
                foregroundImage: './assets/icon-a-foreground.png',
                backgroundColor: '#001413',
              },
            },
            {
              name: 'IconB',
              ios: './assets/icon-b.png',
              android: {
                foregroundImage: './assets/icon-b-foreground.png',
                backgroundColor: '#001413',
              },
            },
          ],
        ],
      ],
    }
  3. Configure AlternateIcon objects

    main

    When providing detailed configuration for icons, use the AlternateIcon type. This allows you to explicitly map a name to a specific file path.

    If you provide an array of strings instead of AlternateIcon objects, the plugin will treat the strings as paths and automatically derive the icon names using PascalCase.

    // Using AlternateIcon objects
    const icons: AlternateIcon[] = [
      { name: 'HolidayTheme', path: './assets/holiday.png' }
    ];
    
    // Using string paths (names are derived via PascalCase)
    const iconPaths: string[] = ['./assets/holiday.png'];
  4. Configure iOS icon variants

    main

    When defining an AlternateIcon, the ios property can be configured as an iOSVariantsIcon object. This allows you to specify different icon images for the different iOS system appearance modes: light, dark, and tinted. The keys in the object must be one of these three strings, and the values must be the paths to the icon files.

    // Example of an iOSVariantsIcon configuration
    const iosIcons: iOSVariantsIcon = {
      light: './assets/icon-light.png',
      dark: './assets/icon-dark.png',
      tinted: './assets/icon-tinted.png'
    };
  5. Set the alternate app icon

    main

    Use setAlternateAppIcon(name) to switch the app icon. Pass the PascalCase name of the icon defined in your app.json. To reset the icon to the default app icon, pass null.

    // Set icon to IconA
    await setAlternateAppIcon("IconA");
    
    // Reset to default icon
    await setAlternateAppIcon(null);
  6. Configure Metro resolver blockList to prevent react-native conflicts

    main

    When using npm v7+ in a monorepo or a project where react-native might be installed in a parent directory, you may encounter incompatible versions of react-native being bundled. To prevent this, add a RegExp to config.resolver.blockList that targets the parent node_modules/react-native path. This ensures the bundler only uses the local version.

    config.resolver.blockList = [
      ...Array.from(config.resolver.blockList ?? []),
      new RegExp(path.resolve('..', 'node_modules', 'react-native')),
    ];
  7. Configure Metro nodeModulesPaths and watchFolders for monorepos

    main

    In monorepo setups, you may need to explicitly define where Metro looks for modules and which folders it should watch to ensure dependencies in parent directories are correctly resolved and tracked. Use config.resolver.nodeModulesPaths to include both local and parent node_modules directories, and config.watchFolders to include the parent directory.

    config.resolver.nodeModulesPaths = [
      path.resolve(__dirname, './node_modules'),
      path.resolve(__dirname, '../node_modules'),
    ];
    
    config.watchFolders = [path.resolve(__dirname, '..')];
  8. Configure expo-module.config.json for expo-alternate-app-icons

    main

    The expo-module.config.json file defines the native module mappings for the expo-alternate-app-icons library across different platforms. This configuration ensures that the Expo autolinking mechanism correctly identifies and links the native modules for iOS and Android.

    • iOS: Uses the ExpoAlternateAppIconsModule.
    • Android: Uses the expo.modules.alternateappicons.ExpoAlternateAppIconsModule.
    {
      "platforms": ["ios", "android"],
      "ios": {
        "modules": ["ExpoAlternateAppIconsModule"]
      },
      "android": {
        "modules": ["expo.modules.alternateappicons.ExpoAlternateAppIconsModule"]
      }
    }