I looked up on the internet and found some packages like this which doesn't support React Native Android and this which not well documented...
Are there any other modules for React Native Android for that? Or is there any way i can program app to change the icon dynamically.
For example, when dark theme for system, icon changes to dark theme. Or like a calendar icon changes showing current date on icon. Or clock showing hands movement as seconds goes by, etc.
There are few steps to enable dynamic icon change on Android. Seems a lot of work, but actually very easy.
1. Put all your icons on mipmap
folder.
2. AndroidManifest.xml
(Create activity alias for each icon)
Under <application>
, Main <activity>
should not contain intent-filter
& android:exported
should be set to true
. this will make MainActivity
available always without showing shortcut icon.
<activity
android:name=".MainActivity"
android:label="Test App"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize"
android:exported="true"
>
</activity>
3. Now, for each icon you want to display, create <activity-alias>
. Set android:enabled
to true
for your defailt icon. All enabled icons will be displayed on desktop. So make sure you enable only one activity alias.
<activity-alias
android:label="Test App :: Default"
android:icon="@mipmap/icon1"
android:name="First"
android:enabled="true"
android:targetActivity=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:label="Test App :: Special"
android:icon="@mipmap/icon2"
android:name="Second"
android:enabled="false"
android:targetActivity=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:label="Test App :: Very Special"
android:icon="@mipmap/icon3"
android:name="Third"
android:enabled="false"
android:targetActivity=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
4. Create a Java Classes
Create empty class for each of your activity alias.
package com.your.package;
class First {
}
5. Create IconChanger class
@ReactMethod
allows accessing it from react-native. You can change com.your.package
to BuildConfig.APPLICATION_ID
to avoid writing your package name multiple times.
package your.package.name;
import android.os.Bundle;
import com.facebook.react.ReactActivity;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import java.util.Map;
import java.util.HashMap;
import android.content.pm.PackageManager;
import android.content.ComponentName;
import com.facebook.react.bridge.Promise;
import android.os.Bundle;
import android.widget.Toast;
public class IconChanger extends ReactContextBaseJavaModule {
private final ReactApplicationContext reactContext;
public IconChanger(ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext = reactContext;
}
@Override
public String getName() {
return "IconChanger";
}
@ReactMethod
public void changeIcon(String enableIntent, String disableIntent, Promise response) {
try {
PackageManager packageManager = this.reactContext.getPackageManager();
int action;
String activeIntent="com.your.package."+enableIntent;
Toast.makeText( this.reactContext,"Enabling "+enableIntent,Toast.LENGTH_SHORT).show();
packageManager.setComponentEnabledSetting(
new ComponentName("com.your.package", activeIntent),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP
);
if(!disableIntent.equals(null) && !disableIntent.equals(enableIntent)){
activeIntent="com.your.package.."+disableIntent;
Toast.makeText( this.reactContext,"Disabling "+disableIntent,Toast.LENGTH_SHORT).show();
packageManager.setComponentEnabledSetting(
new ComponentName("com.your.package.", activeIntent),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP
);
}
response.resolve(enableIntent);
} catch (Exception e) {
response.reject("Error", e);
}
}
}
6. Register it as NativeModule
Create CustomPackages.java
package com.your.package;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CustomPackages implements ReactPackage {
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
@Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new IconChanger(reactContext));
return modules;
}
}
7. Now add this package to your MainApplication.java
@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
packages.add(new CustomPackages());
return packages;
}
8. Access IconChanger
from react-native
import { NativeModules } from 'react-native';
const { IconChanger } = NativeModules;
IconChanger.changeIcon(newIcon, oldIcon);
[NOTES]
This will enable new activity & then close old activity.
Change icon on app close or in background, as changing activity closes the app.