如何在Android中以编程方式更改应用程序图标?

时间:2009-07-09 10:14:26

标签: android

是否可以直接从程序中更改应用程序图标?
我的意思是,更改icon.png文件夹中的res\drawable 我想让用户从程序中更改应用程序的图标,以便下次他们在启动器中看到之前选择的图标。

11 个答案:

答案 0 :(得分:116)

试试这个,它适用于我:

1。修改MainActivity中的AndroidManifest.xml部分,从中删除,与MAIN部分中的intent-filter类别对齐

<activity android:name="ru.quickmessage.pa.MainActivity"
    android:configChanges="keyboardHidden|orientation"
    android:screenOrientation="portrait"
    android:label="@string/app_name"
    android:theme="@style/CustomTheme"
    android:launchMode="singleTask">
    <intent-filter>
        ==> <action android:name="android.intent.action.MAIN" /> <== Delete this line
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

2。为每个图标创建<activity-alias>。喜欢这个

<activity-alias android:label="@string/app_name" 
    android:icon="@drawable/icon" 
    android:name=".MainActivity-Red"
    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>

3。以编程方式设置:为相应的activity-alias

设置ENABLE属性
 getPackageManager().setComponentEnabledSetting(
        new ComponentName("ru.quickmessage.pa", "ru.quickmessage.pa.MainActivity-Red"), 
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);

注意,必须始终至少启用一个。

答案 1 :(得分:68)

这是一个老问题,但仍然有效,因为没有明确的Android功能。来自facebook的人找到了一个解决方法 - 不知何故。今天,我发现了一种适合我的方式。不完美(请参阅本答案末尾的评论),但它确实有效!

主要的想法是,我更新了我的主屏幕上的启动器创建的应用程序快捷方式的图标。当我想在快捷方式图标上更改某些内容时,我先删除它并使用新的位图重新创建它。

这是代码。它有一个按钮increment。按下时,快捷方式将替换为具有新计数编号的快捷方式。

首先,您需要在清单中使用这两个权限:

<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" />

然后,您需要这两种方法来安装和卸载快捷方式。 shortcutAdd方法创建一个带有数字的位图。这只是为了证明它实际上发生了变化。您可能希望在应用中使用某些内容更改该部分。

private void shortcutAdd(String name, int number) {
    // Intent to be send, when shortcut is pressed by user ("launched")
    Intent shortcutIntent = new Intent(getApplicationContext(), Play.class);
    shortcutIntent.setAction(Constants.ACTION_PLAY);

    // Create bitmap with number in it -> very default. You probably want to give it a more stylish look
    Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
    Paint paint = new Paint();
    paint.setColor(0xFF808080); // gray
    paint.setTextAlign(Paint.Align.CENTER);
    paint.setTextSize(50);
    new Canvas(bitmap).drawText(""+number, 50, 50, paint);
    ((ImageView) findViewById(R.id.icon)).setImageBitmap(bitmap);

    // Decorate the shortcut
    Intent addIntent = new Intent();
    addIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
    addIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name);
    addIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON, bitmap);

    // Inform launcher to create shortcut
    addIntent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
    getApplicationContext().sendBroadcast(addIntent);
}

private void shortcutDel(String name) {
    // Intent to be send, when shortcut is pressed by user ("launched")
    Intent shortcutIntent = new Intent(getApplicationContext(), Play.class);
    shortcutIntent.setAction(Constants.ACTION_PLAY);

    // Decorate the shortcut
    Intent delIntent = new Intent();
    delIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
    delIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name);

    // Inform launcher to remove shortcut
    delIntent.setAction("com.android.launcher.action.UNINSTALL_SHORTCUT");
    getApplicationContext().sendBroadcast(delIntent);
}

最后,这里有两个监听器添加第一个快捷方式并使用递增计数器更新快捷方式。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.test);
    findViewById(R.id.add).setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            shortcutAdd("changeIt!", count);
        }
    });
    findViewById(R.id.increment).setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            shortcutDel("changeIt!");
            count++;
            shortcutAdd("changeIt!", count);
        }
    });
}

说明:

  • 如果您的应用控制主屏幕上的更多快捷方式,例如Intent中有不同的额外内容。他们只需要不同的名称,以便卸载并重新安装正确的名称。

  • Android中快捷方式的程序化处理是众所周知的,广泛使用但未经官方支持的Android功能。它似乎适用于默认启动器,我从未尝试过其他任何地方。所以不要怪我,当你收到这个用户的电子邮件“它不适用于我的XYZ,双根,超级爆破手机”

  • 启动快捷方式时,启动程序会写Toast,而卸载快捷方式时会启动快捷方式。每次我更改图标时,我都会得到两个Toast个。这不是完美的,但是,只要我的应用程序的其余部分是完美的......

答案 2 :(得分:35)

除非通过软件升级,否则您无法更改已签名并密封的APK中的清单或资源。

答案 3 :(得分:16)

以编程方式,您可能希望自己发布应用程序启动器:

注意:此方法不再适用于Android 8.0 - Oreo

在AndroidManifest.xml中,添加:

<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>

然后你需要创建你的应用启动器意图:

Intent myLauncherIntent = new Intent();
myLauncherIntent.setClassName("your.package.name", "YourLauncherActivityName");
myLauncherIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

使用您的应用启动器和自定义图标创建安装快捷方式:

Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, myLauncherIntent);
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "Application Name");
intent.putExtra
       (
        Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
        Intent.ShortcutIconResource.fromContext
                                    (
                                         getApplicationContext(), 
                                         R.drawable.app_icon
                                    )
       );
intent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");

最后发布广播意图:

getApplicationContext().sendBroadcast(intent);

答案 4 :(得分:9)

假设您的意思是更改主屏幕上显示的图标,可以通过创建完全相同的小部件轻松完成。这篇文章演示了如何为类似于iPhone的“新消息”类型应用程序实现这一点:

http://www.cnet.com/8301-19736_1-10278814-251.html

答案 5 :(得分:7)

@ P-A的解决方案部分适用于我。详细说明我的发现如下:

1)第一个代码段不正确,见下文:

<activity
    ...
    <intent-filter>
        ==> <action android:name="android.intent.action.MAIN" /> <== This line shouldn't be deleted, otherwise will have compile error
        <category android:name="android.intent.category.LAUNCHER" /> //DELETE THIS LINE
    </intent-filter>
</activity>

2)在启用另一个图标之前,应使用以下代码禁用所有图标,否则它将添加一个新图标,而不是替换它。

getPackageManager().setComponentEnabledSetting(
        getComponentName(), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);

但是,如果您使用上面的代码,那么主屏幕上的快捷方式将被删除!并且它不会被自动添加回来。您可以以编程方式添加图标,但它可能不会保持与以前相同的位置。

3)请注意,图标不会立即更改,可能需要几秒钟。如果您在更改后立即单击它,则可能会收到错误消息:&#34;应用程序未安装&#34;。

所以,恕我直言这个解决方案只适用于改变应用程序启动器中的图标,而不适用于快捷方式(即主屏幕上的图标)

答案 6 :(得分:5)

AndroidManifest.xml示例:

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

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

        <activity-alias android:label="RED"
                        android:icon="@drawable/ic_android_red"
                        android:name="com.pritesh.resourceidentifierexample.MainActivity-Red"
                        android:enabled="true"
                        android:targetActivity="com.pritesh.resourceidentifierexample.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity-alias>

        <activity-alias android:label="GREEN"
                        android:icon="@drawable/ic_android_green"
                        android:name="com.pritesh.resourceidentifierexample.MainActivity-Green"
                        android:enabled="false"
                        android:targetActivity="com.pritesh.resourceidentifierexample.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity-alias>

        <activity-alias android:label="BLUE"
                        android:icon="@drawable/ic_android_blue"
                        android:name="com.pritesh.resourceidentifierexample.MainActivity-Blue"
                        android:enabled="false"
                        android:targetActivity="com.pritesh.resourceidentifierexample.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity-alias>

    </application>

然后按照MainActivity中的以下代码进行操作:

ImageView imageView = (ImageView)findViewById(R.id.imageView);
            int imageResourceId;
            String currentDateTimeString = DateFormat.getDateTimeInstance().format(new Date());
            int hours = new Time(System.currentTimeMillis()).getHours();
            Log.d("DATE", "onCreate: "  + hours);

            getPackageManager().setComponentEnabledSetting(
                    getComponentName(), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);

            if(hours == 13)
            {
                imageResourceId = this.getResources().getIdentifier("ic_android_red", "drawable", this.getPackageName());
                getPackageManager().setComponentEnabledSetting(
                        new ComponentName("com.pritesh.resourceidentifierexample", "com.pritesh.resourceidentifierexample.MainActivity-Red"),
                        PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
            }else if(hours == 14)
            {
                imageResourceId = this.getResources().getIdentifier("ic_android_green", "drawable", this.getPackageName());
                getPackageManager().setComponentEnabledSetting(
                        new ComponentName("com.pritesh.resourceidentifierexample", "com.pritesh.resourceidentifierexample.MainActivity-Green"),
                        PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);

            }else
            {
                imageResourceId = this.getResources().getIdentifier("ic_android_blue", "drawable", this.getPackageName());
                getPackageManager().setComponentEnabledSetting(
                        new ComponentName("com.pritesh.resourceidentifierexample", "com.pritesh.resourceidentifierexample.MainActivity-Blue"),
                        PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);

            }

            imageView.setImageResource(imageResourceId);

答案 7 :(得分:3)

尝试此解决方案

<activity android:name=".SplashActivity"
        android:label="@string/app_name"
        android:icon="@drawable/ic_launcher">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <activity-alias android:label="ShortCut"
        android:icon="@drawable/ic_short_cut"
        android:name=".SplashActivityAlias"
        android:enabled="false"
        android:targetActivity=".SplashActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity-alias>

要更改应用程序图标时,添加以下代码

PackageManager pm = getPackageManager();
                    pm.setComponentEnabledSetting(
                            new ComponentName(YourActivity.this,
                                    "your_package_name.SplashActivity"),
                            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                            PackageManager.DONT_KILL_APP);

                    pm.setComponentEnabledSetting(
                            new ComponentName(YourActivity.this,
                                    "your_package_name.SplashActivityAlias"),
                            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                            PackageManager.DONT_KILL_APP);

答案 8 :(得分:2)

如前所述,您需要使用 For RowCount = 1 To Range("A1:E57").EntireRow.Select 来更改应用程序图标。 为避免在启用适当的活动别名后终止应用程序,您需要在应用程序终止后执行此操作。要了解应用程序是否已被终止,您可以使用 this method

  1. 在 AndroidManifest.xml 中创建活动别名
<activity-alias>
  1. 创建一个服务,该服务将在终止应用程序后更改活动活动别名。您需要在某处存储新的活动活动别名的名称(例如 SharedPreferences)
<activity android:name=".ui.MainActivity"/>

<activity-alias
    android:name=".one"
    android:icon="@mipmap/ic_launcher_one"
    android:targetActivity=".ui.MainActivity"
    android:enabled="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=".two"
    android:icon="@mipmap/ic_launcher_two"
    android:targetActivity=".ui.MainActivity"
    android:enabled="false">

    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>

</activity-alias>
  1. 将服务添加到 AndroidManifest.xml
class ChangeAppIconService: Service() {
    private val aliases = arrayOf(".one", ".two")

    override fun onBind(intent: Intent?): IBinder? = null

    override fun onTaskRemoved(rootIntent: Intent?) {
        changeAppIcon()
        stopSelf()
    }

    fun changeAppIcon() {
        val sp = getSharedPreferences("appSettings", Context.MODE_PRIVATE)

        sp.getString("activeActivityAlias", ".one").let { aliasName ->
            if (!isAliasEnabled(aliasName)) {
                setAliasEnabled(aliasName)
            }
        }
    }

    private fun isAliasEnabled(aliasName: String): Boolean {
        return packageManager.getComponentEnabledSetting(
            ComponentName(
                this,
                "${BuildConfig.APPLICATION_ID}$aliasName"
            )
        ) == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
    }

    private fun setAliasEnabled(aliasName: String) {
        aliases.forEach {
            val action = if (it == aliasName)
                PackageManager.COMPONENT_ENABLED_STATE_ENABLED
            else
                PackageManager.COMPONENT_ENABLED_STATE_DISABLED
                
            packageManager.setComponentEnabledSetting(
                ComponentName(
                    this,
                    "${BuildConfig.APPLICATION_ID}$aliasName"
                ),
                action,
                PackageManager.DONT_KILL_APP
            )
        }
    }
}
  1. <service android:name=".ChangeAppIconService" android:stopWithTask="false" /> 开始ChangeAppIconService
MainActivity.onCreate

答案 9 :(得分:0)

要获得Markus工作的解决方案,我需要第一个Intent,所以:

Intent myLauncherIntent = new Intent(Intent.ACTION_MAIN);
            myLauncherIntent.setClassName(this,  this.getClass().getName());
            myLauncherIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

答案 10 :(得分:0)

应用上面提到的建议,每当默认图标更改为新图标时,我都会遇到应用程序被杀死的问题。因此,通过一些调整实现了代码。 第1步)。在文件AndroidManifest.xml中,使用android:enabled =“ true”创建默认活动,并使用android:enabled =“ false”创建其他别名。您将不包含android:enabled =“ true”,而是将其附加在其中。

       <activity
        android:name=".activities.SplashActivity"
        android:label="@string/app_name"
        android:screenOrientation="portrait"
        android:theme="@style/SplashTheme">

    </activity>
    <!-- <activity-alias used to change app icon dynamically>   : default icon, set enabled true    -->
    <activity-alias
        android:label="@string/app_name"
        android:icon="@mipmap/ic_launcher"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:name=".SplashActivityAlias1" <!--put any random name started with dot-->
        android:enabled="true"
        android:targetActivity=".activities.SplashActivity"> <!--target activity class path will be same for all alias-->
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity-alias>
    <!-- <activity-alias used to change app icon dynamically>  : sale icon, set enabled false initially -->
    <activity-alias
        android:label="@string/app_name"
        android:icon="@drawable/ic_store_marker"
        android:roundIcon="@drawable/ic_store_marker"
        android:name=".SplashActivityAlias" <!--put any random name started with dot-->
        android:enabled="false"
        android:targetActivity=".activities.SplashActivity"> <!--target activity class path will be same for all alias-->
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

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

步骤2)。制作一种方法来禁用包含默认图标的第一个活动别名,并启用需要更改包含图标的第二个别名。

/**
 * method to change the app icon dynamically
 *
 * @param context
 * @param isNewIcon  : true if new icon need to be set; false to set default 
 * icon
 */

public static void changeAppIconDynamically(Context context, boolean isNewIcon) {
    PackageManager pm = context.getApplicationContext().getPackageManager();
    if (isNewIcon) {
        pm.setComponentEnabledSetting(
                new ComponentName(context,
                        "com.example.dummy.SplashActivityAlias1"), //com.example.dummy will be your package
                PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                PackageManager.DONT_KILL_APP);

        pm.setComponentEnabledSetting(
                new ComponentName(context,
                        "com.example.dummy.SplashActivityAlias"),
                PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                PackageManager.DONT_KILL_APP);
    } else {
        pm.setComponentEnabledSetting(
                new ComponentName(context,
                        "com.example.dummy.SplashActivityAlias1"),
                PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                PackageManager.DONT_KILL_APP);

        pm.setComponentEnabledSetting(
                new ComponentName(context,
                        "com.example.dummy.SplashActivityAlias"),
                PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                PackageManager.DONT_KILL_APP);
    }
}

步骤3)。现在,根据您的要求调用此方法,例如单击按钮或特定日期或特定场合的条件,就像-

// Switch app icon to new icon
    GeneralUtils.changeAppIconDynamically(EditProfileActivity.this, true);
// Switch app icon to default icon
            GeneralUtils.changeAppIconDynamically(EditProfileActivity.this, false);

希望这将帮助那些面对应用程序问题而被图标更改杀死的人。 快乐编码:)