如何在 Android 中以编程方式更改应用程序图标?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1103027/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to change an application icon programmatically in Android?
提问by systempuntoout
Is it possible to change an application icon directly from the program?
I mean, change icon.png
in the res\drawable
folder.
I would like to let users to change application's icon from the program so next time they would see the previously selected icon in the launcher.
是否可以直接从程序更改应用程序图标?
我的意思是,icon.png
在res\drawable
文件夹中进行更改。
我想让用户从程序中更改应用程序的图标,以便下次他们会在启动器中看到之前选择的图标。
采纳答案by jboi
It's an old question, but still active as there is no explicit Android feature. And the guys from facebook found a work around - somehow. Today, I found a way that works for me. Not perfect (see remarks at the end of this answer) but it works!
这是一个老问题,但仍然活跃,因为没有明确的 Android 功能。来自 facebook 的家伙找到了解决办法 - 不知何故。今天,我找到了一种适合我的方法。不完美(请参阅本答案末尾的评论)但它有效!
Main idea is, that I update the icon of my app's shortcut, created by the launcher on my home screen. When I want to change something on the shortcut-icon, I remove it first and recreate it with a new bitmap.
主要想法是,我更新了由主屏幕上的启动器创建的应用程序快捷方式的图标。当我想更改快捷方式图标上的某些内容时,我首先将其删除并使用新位图重新创建它。
Here is the code. It has a button increment
. When pressed, the shortcut is replaced with one that has a new counting number.
这是代码。它有一个按钮increment
。按下后,快捷方式将替换为具有新计数的快捷方式。
First you need these two permissions in your manifest:
首先,您的清单中需要这两个权限:
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" />
Then you need this two methods for installing and uninstalling shortcuts. The shortcutAdd
method creates a bitmap with a number in it. This is just to demonstrate that it actually changes. You probably want to change that part with something, you want in your app.
那么就需要这两种安装和卸载快捷方式的方法。该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);
}
And finally, here are two listener to add the first shortcut and update the shortcut with an incrementing counter.
最后,这里有两个监听器来添加第一个快捷方式并使用递增计数器更新快捷方式。
@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);
}
});
}
Remarks:
评论:
This way works also if your App controls more shortcuts on the home screen, e.g. with different extra's in the
Intent
. They just need different names so that the right one is uninstalled and reinstalled.The programmatical handling of shortcuts in Android is a well known, widely used but not officially supported Android feature. It seems to work on the default launcher and I never tried it anywhere else. So dont blame me, when you get this user-emails "It does not work on my XYZ, double rooted, super blasted phone"
The launcher writes a
Toast
when a shortcut was installad and one when a shortcut was uninstalled. So I get twoToast
s every time I change the icon. This is not perfect, but well, as long as the rest of my app is perfect...
如果您的应用程序控制主屏幕上的更多快捷方式,例如在
Intent
. 他们只需要不同的名称,以便卸载并重新安装正确的名称。Android 中快捷方式的编程处理是众所周知的、广泛使用但未得到官方支持的 Android 功能。它似乎适用于默认启动器,我从未在其他任何地方尝试过。所以不要怪我,当你收到这个用户的电子邮件“它在我的 XYZ 上不起作用,双根,超级爆炸的手机”
启动器
Toast
在安装快捷方式时写入一个,在卸载快捷方式时写入一个。所以我Toast
每次更改图标时都会得到两个s。这并不完美,但是,只要我的应用程序的其余部分是完美的......
回答by P-A
Try this, it works fine for me:
试试这个,它对我来说很好用:
1 . Modify your MainActivity
section in AndroidManifest.xml
, delete from it, line with MAIN
category in intent-filter
section
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 . Create <activity-alias>
, for each of your icons. Like this
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 . Set programmatically: set ENABLE attribute for the appropriate activity-alias
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);
Note, At least one must be enabled at all times.
请注意,必须始终启用至少一个。
回答by CommonsWare
You cannot change the manifest or the resource in the signed-and-sealed APK, except through a software upgrade.
除非通过软件升级,否则您无法更改已签名并密封的 APK 中的清单或资源。
回答by Andrei Marcut
Programatically, you may want to publish the application launcher yourself :
以编程方式,您可能希望自己发布应用程序启动器:
Note: this method no longer works starting with Android 8.0 - Oreo
注意:此方法不再适用于 Android 8.0 - Oreo
In your AndroidManifest.xml, add :
在您的 AndroidManifest.xml 中,添加:
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
Then you need create your app launcher intent:
然后你需要创建你的应用启动器意图:
Intent myLauncherIntent = new Intent();
myLauncherIntent.setClassName("your.package.name", "YourLauncherActivityName");
myLauncherIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Create an install shortcut intent with your app launcher and custom icon:
使用您的应用启动器和自定义图标创建安装快捷方式意图:
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");
And finally launch the broadcast intent:
最后启动广播意图:
getApplicationContext().sendBroadcast(intent);
回答by Marius Kjeldahl
Assuming you mean changing the icon shown on the home screen, this could easily be done by creating a widget that does exactly this. Here's an article that demonstrate how that can be accomplished for a "new messages" type application similar to iPhone:
假设您的意思是更改主屏幕上显示的图标,这可以通过创建一个完全执行此操作的小部件来轻松完成。这是一篇文章,演示了如何为类似于 iPhone 的“新消息”类型的应用程序实现这一点:
回答by Deqing
@P-A's solution partially works for me. Detail my findings below:
@PA 的解决方案部分对我有用。在下面详细说明我的发现:
1) The first code snippet is incorrect, see below:
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) Should use following code to disable all icons before enabling another one, otherwise it will add a new icon, instead of replacing it.
2) 在启用另一个图标之前,应使用以下代码禁用所有图标,否则它将添加一个新图标,而不是替换它。
getPackageManager().setComponentEnabledSetting(
getComponentName(), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
BUT, if you use code above, then shortcut on homescreen will be removed! And it won't be automatically added back. You might be able to programmatically add icon back, but it probably won't stay in the same position as before.
但是,如果您使用上面的代码,那么主屏幕上的快捷方式将被删除!它不会自动添加回来。您也许能够以编程方式重新添加图标,但它可能不会保持与以前相同的位置。
3) Note that the icon won't get changed immediately, it might take several seconds. If you click it right after changing, you might get an error saying: "App isn't installed".
3) 请注意,图标不会立即更改,可能需要几秒钟。如果您在更改后立即单击它,您可能会收到一条错误消息:“未安装应用程序”。
So, IMHO this solution is only suitable for changing icon in app launcher only, not for shortcuts (i.e. the icon on homescreen)
因此,恕我直言,此解决方案仅适用于更改应用程序启动器中的图标,不适用于快捷方式(即主屏幕上的图标)
回答by Faxriddin Abdullayev
Try this solution
试试这个解决方案
<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>
Add the following code when you want to change your app icon
当您想更改应用程序图标时添加以下代码
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);
回答by Pritesh Patel
AndroidManifest.xml
example:
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>
Then follow below given code in MainActivity
:
然后按照下面给出的代码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);
回答by PuZZleDucK
To get the solution by Markus working I needed the first Intent so be:
为了通过 Markus 工作获得解决方案,我需要第一个 Intent,所以是:
Intent myLauncherIntent = new Intent(Intent.ACTION_MAIN);
myLauncherIntent.setClassName(this, this.getClass().getName());
myLauncherIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
回答by Abhijeet
Applying the suggestions mentioned, I've faced the issue of app getting killed whenever default icon gets changed to new icon. So have implemented the code with some tweaks. Step 1). In file AndroidManifest.xml, create for default activity with android:enabled="true" & other alias with android:enabled="false". Your will not contain but append those in with android:enabled="true".
应用提到的建议,当默认图标更改为新图标时,我遇到了应用程序被杀死的问题。所以已经通过一些调整实现了代码。第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>
Step 2). Make a method that will be used to disable 1st activity-alias that contains default icon & enable 2nd alias that contains icon need to be changed.
第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);
}
}
Step 3). Now call this method depending on your requirement, say on button click or date specific or occasion specific conditions, simply like -
步骤 3)。现在根据您的要求调用此方法,例如单击按钮或特定日期或特定场合条件,就像 -
// Switch app icon to new icon
GeneralUtils.changeAppIconDynamically(EditProfileActivity.this, true);
// Switch app icon to default icon
GeneralUtils.changeAppIconDynamically(EditProfileActivity.this, false);
Hope this will help those who face the issue of app getting killed on icon change. Happy Coding :)
希望这将帮助那些面临应用程序因图标更改而被杀死的问题的人。快乐编码:)