Android & IOS Dinamik AppIcon Değiştirme

Emre Karataş
KoçSistem
Published in
5 min readDec 6, 2023

Muhtemelen doğum gününüzde yada başka özel günlerde uygulama simgenizin değiştiğini ve sonrasında tekrar sorunsuz bir şekilde uygulamanın normal simgesine geri dönmesi gibi harika numaralar yapabilen uygulamalarla karşılaşmışsınızdır. Bu merak uyandıran ve “Bunu nasıl yapıyorlar?” diye merak etmenizi sağlayan türden bir özellik. Bu yazımda Android ve IOS ile bunun nasıl yapılacağına ve aynı zamanda nasıl yönetebileceğini anlatacağım. Keyifli okumalar ♥

Şöyle bir örnek senaryo düşünelim. Uygulamamızın tüm kullanıcılar tarafından görünen, bilinen bir simgesi var. Kullanıcılarımıza doğum günleri, yılbaşı ve tatil günlerinde özel simge gösterelim ve bu özel günlerde olan kullanıcılar, set edilen ilgili özel gün ikonunu görsünler. Kulağa hoş geliyor!!! Hadi buna önce Android sonra da IOS’ta yakından bakalım :)

Android’de uygulama simgesi diğer uygulama bileşenleri gibi manifest dosyasından ayarlanır. Android sistemi manifest dosyasını okur ve uygulama simgesini buna göre ayarlar. Runtime’da uygulama simgesini değiştirmenin bir yolu yoktur. Ancak bunu yapabileceğimiz geçici bir çözüm mevcut. activity-alias tanımlayarak appicon değiştirme sürecini yönetebiliriz. (activity-alias ile ilgili daha detaylı bilgiye buradan ulaşabilirsiniz.)

Doğum günü, yılbaşı ve tatil günleri için maniefst dosyasında aşağıdaki gibi activity-alias tanımlamalarını yapıyoruz. Manifest dosyasının son hali şu şekilde

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AppIconChanger"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<activity-alias
android:name=".Holiday"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_holiday"
android:label="Holiday"
android:roundIcon="@mipmap/ic_holiday"
android:targetActivity=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>

<activity-alias
android:name=".Birthday"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_birthday"
android:label="Birthday"
android:roundIcon="@mipmap/ic_birthday"
android:targetActivity=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>

<activity-alias
android:name=".NewYear"
android:enabled="false"
android:roundIcon="@mipmap/ic_new_year"
android:exported="true"
android:icon="@mipmap/ic_new_year"
android:label="New Year"
android:targetActivity=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
</application>
</manifest>

activity-alias’ta bulunan “targetActivity” haricindeki diğer tüm parametreler <activity> içerisinde mevcuttur. activity-alias içerisinde tanımlanmayan bir özellik hedef activity <activity> içerisinde tanımlandığı değerlerle aynı olmaktadır. activity-alias ile farklılaştırmak istediğimiz özellikleri belirtmeliyiz.

android:name: Activitynin ismi set edilir.
android:enabled: Uygulama ilk defa yüklendiğinde ve açıldığında
hangi activitynin launcher mod için
aktif olduğunu belirtir.
android:roundIcon ve android:icon: Uygulama simgesi set edilir.
android:targetActivity: İlişkili olduğu activity belirtilir. Bu özellik
ilgili activity name değeriyle eşleşmelidir.

Yukarıdaki ayarlara baktığımızda özetle şunu görüyoruz; bir adet ana <activity> ve bir de buna bağlı farklı özellikleri set edip ayarlamalar yapmamızı sağlayan <activity-alias> taglerimiz var. Manifestte ayarlama yaparken ilk açılmasını istediğimiz özellik için enable özelliğini true yapıp diğerlerini false yapıyoruz. Ayrıca activity-alias’taki targetActivity özelliğine ilgili activity tagindeki namede yazan değeri set ediyoruz. Manifestteki ayarlarımızın hepsi bu kadar. Şimdi gelelim bu ayarları kod tarafından yönetip değiştirerek uygulamanın simgesini değiştirme işlerine :)

Öncelikle aşağıdaki gibi bir enum class tanımladım, burada verdiğim isimleri manifestteki namelerle uyumlu verdiğimi belirtmek isterim :)

enum class AppIconEnum { Holiday, Birthday, NewYear, MainActivity }

Activity’deki koda girmeden önce örnek uygulama ekranını şuraya bırakayım

Tıklanan butondaki özelliğe göre uygulama simgesi değişecek şekilde bir örnek yaptım. Bu sihirli olayı gerçekleştiren koda bakabiliriz artık :)

private fun handleClickEvents() {
newYearBtn.setOnClickListener {
changeIcon(AppIconEnum.NewYear)
}
birthdayBtn.setOnClickListener {
changeIcon(AppIconEnum.Birthday)
}
holidayBtn.setOnClickListener {
changeIcon(AppIconEnum.Holiday)
}
resetBtn.setOnClickListener {
changeIcon(AppIconEnum.MainActivity)
}
}

private fun changeIcon(activeAppIcon: AppIconEnum) {
for (value in AppIconEnum.values()) {
val action = if (value == activeAppIcon) {
PackageManager.COMPONENT_ENABLED_STATE_ENABLED
} else {
PackageManager.COMPONENT_ENABLED_STATE_DISABLED
}
packageManager.setComponentEnabledSetting(
ComponentName(applicationContext, "com.ek.appiconchanger.${value.name}"),
action, PackageManager.DONT_KILL_APP
)
}
}

changeIcon aldığı enum değerine karşılık gelen activity alias değerindeki enabled özelliğini true yapıp, diğer activity alias’lardaki enabled özelliğini false yapıyor.

Çıktımızı şu şekilde görebiliriz 💪

IOS

IOS’ta bu işler nasıl yürüyor, gelin şimdi de buna bakalım.

Apple, AppStore’a uygulama göndermeden kod aracılığıyla önceden uygulama içinde tanımlanmış simgelerle uygulama simgesini değiştirebileceğimiz özelliği IOS 10.3 sürümüyle sundu.

Uygulamada kullanılacak olan ikonları ana proje dizinimize koyuyoruz;

birthday, holiday, newyear

IOS tarafında da aynı ikonları kullandım. Tatil, yılbaşı ve doğum günü gibi özel günlerde uygulama simgesini değiştirme akışını IOS için de gerçekleştirelim :)

Yukarda eklenen bu görselleri info.plist dosyasında aşağıdaki gibi tanımlanmalıdır;

Her alternatif simge için CFBundleAlternateIcons altına bir key ve CFBundleIconFiles eklenmesi gerekiyor. info.plist dosyasındaki ayar da bu kadar :) Şimdi gelelim değişim işleminin nasıl olduğuna bakmaya. ViewController’da kodların tamamı şu

class ViewController: UIViewController {
@IBOutlet weak var birthdayBtn: UIButton!
@IBOutlet weak var newYearBtn: UIButton!
@IBOutlet weak var holidayBtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()

birthdayBtn.addTarget(self, action: #selector(didTapAppIcon(_:)), for: .touchUpInside)
holidayBtn.addTarget(self, action: #selector(didTapAppIcon(_:)), for: .touchUpInside)
newYearBtn.addTarget(self, action: #selector(didTapAppIcon(_:)), for: .touchUpInside)

}

@objc private func didTapAppIcon(_ sender: UIButton){
if(sender.tag == 1){
UIApplication.shared.setAlternateIconName("holiday"){ error in
guard error == nil else{
print("Something went wrong1")
return
}
print("icon updated")

}
}
else if(sender.tag == 2){
UIApplication.shared.setAlternateIconName("birthday"){ error in
guard error == nil else{
print("Something went wrong2")
return
}
print("icon updated")

}
}
else if(sender.tag == 3){
UIApplication.shared.setAlternateIconName("newyear"){ error in
guard error == nil else{
print("Something went wrong3")
return
}
print("icon updated")

}
}
}
}

Koda bakınca tüm işi yapan yerin aslında aşağıdaki şu kod olduğunu görmüş oluyoruz.

UIApplication.shared.setAlternateIconName("newyear"){ error in
guard error == nil else{
print("Something went wrong3")
return
}
print("icon updated")

}

Çıktımızı şu şekilde görebiliriz 💪

Hem Android hem de IOS ile bu işin nasıl olacağını anlatmaya ve örneklendirmeye çalıştım. Şimdi gelelim bu işin nasıl işleyebileceğine.

Doğum günü ve tatil günü için elimizde bir kullanıcı bilgisi olması gerekir. Yani bu gibi profil bilgisi gerektiren işler için kullanıcının uygulamaya giriş yapması gerekir. Ama yılbaşı gibi genel durumlarda tüm uygulamayı kullanan kullanıcılar için aksiyon alabiliriz. Her iki durum için de şu 2 yöntemi uygulayabiliriz;

  1. Push ile App Icon Değiştirme
    AppIcon değişimi yapmak istediğimizi kişi/kişilere silent modda bir push bildirim göndeririz ve gelen bildirimdeki datanın içerisindeki parametreye göre app icon değişimi yapan fonksiyonu çalıştırıp icon değişikliğini gerçekleştirebiliriz. Kullanıcı uygulamayı kullansa da kullanmasa da bildirim servisi içinden bu işlem gerçekleşebilir. Burada iki konuya dikkat etmek gerekebilir. Birincisi, bildirim herhangi bir nedenden dolayı kullanıcıya ulaşmazsa bu değişim gerçekleşmez. İkincisi, kullanıcı uygulamayı 3 farklı cihazda aynı kullanıcıyla kullanıyordur ve sizin akışlarınızdan dolayı backend sadece kullanıcının son kullandığı telefona bildirim gönderiyor olabilir bu durumda kullanıcının diğer telefonlarında bu aksiyon gerçekleşmez.
  2. Splash Ekranda App Icon Değişimi
    Gözlemlediğim kadarıyla genel kullanımı bu şekilde. Splash’te yada ilk açılan sayfanızda alacağınız bir parametre ile app icon değişimi olup olmayacağı bilgisine göre fonksiyonu bu sayfada gerçekleştirebilir ve app icon değişimi olduğuna dair kullanıcınıza bir bilgilendirme mesajı gösterebilirsiniz.

Öncelikle yazımı okuduğunuz için teşekkür ederim. Hem Android hem de IOS ile dinamik bir şekilde App Icon değişiminin ve gerçek dünyada nasıl uygulama akışınıza dahil edebileceğinizi örneklendirip anlatmaya çalıştım. Umarım faydalı olmuştur ♥♥

Paylaşmak güzeldir 💪 Kodlara buradan erişebilirsiniz;
IOS Repo
Android Repo

Bir sonraki yazılarda görüşmek üzere 👋

--

--