skb1129 / react-native-change-icon

Change your application icon programmatically for React Native apps
MIT License
500 stars 92 forks source link

[Android] Changing the app icon will shut down the process. (v5.0.0) #106

Open Jongkeun opened 7 months ago

Jongkeun commented 7 months ago

Platform

Description This is such an obvious error. Changing the app icon on Android will shut down the process. I made a new project and tried it. But it was the same Please share the sample project repository that the app icon changes normally

To Reproduce Steps to reproduce the behavior:

  1. Install this library and follow the steps that is on How to Use
  2. call changeIcon on Android.

Expected behavior The app will not shut down and only the icon will change.

Screenshots Don't have to attach this.

Device (please complete the following information):

Versions

Code Snippet

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.appname">
  <uses-permission android:name="android.permission.INTERNET"/>
  <application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="false" android:theme="@style/AppTheme">
    <activity android:name=".MainActivity" android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:exported="true">
      <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
      </intent-filter>
      <intent-filter>
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
        <data android:scheme="appname"/>
      </intent-filter>
    </activity>

      <activity-alias
            android:name="MainActivityDefault"
            android:enabled="true"
            android:exported="true"
            android:icon="@mipmap/ic_launcher"
            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:name="MainActivityDark"
            android:enabled="false"
            android:exported="true"
            android:icon="@mipmap/ic_launcher"
            android:targetActivity=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity-alias>
  </application>
</manifest>
TierryBr commented 7 months ago

I also have the same problem, any solution?

psjostrom commented 6 months ago

Same here.

jacobmolby commented 6 months ago

It's the only way to change app icon for Android. For instance check out the duckduckgo app.

Best thing you can do is to warn the user about what is about to happen.

Jongkeun commented 6 months ago

It's the only way to change app icon for Android. For instance check out the duckduckgo app.

Best thing you can do is to warn the user about what is about to happen.

@jacobmolby , you can check this feature at Todoist. It looks like there are some workaround way. They are doing without closing.

jacobmolby commented 6 months ago

It's the only way to change app icon for Android. For instance check out the duckduckgo app. Best thing you can do is to warn the user about what is about to happen.

@jacobmolby , you can check this feature at Todoist. It looks like there are some workaround way. They are doing without closing.

Interesting. So I've tried. In their implementation, you have to restart the app "to enable icon switching" but after that it works without closing.

I found this repo trying to implement something similar, but I haven't tried it out. https://github.com/gonodono/app-icon-change-demo.

RahSolteo commented 6 months ago

Has anyone found a solution for this?

dylmye commented 6 months ago

The best way I found was to patch ChangeIconModule, after activity.finish(); in the changeIcon method, creating a new Intent:

Intent newIconIntent = Intent.makeMainActivity(new ComponentName(this.packageName, activeClass));
newIconIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.reactContext.startActivity(newIconIntent);

This will swiftly open the new activity after the old one ends. You'll also need to store the react context in the constructor:

public class ChangeIconModule extends ReactContextBaseJavaModule implements Application.ActivityLifecycleCallbacks {
    //[...]
    private ReactApplicationContext reactContext;
    //[...]
    public ChangeIconModule(ReactApplicationContext reactContext, String packageName) {
        //[...]
        this.reactContext = reactContext;
    }
}
berkaygurcan commented 4 months ago

continues... When we change the icon on Android, the application closes. Can you get your hands on it as soon as possible?

Navicna commented 2 months ago

Hey guys! I had this issue when I used version 5. I turned back to 4 and it worked fine!

maryaibtissem commented 2 months ago

Hello, Same here :-(

SHugzaurus commented 1 month ago

Hello, everyone. I applied a patch to the changeIcon method to remove the activity.finish() which was causing the app to close. Now changes only apply when you leave the app context though. I also removed the .MainActivityDefault shenanigans as it is causing double app launcher issues. React Native doesn't seem to like it when only aliases have the MAIN and LAUNCHER intents. So doing this allows to launch the Main Activity by default.

here is my modified version of the changeIcon method (i'm using patch package but as the repo seems stale maybe someone could take the maintenance back).

public void changeIcon(String iconName, Promise promise) {
        final Activity activity = getCurrentActivity();
        if (activity == null) {
            promise.reject("ANDROID:ACTIVITY_NOT_FOUND");
            return;
        }

        // Define MainActivity as default icon class 
        final String mainActivityClass = this.packageName + ".MainActivity";

        // handling bad icon names
        final String activeClass = (iconName == null || iconName.isEmpty())
                ? mainActivityClass
                : this.packageName + ".MainActivity" + iconName;

        // handling icon already in use
        if (this.componentClass.equals(activeClass)) {
            promise.reject("ANDROID:ICON_ALREADY_USED");
            return;
        }

        try {
            // activate new icon
            activity.getPackageManager().setComponentEnabledSetting(
                    new ComponentName(this.packageName, activeClass),
                    PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                    PackageManager.DONT_KILL_APP
            );
            promise.resolve(iconName);
        } catch (Exception e) {
            promise.reject("ANDROID:ICON_INVALID");
            return;
        }
    }
AkimMnsr commented 1 month ago

i've tried your solution @SHugzaurus but I've noticed that changing the icon now leads to the duplication of the app on the device. This seems to occur because the app creates a new instance whenever a new icon is activated without properly disabling the old one. As a result, both icons coexist, causing the duplication issue.

thinhtt264 commented 1 month ago

The best way I found was to patch ChangeIconModule, after activity.finish(); in the changeIcon method, creating a new Intent:

Intent newIconIntent = Intent.makeMainActivity(new ComponentName(this.packageName, activeClass));
newIconIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.reactContext.startActivity(newIconIntent);

This will swiftly open the new activity after the old one ends. You'll also need to store the react context in the constructor:

public class ChangeIconModule extends ReactContextBaseJavaModule implements Application.ActivityLifecycleCallbacks {
    //[...]
    private ReactApplicationContext reactContext;
    //[...]
    public ChangeIconModule(ReactApplicationContext reactContext, String packageName) {
        //[...]
        this.reactContext = reactContext;
    }
}

Hi, I tried it and it works pretty well, but I have another problem with createRef in React Native not being recreated when I change the app icon

caglardurmus commented 1 month ago

The best way I found was to patch ChangeIconModule, after activity.finish(); in the changeIcon method, creating a new Intent:

Intent newIconIntent = Intent.makeMainActivity(new ComponentName(this.packageName, activeClass));
newIconIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.reactContext.startActivity(newIconIntent);

This will swiftly open the new activity after the old one ends. You'll also need to store the react context in the constructor:

public class ChangeIconModule extends ReactContextBaseJavaModule implements Application.ActivityLifecycleCallbacks {
    //[...]
    private ReactApplicationContext reactContext;
    //[...]
    public ChangeIconModule(ReactApplicationContext reactContext, String packageName) {
        //[...]
        this.reactContext = reactContext;
    }
}

Hi, I tried it and it works pretty well, but I have another problem with createRef in React Native not being recreated when I change the app icon

Can you give the full file?