2009-07-09 4 views
102

Можно ли изменить значок приложения непосредственно из программы?
Я имею в виду, изменить icon.png в папке res\drawable.
Я бы хотел, чтобы пользователи меняли значок приложения из программы, чтобы в следующий раз они увидели ранее выбранный значок в панели запуска.Как изменить значок приложения программно в Android?

ответ

55

Это старый вопрос, но по-прежнему активна, как нет явного 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); 
     } 
    }); 
} 

Примечания:

  • Этот способ также работает, если ваш App контролирует больше ярлыков на домашнем экране, например, с различными дополнительными в Intent. Им просто нужны разные имена, так что правый удаляется и переустанавливается.

  • Программная обработка ярлыков в Android - это хорошо известная, широко используемая, но официально не поддерживаемая функция Android. Кажется, что он работает с пусковой установкой по умолчанию, и я никогда не пробовал ее нигде. Так что не вините меня, когда вы этого пользовательское сообщение электронной почты «Это не работает на моем XYZ, дважды укоренился, супер взорванный телефон»

  • Пусковые пишет Toast, когда ярлык был installad и один, когда ярлык был удален , Поэтому я получаю два Toast s каждый раз, когда меняю значок. Это не идеально, но хорошо, если остальное приложение отлично ...

+2

Приложение сегодняшнего календаря может использовать значки каждый день без тоста. –

+0

@ Джим (я думаю), это на самом деле виджет затем – JacksOnF1re

+0

@jboi Как насчет изменения позиции ярлыков после удаления? Ярлык теряет свое положение, указанное пользователем. И помещается в любую пустую ячейку. – Mixer

8

Предполагая, что вы имеете в виду изменение значка, отображаемого на главном экране, это легко сделать, создав виджет, который делает именно это. Вот статья, демонстрирующая, как это может быть достигнуто за «новые сообщения» типа приложение, похожего на iPhone:

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

31

Вы не можете изменить манифест или ресурс в подписанном-и запечатанном APK, кроме как через обновление программного обеспечения.

+0

Я знаю, что это Oldy, сомневаясь между открытием нового вопроса и спросить здесь, но здесь идет: * это все еще случай *? По умолчанию программа «mail» (не знаю, является ли это «смысл») на 2.2.1 изменяет значок (или, по крайней мере, рекламу накладывается на количество непрочитанных сообщений) – Nanne

+2

@Nanne: Это виджет приложения или функция главного экрана, а не значок приложения. Вы по-прежнему не можете изменить манифест или ресурс, кроме как с помощью обновления программного обеспечения. – CommonsWare

+0

Это то, что я получаю, когда добавляю _app_ 'mail' на рабочий стол, поэтому, если это виджет, у него есть способ добавить себя, когда я выбираю приложение. Но это может быть просто смысл. – Nanne

15

Programatically, вы можете опубликовать приложение запуска самостоятельно:

В вашем 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); 
+0

ничего не случилось с этим – nimi

+0

@James ссылка не работает. – Petr

+0

Спасибо Петру. Я удалил его. –

99

Попробуйте, это работает хорошо для меня =)

1. Измените MainActivity раздел в AndroidManifest.xml, удалите из него, линий с основной категорией в намеренном фильтрующей секции

<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. Набор программно: набор ВКЛЮЧИТЬ атрибут для соответствующих деятельностных псевдонима

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

Примечание, по крайней мере один должен быть включен во все времена.

+10

что на самом деле делает код? пожалуйста, вы можете объяснить, что – cafebabe1991

+3

печально работает по-разному на устройствах, которые я пробовал. Работает на HTC Desire 2.2, но ненадежна в Galaxy Nexus 4.2.2 и Nexus 7 4.3. На Galaxy Nexus может привести к исчезновению всех значков для приложения, а также удалению всех виджетов. Жаль, поэтому мне пришлось удалить эту функцию на более поздних устройствах. –

+0

Я сделал два псевдонима активности и нажал кнопку i, отключил один компонент и включил другой, но значок остается тем же (samsung galaxy tab2 android 4.1.1) – Mark

0

Чтобы получить решение по Маркусу работает я нуждался в первом Намерения так быть:

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

@ Решение 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) Обратите внимание, что значок не будет изменен немедленно, это может занять несколько секунд. Если вы щелкните по нему сразу после изменения, вы можете получить сообщение об ошибке: «Приложение не установлено».

Таким образом, IMHO это решение подходит только для замены значка в приложении для запуска приложений, но не для быстрых клавиш (т.значок на рабочем столе)

+1

Ошибка при запуске приложения. Активность по умолчанию не найдена. – CopsOnRoad

+0

Ошибка при запуске приложения. Активность по умолчанию не найдена. –

1

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); 
+0

Я получаю 'com.pritesh.resourceidentifierexample.MainActivity-Red не существует в com.pritesh.resourceidentifierexample' exception. здесь я использовал ваше манифестное имя, чтобы продемонстрировать свою проблему –

Смежные вопросы