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

sys*_*out 139 android

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

小智 126

试试这个,它对我来说很好:

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>
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

3.以编程方式设置:为相应的设置ENABLE属性activity-alias

 getPackageManager().setComponentEnabledSetting(
        new ComponentName("ru.quickmessage.pa", "ru.quickmessage.pa.MainActivity-Red"), 
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
Run Code Online (Sandbox Code Playgroud)

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

  • 实际上代码的作用是什么?请你解释一下 (10认同)
  • 我不能启动我的应用程序,因为我删除了这个:<action android:name ="android.intent.action.MAIN"/> <category android:name ="android.intent.category.LAUNCHER"/> (5认同)
  • 遗憾的是,我试过的设备的工作方式不同.适用于HTC Desire 2.2,但在Galaxy Nexus 4.2.2和Nexus 7 4.3上不可靠.在Galaxy Nexus上,可以导致应用程序的所有图标消失,以及任何小部件被删除.可惜,所以我不得不在以后的设备上删除此功能. (3认同)
  • 运行应用程序时出错。未找到默认活动 (3认同)
  • 运行应用程序时出错。找不到默认活动。 (2认同)
  • 这效果很好。但是,“DONT_KILL_APP”标志似乎不起作用(或者我理解不正确)。在切换图标/活动别名的一两秒内,应用程序将被终止并从后台删除。图标在启动器中被替换,但应用程序被杀死:/有人知道如何防止此应用程序被杀死吗? (2认同)
  • 这似乎不适用于 Android 10,该应用程序会被杀死。对于旧版本的操作系统,它工作正常。 (2认同)

jbo*_*boi 71

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

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

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

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

<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" />
Run Code Online (Sandbox Code Playgroud)

然后,您需要这两种方法来安装和卸载快捷方式.该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);
}
Run Code Online (Sandbox Code Playgroud)

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

@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);
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

备注:

  • 如果您的应用程序控制主屏幕上的更多快捷方式,例如使用不同的额外内容,这种方式也适用Intent.它们只需要不同的名称,以便卸载并重新安装正确的名称.

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

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

  • 今天的日历应用程序每天都可以在没有祝酒的情况下制作图标. (8认同)
  • 不幸的是,_shortcutDel_在棉花糖中不再起作用,另请参见http://stackoverflow.com/a/33731620/1545993 (2认同)
  • 这取代了快捷图标,而不是启动器图标 (2认同)
  • 在下面的几行中,什么是Play.class和Constants.ACTION_PLAY。Intent ShortcutIntent = new Intent(getApplicationContext(),Play.class); shortcutIntent.setAction(Constants.ACTION_PLAY); (2认同)

Com*_*are 35

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

  • @Nanne:这是一个app小部件或主屏幕功能,而不是应用程序图标.除了通过软件升级之外,您仍然无法更改清单或资源. (2认同)
  • @NeTeInStEiN:它不适用于所有主屏幕(例如,那些不关注启用组件的更改的主屏幕). (2认同)
  • 不是真的了。Android 6+ 上的 Google 日历每天都会在启动器中更改。今天,图标是“2”,昨天是“1”。通常,图标上有一个“31”。但现在不是了,它会改变。有谁知道这怎么可能? (2认同)

And*_*cut 17

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

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

在AndroidManifest.xml中,添加:

<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
Run Code Online (Sandbox Code Playgroud)

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

Intent myLauncherIntent = new Intent();
myLauncherIntent.setClassName("your.package.name", "YourLauncherActivityName");
myLauncherIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Run Code Online (Sandbox Code Playgroud)

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

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");
Run Code Online (Sandbox Code Playgroud)

最后发布广播意图:

getApplicationContext().sendBroadcast(intent);
Run Code Online (Sandbox Code Playgroud)

  • 请注意,这不会起作用,因为奥利奥 (2认同)

Mar*_*ahl 10

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

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


Dmi*_*tov 8

如前所述,您需要使用<activity-alias>更改应用程序图标。\n为了避免在启用适当的活动别名后终止应用程序,您需要在终止应用程序后执行此操作。要查明应用程序是否被杀死,您可以使用此方法

\n
    \n
  1. 在 AndroidManifest.xml 中创建活动别名
  2. \n
\n\n
<activity android:name=".ui.MainActivity"/>\n\n<activity-alias\n    android:name=".one"\n    android:icon="@mipmap/ic_launcher_one"\n    android:targetActivity=".ui.MainActivity"\n    android:enabled="true">\n\n    <intent-filter>\n        <action android:name="android.intent.action.MAIN" />\n        <category android:name="android.intent.category.LAUNCHER" />\n    </intent-filter>\n\n</activity-alias>\n\n<activity-alias\n    android:name=".two"\n    android:icon="@mipmap/ic_launcher_two"\n    android:targetActivity=".ui.MainActivity"\n    android:enabled="false">\n\n    <intent-filter>\n        <action android:name="android.intent.action.MAIN" />\n        <category android:name="android.intent.category.LAUNCHER" />\n    </intent-filter>\n\n</activity-alias>\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. \xd0\xa1创建一个服务,该服务将在终止应用程序后更改活动活动别名。您需要将新活动活动别名的名称存储在某处(例如 SharedPreferences)
  2. \n
\n\n
class ChangeAppIconService: Service() {\n    private val aliases = arrayOf(".one", ".two")\n\n    override fun onBind(intent: Intent?): IBinder? = null\n\n    override fun onTaskRemoved(rootIntent: Intent?) {\n        changeAppIcon()\n        stopSelf()\n    }\n\n    fun changeAppIcon() {\n        val sp = getSharedPreferences("appSettings", Context.MODE_PRIVATE)\n\n        sp.getString("activeActivityAlias", ".one").let { aliasName ->\n            if (!isAliasEnabled(aliasName)) {\n                setAliasEnabled(aliasName)\n            }\n        }\n    }\n\n    private fun isAliasEnabled(aliasName: String): Boolean {\n        return packageManager.getComponentEnabledSetting(\n            ComponentName(\n                this,\n                "${BuildConfig.APPLICATION_ID}$aliasName"\n            )\n        ) == PackageManager.COMPONENT_ENABLED_STATE_ENABLED\n    }\n\n    private fun setAliasEnabled(aliasName: String) {\n        aliases.forEach {\n            val action = if (it == aliasName)\n                PackageManager.COMPONENT_ENABLED_STATE_ENABLED\n            else\n                PackageManager.COMPONENT_ENABLED_STATE_DISABLED\n                \n            packageManager.setComponentEnabledSetting(\n                ComponentName(\n                    this,\n                    "${BuildConfig.APPLICATION_ID}$aliasName"\n                ),\n                action,\n                PackageManager.DONT_KILL_APP\n            )\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. 将服务添加到AndroidManifest.xml
  2. \n
\n\n
<service \n    android:name=".ChangeAppIconService"\n    android:stopWithTask="false"\n    />\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. 开始ChangeAppIconServiceMainActivity.onCreate
  2. \n
\n\n
class MainActivity: Activity {\n\n    ...\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n       ...\n\n       startService(Intent(this, ChangeAppIconService::class.java))\n\n       ...\n    }\n\n    ...\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n


Deq*_*ing 7

@ PA的解决方案部分适用于我.详细说明以下我的发现

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>
Run Code Online (Sandbox Code Playgroud)

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

getPackageManager().setComponentEnabledSetting(
        getComponentName(), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 运行app时出错.未找到默认活动. (2认同)

Fax*_*yev 6

试试这个解决方案

<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>
Run Code Online (Sandbox Code Playgroud)

当您想更改应用程序图标时添加以下代码

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);
Run Code Online (Sandbox Code Playgroud)