Android'de bir uygulama simgesini programlı olarak nasıl değiştirebilirim?


154

Bir uygulama simgesini doğrudan programdan değiştirmek mümkün müdür?
Ben, değişikliği anlamına icon.pngiçinde res\drawableklasöründe.
Kullanıcıların, uygulamanın simgesini yeniden başlatmasına izin vermek istiyorum, böylece bir dahaki sefere başlatıcıda önceden seçilen simgeyi görecekler.

Yanıtlar:


81

Bu eski bir soru, ancak açık bir Android özelliği olmadığı için hala aktif. Ve facebook'tan gelen adamlar bir şekilde bir iş buldu - bir şekilde. Bugün, benim için işe yarayan bir yol buldum. Mükemmel değil (bu cevabın sonundaki açıklamalara bakın) ama işe yarıyor!

Ana fikir, ana ekranımda başlatıcı tarafından oluşturulan uygulamamın kısayolunun simgesini güncellemem. Kısayol simgesindeki bir şeyi değiştirmek istediğimde, önce onu kaldırırım ve yeni bir bitmap ile yeniden oluştururum.

İşte kod. Bir düğmesi var increment. Basıldığında, kısayol yeni bir sayma numarası olan bir kısayol ile değiştirilir.

İlk olarak manifestinizde şu iki izne ihtiyacınız var:

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

Ardından kısayolları yüklemek ve kaldırmak için bu iki yönteme ihtiyacınız vardır. shortcutAddYöntem içinde bir sayı ile bir bitmap oluşturur. Bu sadece gerçekten değiştiğini göstermek içindir. Muhtemelen bu bölümü uygulamanızda istediğiniz bir şeyle değiştirmek istiyorsunuz.

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

Ve son olarak, ilk kısayolu eklemek ve kısayolu artan bir sayaçla güncellemek için iki dinleyici.

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

Uyarılar:

  • Bu şekilde, Uygulamanız ana ekranda daha fazla kısayolu kontrol ederse de çalışır, örn Intent. Doğru isimlerin kaldırılması ve yeniden yüklenmesi için sadece farklı adlara ihtiyaçları vardır.

  • Android'deki kısayolların programlı kullanımı, iyi bilinen, yaygın olarak kullanılan ancak resmi olarak desteklenmeyen bir Android özelliğidir. Varsayılan başlatıcıda çalışıyor gibi görünüyor ve başka hiçbir yerde denemedim. Bu yüzden bu kullanıcı e-postalarını aldığınızda beni suçlama "Bu benim XYZ, çift köklü, süper patlama telefonumda çalışmıyor"

  • Başlatıcı Toast, bir kısayol yüklendiğinde bir ve bir kısayol kaldırıldığında bir yazar. ToastSimgeyi her değiştirdiğimde iki saniye alıyorum. Uygulamamın geri kalanı mükemmel olduğu sürece bu mükemmel değil, ama iyi ...


9
Bugünün Takvim uygulaması tost olmadan günlük simgeler canges.
Jim McKeeth

1
@ Jim (sanırım) bu aslında bir widget o zaman
JacksOnF1re

3
shortcutDel maalesef ayrıca bkz, Marshmallow içinde artık çalışmıyor stackoverflow.com/a/33731620/1545993
Taifun

2
başlatıcı simgesinin yerine kısayol simgesinin yerini alır
user1506104 16:18

3
Aşağıdaki satırlarda Play.class ve Constants.ACTION_PLAY amacıdır. ShortcutIntent = new Intent (getApplicationContext (), Play.class); shortcutIntent.setAction (Constants.ACTION_PLAY);
Dasharath Singh Bajroliya

136

Bunu deneyin, benim için iyi çalışıyor:

1. MainActivityBölümünüzü bölümden değiştirin, bölümden AndroidManifest.xmlsilin, bölümdeki MAINkategoriye göre intent-filtersıralayın

<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>Simgelerinizin her biri için oluşturun . Bunun gibi

<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. Programlı olarak ayarla: uygun için ENABLE özniteliğini ayarlaactivity-alias

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

Not: Her zaman en az bir tanesinin etkinleştirilmesi gerekir.


3
ne yazık ki denediğim cihazlarda farklı çalışıyor. HTC Desire 2.2 üzerinde çalışır, ancak Galaxy Nexus 4.2.2 ve Nexus 7 4.3'te güvenilmez. Galaxy Nexus'ta, uygulamanın kaybolması için tüm simgelere ve ayrıca tüm widget'ların kaldırılmasına neden olabilir. Yazık, bu yüzden sonraki cihazlarda bu işlevselliği kaldırmak zorunda kaldım.
Richard Le Mesurier


1
Bu, uygulama tepsisindeki ve ana ekrandaki başlatıcı simgeleri arasında geçiş yapmak için mükemmel çalışıyor, ancak işletim sistemi düzeyinde kullanılan simgenin (çoklu görev, kaldırma açılır penceresi veya Uygulama Yöneticisi listesinde) kaldığını gördüm manifest'te uygulama düzeyinde bir tane ayarlamadıysanız orijinal veya varsayılan genel Android simgesi haline gelir. Buna bir çözüm buldunuz mu veya yalnızca işletim sistemi düzeyindeki simgede bir uyuşmazlığa (veya yokluğa) tolerans gösteriyor musunuz?
jokeefe

2
Uygulama çalıştırılırken hata oluştu. Varsayılan etkinlik bulunamadı.
CopsOnRoad

1
Uygulama çalıştırılırken hata oluştu. Varsayılan aktivite bulunamadı
Kamil Ibadov

36

Bir yazılım yükseltmesi dışında, imzalı ve mühürlü APK'daki manifest'i veya kaynağı değiştiremezsiniz.


2
@Nanne: Bu, bir uygulama simgesi değil, bir uygulama widget'ı veya ana ekran özelliğidir. Bir yazılım yükseltmesi dışında bildirimi veya kaynağı değiştiremezsiniz.
CommonsWare

1
? Hayır, başka bir yolla kastediyorum: onun değil (olarak ilan) bir widget. Bir uygulama kısayolu olarak ekliyorum. Ama, dediğin gibi, sadece bu saçmalık şey onun sadece bir simgeyi ima ettiği için, bu demek değil :)
Nanne

2
@NeTeInStEiN: Tüm ana ekranlar için çalışmaz (örneğin, bileşen özellikli değişikliklere dikkat etmeyenler).
CommonsWare

1
Artık doğru değil. Android 6 ve sonraki sürümlerde Google Takvim, başlatıcıda günlük olarak değişir. Bugün, ikon "2", dün "1" idi. Genellikle, ikon üzerinde bir "31" vardı. Ama artık değil, değişiyor. Bunun nasıl mümkün olduğunu bilen var mı?
UeliDeSchwert

1
@Bobby: Yani, binlerce Android cihaz modelinde yüzlerce farklı önceden yüklenmiş ana ekrana ek olarak, Play Store'da binlerce olmasa bile yüzlerce ana ekran uygulaması var. Bu ana ekran uygulamaları, dinamik başlatıcı simgesinin değiştirilmesine izin veren kancalara sahip olabilir. Ancak, tüm ana ekranların bunu sunması gerekmez. Bu davranışı bir cihazdaki bir ana ekranda bir uygulama için gördüğünüz, bunun tüm cihazlardaki tüm ana ekranlardaki tüm uygulamalar için kullanılabilir olduğu anlamına gelmez.
CommonsWare

17

Programlı olarak, uygulama başlatıcıyı kendiniz yayınlamak isteyebilirsiniz:

Not: Bu yöntem artık Android 8.0 - Oreo ile başlamıyor

AndroidManifest.xml dosyasında şunları ekleyin:

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

Ardından, uygulama başlatıcı amacınızı oluşturmanız gerekir:

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

Uygulama başlatıcı ve özel simgenizle bir yükleme kısayolu oluşturma hedefi:

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

Ve son olarak yayın niyetini başlatın:

getApplicationContext().sendBroadcast(intent);

başlatıcı simgesinin yerine kısayol simgesinin yerini alır
user1506104 16:18


9

@ PA'nın çözümü kısmen benim için çalışıyor. Bulgularımı aşağıda detaylandırın:

1) İlk kod snippet'i yanlış, aşağıya bakın:

<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) Başka bir simgeyi etkinleştirmeden önce tüm simgeleri devre dışı bırakmak için aşağıdaki kodu kullanmalıdır, aksi takdirde değiştirmek yerine yeni bir simge ekler.

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

AMA, yukarıdaki kodu kullanırsanız, ana ekrandaki kısayol kaldırılır! Ve otomatik olarak geri eklenmeyecek. Programlı olarak simge geri ekleyebilirsiniz, ancak muhtemelen daha önce olduğu gibi kalmayacaktır.

3) Simgenin hemen değişmeyeceğini, birkaç saniye sürebileceğini unutmayın. Değiştirdikten hemen sonra tıklarsanız, "Uygulama yüklü değil" şeklinde bir hata mesajı alabilirsiniz.

Bu nedenle, IMHO bu çözüm yalnızca uygulama başlatıcıdaki simgeyi değiştirmek için uygundur, kısayollar için değil (ör. Ana ekrandaki simge)


2
Uygulama çalıştırılırken hata oluştu. Varsayılan etkinlik bulunamadı.
CopsOnRoad

başlatıcıyı silerseniz, @Deqing varsayılan etkinliğini nasıl bulacak?
j2emanue

5

Bu çözümü deneyin

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

Uygulama simgenizi değiştirmek istediğinizde aşağıdaki kodu ekleyin

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 misal:

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

Sonra aşağıdaki kodu aşağıdaki şekilde izleyin 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İstisna alıyorum . burada manifest isminizi sadece sorunumu göstermek için kullandım
Tejas Pandya

0

Markus tarafından çözüm almak için ilk Niyet gerekiyordu yani olmak:

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

0

Belirtilen önerileri uygulayarak, varsayılan simge yeni simgeye her değiştiğinde uygulamanın öldürülmesi sorunuyla karşı karşıya kaldım. Bu yüzden bazı tweaks ile kodu uyguladık. Aşama 1). AndroidManifest.xml dosyasında android: enabled = "true" ve android ile diğer takma adlar: enabled = "false" ile varsayılan etkinlik için oluşturun. Android ile bunları içermeyecek, ancak ekleyeceksiniz: 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>

Adım 2). Varsayılan simge içeren 1. etkinlik takma adını devre dışı bırakmak ve simge içeren 2. takma adı etkinleştirmek için kullanılacak bir yöntem değiştirin.

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

Aşama 3). Şimdi gereksiniminize bağlı olarak bu yöntemi çağırın, örneğin düğme tıklaması veya tarihe özel veya duruma özgü koşullar gibi,

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

Bu simge değişikliği ile öldürülmesi app sorunu yaşayanlara yardımcı olacağını umuyoruz. Mutlu Kodlama :)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.