Как программно изменить значок приложения в Android? - PullRequest
133 голосов
/ 09 июля 2009

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

Ответы [ 9 ]

116 голосов
/ 06 марта 2013

Попробуйте, у меня все работает нормально:

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. Установить программно: установить атрибут ENABLE для соответствующего activity-alias

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

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

68 голосов
/ 25 октября 2013

Это старый вопрос, но он все еще активен, поскольку в нем нет явной функции Android. А ребята из фейсбука нашли обходной путь - как-то. Сегодня я нашел способ, который работает для меня. Не идеально (см. Примечания в конце этого ответа), но это работает!

Основная идея заключается в том, что я обновляю значок ярлыка моего приложения, созданный средством запуска на домашнем экране. Когда я хочу что-то изменить на ярлыке, я сначала удаляю его и воссоздаю с новым растровым изображением.

Вот код. Имеет кнопку 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 с каждый раз, когда меняю значок. Это не идеально, но хорошо, пока остальная часть моего приложения идеально ...

35 голосов
/ 09 июля 2009

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

16 голосов
/ 23 марта 2011

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

Примечание: этот метод больше не работает, начиная с 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);
9 голосов
/ 09 июля 2009

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

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

7 голосов
/ 01 июля 2016

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

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

5 голосов
/ 09 августа 2017

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);
3 голосов
/ 05 октября 2018

Попробуйте это решение

<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);
0 голосов
/ 05 мая 2013

Чтобы получить решение от работающего Маркуса, мне потребовалось первое намерение, поэтому:

Intent myLauncherIntent = new Intent(Intent.ACTION_MAIN);
            myLauncherIntent.setClassName(this,  this.getClass().getName());
            myLauncherIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...