In the pit of

Here I write some problems encountered in this function in the front, in order that you can first understand what problems exist, when these problems do not panic, here I use icon to explain the application icon and name.

1. Dynamic replacement of icon, which can only replace the built-in icon and cannot be obtained from the server to update icon;

2, dynamic replacement after icon, within the application update when have to switch to the original icon), otherwise may cause the failure of update installation running on (AS characterized by the adb will fail), or after upgrade application ICONS appear multiple application ICONS are even not show (all these problems can be solved through here I recommend the development of rules, So this is a pothole, not a guaranteed problem, but one that most people will encounter.) ;

3. There will be a delay in the dynamic replacement of app Icon in Android system. The time for refreshing the icon on different mobile phone systems is different, about 10 seconds, within this time, clicking the icon will prompt that the app is not installed (the prompt may be different.

4. After the code of replacing the icon is run, the application will flash back, or the Dialog and PopupWindow in the display will crash due to error (this problem is very related to the second problem and can be solved according to the rules I give below.

update: 2019/02/25

5. After using the function of modifying the app icon on android9.0, our app is not displayed in the recent taskbar. A solution to this problem will be provided in the final development rules.

Multiple entry configuration

Androidmanifest.xml has a tag called activity-alias. This tag is an alias for an activity.

Activity-alias example:

        <activity-alias
            android:name="NewActivity1"// Register the name of this component without generating a file Android :enabled="false"// Whether to display the launcher android:label="Alias1"// The name of the app that corresponds to the launcher displayed on the desktop android:icon="@mipmap/ic_launcher_round"// The app icon that corresponds to the launcher displayed on the desktop android:targetActivity=".MainActivity"// Corresponds to the original Activity component, where the path corresponds to the registered Activity. > <intent-filter> // LAUNCHER <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity-alias>
Copy the code

Display multiple startup portals

Then, I will first make an app example with multiple startup entries all displayed. The code to be written here is in the listing file, and the code is as follows:

<? xml version="1.0" encoding="utf-8"? > <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.wepon.switchicondemo">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher_round"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"> <! -- Activity--> < Activity android:enabled="true"
            android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <! -- alias 1--> <activity-alias Android :name="NewActivity1"
            android:enabled="true"
            android:label="Alias1"
            android:icon="@mipmap/ic_launcher_round"
            android:targetActivity=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity-alias> <! -- alias 2--> <activity-alias Android :name="NewActivity2"
            android:enabled="true"
            android:label="Alias2"
            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>
Copy the code

After running, the effect is as follows:

Of course, in the actual project we will only display one icon. Here we just need to change the Android: Enabled =”true” for “alias 1″ and” alias 2″ to “false”, so that only one icon will be displayed without rendering.

Code control toggles the display of different application ICONS

The Spring Festival is coming soon. When it comes to our products, our application ICONS will be changed to those used in the Spring Festival. Of course, as mentioned above, these ICONS should be written in the application first, not dynamically taken from the server, but already written in the application. At this time we need to use the code to dynamically switch the application icon, here I give the layout of the Demo as shown:

Click on the three buttons to switch to the corresponding app icon and name. “Original ACTIVITY” indicates only the original startup entry of MainActivity, “ALIAS_1” indicates alias 1, and so on.

The three button clicks correspond to the following code:

/** * Set the Activity to the start entry * @param view */ public voidsetActivity(View view) {
        PackageManager packageManager = getPackageManager();
        packageManager.setComponentEnabledSetting(new ComponentName(this, getPackageName() +
                ".NewActivity1"), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager
                .DONT_KILL_APP);
        packageManager.setComponentEnabledSetting(new ComponentName(this, getPackageName() +
                ".NewActivity2"), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager
                .DONT_KILL_APP);
        packageManager.setComponentEnabledSetting(new ComponentName(this, getPackageName() +
                ".MainActivity"), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager .DONT_KILL_APP); } /** * set alias 1 to boot entry * @param view */ public voidsetAlias1(View view) {
        PackageManager packageManager = getPackageManager();
        packageManager.setComponentEnabledSetting(new ComponentName(this, getPackageName() +
                        ".NewActivity1"), PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                PackageManager.DONT_KILL_APP);
        packageManager.setComponentEnabledSetting(new ComponentName(this, getPackageName() +
                ".NewActivity2"), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager
                .DONT_KILL_APP);
        packageManager.setComponentEnabledSetting(new ComponentName(this, getPackageName() +
                ".MainActivity"), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager .DONT_KILL_APP); } /** * set alias 2 to boot entry * @param view */ public voidsetAlias2(View view) {
        PackageManager packageManager = getPackageManager();
        packageManager.setComponentEnabledSetting(new ComponentName(this, getPackageName() +
                        ".NewActivity1"), PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                PackageManager.DONT_KILL_APP);
        packageManager.setComponentEnabledSetting(new ComponentName(this, getPackageName() +
                ".NewActivity2"), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager
                .DONT_KILL_APP);
        packageManager.setComponentEnabledSetting(new ComponentName(this, getPackageName() +
                ".MainActivity"), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager
                .DONT_KILL_APP);
    }
    
Copy the code

!!!!!!!!! Here to note a point, is ComponentName inside the path must write all, if the error log to see similar to find the path of the log, then nine out of ten is the problem.

The code for switching is actually very small, you see basically also understand, here will not do too much explanation. In this case, I hid all the aliases, that is, only one of the original APP ICONS. By clicking “ALIAS_1”, I switched the icon to “Alias 1”. The result is as follows:

You can see that this is the only entry, but if you click on “ALIAS_1” and immediately go back to the home page and look at the app icon, you’ll see that it doesn’t change for about 10 seconds, and then it changes to the one that we switched to, and then, If we click on the original icon when it is not successfully updated, we will receive a message like “not installed” (Huawei is not installed). Here, my xiaomi does not respond when I click on it, so I can only click on this icon to enter the application after about 10s of seconds when the update is successful. So, through the code we have “already done” icon toggle, but!!

Is that the end of it? Obviously not. There are a lot of questions. Let me run them through.

I don’t know if you have stopped in the APP after clicking the switch button. If not, we will try not to return to the desktop in the app after clicking the switch button. If we stop in the app, the app will flash back after about 10 seconds, that is, when the update is successful, which is the problem of pit 4. I have done a lot of tests on this problem and summarized the reasons and ways to avoid it. The reason is that we set the enable of our original real MainActiviy to false in the code, and the code is as follows:

        packageManager.setComponentEnabledSetting(new ComponentName(this, getPackageName() +
                ".MainActivity"), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager
                .DONT_KILL_APP);
Copy the code

As long as the code sets the enable of the actual Activity to false, that is, the corresponding packagemanager.ponENT_enabled_state_disabled, this will cause our application to flash back. How do we hide the real MainActivity icon without setting this? I’ll come up with the solution later.

But, you think that’s the only problem? There are pits, just the pit is not easy to find, we return to our current situation, this time also is we have to switch to the current “alias” 1, only the ICONS on the desktop, we can also click on the icon to use our normal application, none of this problem, we think that is normal. However, if we run the project through ADB and Android Studio, we will be prompted to launch the app. The failure message is as follows:


01/10 16:48:54: Launching app
$ adb shell am start -n "com.wepon.switchicondemo/com.wepon.switchicondemo.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Error while executing: am start -n "com.wepon.switchicondemo/com.wepon.switchicondemo.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.wepon.switchicondemo/.MainActivity }
Error type 3
Error: Activity class {com.wepon.switchicondemo/com.wepon.switchicondemo.MainActivity} does not exist.

Error while Launching activity

Copy the code

Another problem is that after our code dynamically switches the APP icon, the application upgrade, that is, when the application is updated, will lead to installation failure, or there will be multiple ICONS or even no ICONS on the desktop after the installation is completed!! These problems are only discovered when running or upgrading packages, but then they are discovered too late, so this is a relatively large pit, which corresponds to the pit 2 point I mentioned earlier.

For example, our Demo now has one MainActivity and two aliases. If we remove these aliases in the next version, or if we remove the aliases that our current installation package is displaying, the new version of the installation may not show the application icon. That would result in a successful application installation, but no entry!

And some similar problems, mainly in the application after the upgrade, after installed and whether it leads to failure, no icon or produce multiple ICONS after installation, these phenomena are very serious, but we all these problems can be avoided, here I summarized some rules and operation according to these rules is not for these problems, of course, If you have any other questions, please feel free to contact us, because our app is also doing this function.

Dynamically modify the icon development rules, pit prevention special

1. For the Android: Enabled attribute of the Activity, do not set the value of Enabled in the code, otherwise the application will blink out during the icon switching process. Currently, xiaomi, Huawei and official emulators have tested this problem.

In the listing file, set the Activity’s Android: Enabled =”false “. This value will be fixed in future versions. If this value is set to true, multiple ICONS may appear after the app is upgraded.

3. Then set a default activity-alias for our app to display ICONS (which is also the only one to display, usually we only need to display one icon). Android: Enabled =”false “may cause no application icon on the desktop.

4, Activity-alias android:enabled=”true” default display items as far as possible do not change, if you do need to use a new default value, use code to dynamically change;

5, Activity-alias android:enabled=”true” should not be set to multiple, otherwise there will be multiple ICONS, if you try to hide one or more of them by code, may appear the icon disappeared, this second point has been mentioned;

6, if you want to add a new activity-alias in the later version, then set android:enabled= “false”, this listing file value should be set to false, and then dynamically change through the code;

7, the later version of the activity-alias must contain all the previous version of the activity-alias, mainly to prevent overwriting the application icon after the installation of the situation;

Update: January 14, 2019 5:09 PM New Found Issues needing attention ————–

An Activity whose enabled is set to false cannot be started with an explicit intent, and an error is reported. Such as: If the SplashActivity is set to False, it cannot be started. The error log is as follows: The same goes for other things. (So IN the project I wrote the Activity for the launch entry separately, so there is no other place to use the Activity except for the launch entry.) :

Update: February 25, 2019 New found Issues needing attention ————–

9. This problem is about the 5th point from the beginning. In the 9.0 OS, our application is no longer displayed in the taskbar. We can start our application by setting up the splash screen activity. It is also ok to set our home page activity to SingleInstance startup mode. The key is to see your project needs. If you set it differently, the page displayed in the application will be different if you return to it from the background. The key here is that the activity whose Enabled is set to false should not be in the same activity stack as the other activities.

Above is what I am doing this function in the process of summarizing the rules, not found in other problems at present, there are other problems friend welcome comments, and, in accordance with these rules, cover installed application icon will be the last time you dynamically through code modify the icon of success, because the mobile Launcher there will be a record, So we’re going to modify this record in the Launcher through our code.

By the way, the icon and label information of the Activity and activity-alias configured in the manifest file can be changed in the new version, which has nothing to do with the code, that is, it is the same operation that we usually change the name of the app icon. .

The last

Finally, some of you might want to think, “My current application entry is a default Activity. The default enable is true, and THERE is no activity-alias configured.” The android: Enabled =”false “rule for the Activity in the manifest file. If the new version is set to false, the icon entry will be missing. So let me tell you, if you set up your new version (dynamically toggle the icon version) according to the rules I mentioned above, this will not happen. Here is an example of a version manifest file that can be upgraded for this situation:

<? xml version="1.0" encoding="utf-8"? > <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.wepon.switchicondemo">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher_round"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"> <! -- The original Activity Enabled is fixed tofalse--> <activity Android :enabled="false"
            android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <! -- Set a default alias to replace the original Activity--> <activity-alias Android :name="DefaultAlias"
            android:enabled="true"
            android:label="@string/app_name"
            android:icon="@mipmap/ic_launcher_round"
            android:targetActivity=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity-alias> <! -- alias 1 Spring Festival, double 11, double 12,51, National Day, etc., can all be configured with an alias in the manifest file, here I only use one example. --> <activity-alias android:name="NewActivity1"
            android:enabled="false"
            android:label="Alias1"
            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>
Copy the code

Simple Demo

Here is a simple demo for your reference only

Github.com/ywp0919/Swi…