Androidでプログラムによってアプリケーションアイコンを変更する方法


153

プログラムから直接アプリケーションアイコンを変更することはできますか?つまり、フォルダを
変更icon.pngres\drawableます。
ユーザーがプログラムからアプリケーションのアイコンを変更できるようにして、次回ランチャーで以前に選択したアイコンが表示されるようにします。

回答:


79

古い質問ですが、明示的なAndroid機能がないため、まだアクティブです。そして、facebookの人たちは回避策を見つけました-どういうわけか。今日、私は自分に合った方法を見つけました。完璧ではありませんが(この回答の最後にある備考を参照)、うまくいきます!

主なアイデアは、ホーム画面のランチャーによって作成されたアプリのショートカットのアイコンを更新することです。ショートカットアイコンの何かを変更したいときは、まずそれを削除し、新しいビットマップで再作成します。

これがコードです。ボタンがありますincrement。押すと、ショートカットは新しいカウント番号を持つショートカットに置き換えられます。

まず、マニフェストに次の2つの権限が必要です。

<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" />

次に、ショートカットのインストールとアンインストールにこの2つの方法が必要です。この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);
}

そして最後に、最初のショートカットを追加し、増分カウンターでショートカットを更新する2つのリスナーがあります。

@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機能です。それはデフォルトのランチャーで動作するようで、私は他のどこかでそれを試したことはありません。あなたがこのユーザーからのメールを受け取ったとき、私を非難しないでください。

  • ランチャーは、Toastショートカットがインストールされたときとショートカットがアンインストールされたときを書き込みます。そのためToast、アイコンを変更するたびに2を取得します。これは完璧ではありませんが、私のアプリの残りの部分が完璧である限り...


9
今日のカレンダーアプリは、トーストなしで毎日アイコンを変更できます。
ジムマッキース、2014

1
@ジム(私は思う)これは実際にはウィジェットです
JacksOnF1re

3
残念ながらマシュマロではshortcutDelが機能しなくなりました。stackoverflow.com
a / 33731620/1545993

2
これは、ランチャーアイコンではなく、ショートカットアイコンを置き換えます
user1506104

3
以下の行では、Play.classおよびConstants.ACTION_PLAYとは何ですかIntent shortcutIntent = new Intent(getApplicationContext()、Play.class); shortcutIntent.setAction(Constants.ACTION_PLAY);
Dasharath Singh Bajroliya 2018年

136

これを試してください、それは私にとってはうまくいきます:

1。でMainActivityセクションを変更しAndroidManifest.xml、そこから削除しMAINintent-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);

注:少なくとも1つは常に有効にする必要があります。


3
残念ながら、試したデバイスによって動作が異なります。HTC Desire 2.2で動作しますが、Galaxy Nexus 4.2.2およびNexus 7 4.3では信頼できません。Galaxy Nexusでは、アプリのすべてのアイコンが消えたり、ウィジェットが削除されたりする可能性があります。残念、私は後のデバイスでこの機能を削除する必要がありました。
Richard Le Mesurier 2013年

7
これを削除したため、アプリを起動できません:<action android:name = "android.intent.action.MAIN" /> <category android:name = "android.intent.category.LAUNCHER" />
noobProgrammer

1
これは、アプリトレイとホーム画面のランチャーアイコンを切り替えるために完全に機能しますが、OSレベル(マルチタスク、アンインストールポップアップ、またはアプリケーションマネージャーのリストなど)で使用されるアイコンが残っていることがわかりましたオリジナル、またはマニフェストのアプリケーションレベルでアイコンを設定していない場合は、デフォルトの汎用Androidアイコンになります。これに対する解決策を見つけましたか、またはOSレベルのアイコンの不一致(または不在)を許容しますか?
jokeefe 2014年

2
アプリの実行中にエラーが発生しました。デフォルトのアクティビティが見つかりません。
CopsOnRoad 2017年

1
アプリの実行中にエラーが発生しました。デフォルトのアクティビティが見つかりません
カミルイバドフ2017年

36

ソフトウェアのアップグレードによる場合を除いて、署名およびシールされたAPKのマニフェストまたはリソースを変更することはできません。


2
@Nanne:これはアプリウィジェットまたはホーム画面の機能であり、アプリケーションアイコンではありません。ソフトウェアのアップグレードを除いて、マニフェストまたはリソースを変更することはできません。
CommonsWare 2011年

1
?いいえ、その逆です。つまり、ウィジェットではありません(アドバタイズされません)。アプリのショートカットとして追加します。しかし、あなたが言うように、この非在庫のものはその単なるアイコンを意味するからといって、それがそうであるとは限らない:)
ナン

2
@NeTeInStEiN:すべてのホーム画面(たとえば、コンポーネント対応の変更に注意を払わないもの)では機能しません。
CommonsWare

1
もう本当ではない。Android 6以降のGoogleカレンダーでは、ランチャーが毎日変更されています。今日、アイコンは「2」、昨日は「1」でした。通常、アイコンには「31」がありました。しかし、今は変わりません。誰もがこれがどのように可能であるか知っていますか?
UeliDeSchwert 2017年

1
@ボビー:Playストアには、数千に及ぶものではないにせよ、数百に及ぶAndroidデバイスモデルに存在する数百の異なるホーム画面に加えて、数百に及ぶホーム画面の実装があることを意味します。これらのホーム画面の実装には、動的なランチャーアイコンの置換を可能にするフックがあります。ただし、すべてのホーム画面がこれを提供する必要があるわけではありません。1つのデバイスの1つのホーム画面の1つのアプリでこの動作が見られるからといって、すべてのデバイスのすべてのホーム画面のすべてのアプリでこの動作が利用できるわけではありません。
CommonsWare 2017年

17

プログラム的に、アプリケーションランチャーを自分で公開することもできます。

注:この方法は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);

これは、ショートカットアイコンではなく、ランチャーアイコン置き換え
user1506104


9

@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>

2)別のアイコンを有効にする前に、次のコードを使用してすべてのアイコンを無効にする必要があります。そうしないと、アイコンを置き換えるのではなく、新しいアイコンが追加されます。

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

しかし、上記のコードを使用すると、ホーム画面のショートカットが削除されます!また、自動的に追加されることはありません。プログラムでアイコンを元に戻すことはできますが、おそらく以前と同じ位置にとどまることはありません。

3)アイコンはすぐに変更されないことに注意してください。数秒かかる場合があります。変更後すぐにクリックすると、「アプリがインストールされていません」というエラーが表示される場合があります。

したがって、このソリューションは、アプリランチャーのアイコンを変更する場合にのみ適しています。ショートカット(ホーム画面のアイコンなど)には適していません。


2
アプリの実行中にエラーが発生しました。デフォルトのアクティビティが見つかりません。
CopsOnRoad 2017年

ランチャーを削除すると、デフォルトのアクティビティ@Deqingはどのように見つけられますか
j2emanue 2018

5

この解決策を試してください

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

4

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

com.pritesh.resourceidentifierexample.MainActivity-Red doesn't exist in com.pritesh.resourceidentifierexample例外が発生します。ここで私はちょうど私の問題を示すために、マニフェストの名前を使用しました
Tejas Pandya

0

Markusのソリューションを機能させるには、最初のインテントが必要だったので、

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

0

上記の提案を適用すると、デフォルトのアイコンが新しいアイコンに変更されるたびにアプリが強制終了するという問題に直面しました。そのため、コードをいくつか調整して実装しました。ステップ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>

ステップ2)。デフォルトのアイコンを含む最初のアクティビティエイリアスを無効にし、変更が必要なアイコンを含む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);
    }
}

手順3)。今、あなたの要件に応じてこのメソッドを呼び出してください-ボタンのクリックや日付の特定の、または特定の機会の特定の条件で、単純に-

// Switch app icon to new icon
    GeneralUtils.changeAppIconDynamically(EditProfileActivity.this, true);
// Switch app icon to default icon
            GeneralUtils.changeAppIconDynamically(EditProfileActivity.this, false);

これが、アイコンの変更でアプリが殺されてしまう問題に直面している人たちに役立つことを願っています。ハッピーコーディング:)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.