¿Cómo cambiar un icono de aplicación programáticamente en Android?

¿Es posible cambiar el icono de una aplicación directamente desde el progtwig?
Quiero decir, cambie icon.png en la carpeta res\drawable .
Me gustaría dejar que los usuarios cambien el ícono de la aplicación del progtwig para que la próxima vez vean el ícono previamente seleccionado en el iniciador.

Es una vieja pregunta, pero sigue activa ya que no hay una función explícita de Android. Y los chicos de Facebook encontraron un trabajo alternativo, de alguna manera. Hoy, encontré una forma que me funciona. No es perfecto (ver comentarios al final de esta respuesta) ¡pero funciona!

La idea principal es actualizar el ícono del acceso directo de mi aplicación, creado por el iniciador en la pantalla de inicio. Cuando quiero cambiar algo en el icono de acceso directo, lo elimino primero y lo vuelvo a crear con un nuevo bitmap.

Aquí está el código. Tiene un increment botón. Cuando se presiona, el atajo se reemplaza por uno que tiene un nuevo número de conteo.

Primero necesitas estos dos permisos en tu manifiesto:

   

Entonces necesita estos dos métodos para instalar y desinstalar accesos directos. El shortcutAdd shortAdAd crea un bitmap con un número en él. Esto es solo para demostrar que realmente cambia. Es probable que desee cambiar esa parte con algo que desee en su aplicación.

 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); } 

Y finalmente, aquí hay dos oyentes para agregar el primer atajo y actualizar el atajo con un contador de incremento.

 @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); } }); } 

Observaciones:

  • De esta forma también funciona si su aplicación controla más accesos directos en la pantalla de inicio, por ejemplo, con diferentes extra en el Intent . Solo necesitan nombres diferentes para que la correcta se desinstale y vuelva a instalar.

  • El manejo programático de accesos directos en Android es una característica de Android bien conocida, ampliamente utilizada pero no oficialmente admitida. Parece funcionar en el iniciador predeterminado y nunca lo intenté en ningún otro lado. Así que no me culpes, cuando recibas este correo electrónico de usuario “No funciona en mi teléfono XYZ, de doble enraizamiento y muy malgastado”

  • El iniciador escribe un Toast cuando se Toast un atajo y otro cuando se desinstaló un atajo. Así que me doy dos Toast cada vez que cambio el ícono. Esto no es perfecto, pero bueno, siempre y cuando el rest de mi aplicación sea perfecta …

Prueba esto, funciona bien para mí:

1. Modifique su sección de MainActivity en AndroidManifest.xml , elimínela de ella, MainActivity con la categoría MAIN en la sección de intent-filter

   ==>  <== Delete this line    

2. Crea , para cada uno de tus icons. Me gusta esto

       

3. Establezca programáticamente: establezca el atributo ENABLE para el activity-alias apropiado

  getPackageManager().setComponentEnabledSetting( new ComponentName("ru.quickmessage.pa", "ru.quickmessage.pa.MainActivity-Red"), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP); 

Nota: Al menos uno debe estar habilitado en todo momento.

No puede cambiar el manifiesto o el recurso en el APK firmado y sellado, excepto a través de una actualización de software.

Progtwigtivamente, es posible que desee publicar el iniciador de aplicaciones usted mismo:

En su AndroidManifest.xml, agregue:

  

Entonces necesitas crear el bash de iniciador de tu aplicación:

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

Cree un bash de acceso directo a la instalación con el iniciador de aplicaciones y el icono personalizado:

 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"); 

Y finalmente lanzar el bash de transmisión:

 getApplicationContext().sendBroadcast(intent); 

Suponiendo que quiera decir cambiar el ícono que se muestra en la pantalla de inicio, esto podría hacerse fácilmente creando un widget que haga exactamente esto. Aquí hay un artículo que demuestra cómo se puede lograr esto para una aplicación tipo “mensajes nuevos” similar a iPhone:

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

La solución de @ PA funciona parcialmente para mí. Detallar mis hallazgos a continuación:

1) El primer fragmento de código es incorrecto, ver a continuación:

  ==>  <== This line shouldn't be deleted, otherwise will have compile error  //DELETE THIS LINE   

2) Debe usar el siguiente código para desactivar todos los icons antes de habilitar otro, de lo contrario agregará un ícono nuevo, en lugar de reemplazarlo.

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

PERO, si usa el código anterior, ¡se eliminarán los accesos directos en la pantalla de inicio! Y no se agregará automáticamente de nuevo. Es posible que pueda volver a agregar el icono mediante progtwigción, pero probablemente no se mantendrá en la misma posición que antes.

3) Tenga en cuenta que el ícono no se cambiará de inmediato, podría tomar varios segundos. Si hace clic en él justo después de cambiar, es posible que aparezca un error que dice: “La aplicación no está instalada”.

Entonces, en mi humilde opinión, esta solución solo es adecuada para cambiar el ícono solo en el iniciador de aplicaciones, no para los accesos directos (es decir, el icono en la pantalla de inicio)

Ejemplo de AndroidManifest.xml :

                              

A continuación, siga el código dado a continuación en 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); 

Para obtener la solución de Markus trabajando, necesitaba la primera intención así que sé:

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