İçeriğe Atla
Mustafa Erbay
Teknoloji · 9 dk okuma · görüntülenme Read in English

Mobil Uygulama Boyutu: Derleme Optimizasyonu mu, Dinamik Paketleme mi?

Mobil uygulama boyutunu optimize etmek için derleme seviyesinde mi yoksa dinamik paketleme yöntemleriyle mi ilerlemeli? İki yaklaşımın artıları, eksileri ve…

100%

Giriş: Uygulama Boyutu Neden Önemli?

Mobil uygulama geliştirme dünyasında, kullanıcı deneyimini doğrudan etkileyen en kritik faktörlerden biri de uygulamanın boyutu. Özellikle sınırlı depolama alanına sahip cihazlarda veya yavaş internet bağlantılarında, büyük boyutlu uygulamalar indirme süresini uzatır, cihaz performansını düşürebilir ve hatta kullanıcıların uygulamayı hiç indirmemesine neden olabilir. Bu nedenle, uygulama boyutunu optimize etmek, yalnızca teknik bir gereklilik değil, aynı zamanda stratejik bir başarı faktörüdür.

Peki, bu optimizasyonu nasıl sağlarız? Temelde iki ana yaklaşım öne çıkıyor: derleme (build) zamanında yapılan optimizasyonlar ve çalışma (runtime) zamanında dinamik olarak yönetilen paketleme stratejileri. Bu iki yaklaşımın her birinin kendine özgü avantajları, dezavantajları ve uygulama alanları var. Bu yazıda, bu yöntemleri derinlemesine inceleyecek, somut örneklerle ne zaman hangisini tercih etmemiz gerektiğini irdeleyeceğiz.

Derleme Zamanı Optimizasyonu: Koddan Gelen Ferahlık

Derleme zamanı optimizasyonları, uygulamanın kaynak kodunu ve bağımlılıklarını paketleme sürecinde küçültmeye odaklanır. Bu, genellikle geliştirme ortamında yapılan ayarlamalarla, kullanılan kütüphanelerin daha verimli hale getirilmesiyle veya gereksiz kodların ayıklanmasıyla gerçekleştirilir. Hedef, dağıtıma hazır hale gelen APK veya IPA dosyasının mümkün olduğunca küçük olmasını sağlamaktır.

Bu yaklaşımın en büyük artısı, sonuçların doğrudan ve kalıcı olmasıdır. Bir kere optimize ettiğinizde, uygulamanın temel boyutu küçülür ve bu, her kullanıcı için geçerli olur. Örneğin, Android’de ProGuard veya R8 gibi araçlar, kullanılmayan kodları (code shrinking), kod karartmayı (obfuscation) ve optimizasyonları (optimization) otomatik olarak yapar. Bu araçlar, özellikle Java ve Kotlin tabanlı uygulamalarda muazzam boyut tasarrufları sağlayabilir.

iOS tarafında ise Swift ve Objective-C derleyicileri de benzer optimizasyon yeteneklerine sahiptir. -O (optimize) bayrakları, LLVM derleyicisinin kodunuzu daha verimli hale getirmesini sağlar. Kütüphane optimizasyonları da bu kategoriye girer; gereksiz modülleri veya kaynakları çıkararak framework boyutunu azaltmak mümkündür. Örneğin, bir uygulama yalnızca belirli fonksiyonları kullanıyorsa, tüm framework’ü dahil etmek yerine yalnızca gerekli kısımları içeren bir “dynamic framework” oluşturmak veya sadece kullanılan kısımları eklemek boyutu önemli ölçüde düşürebilir.

Bu yöntemlerin dezavantajı ise, bazen derleme süresini uzatabilmesidir. Özellikle büyük projelerde, kod küçültme ve karartma işlemleri zaman alıcı olabilir. Ayrıca, yanlış yapılandırıldığında, bu araçlar uygulamanın çalışma zamanında beklenmedik hatalara yol açabilir. Örneğin, R8’in kod karartma seviyesi çok yüksek tutulursa ve gerekli sınıflar korunmazsa (keep rules), çalışma anında ClassNotFoundException gibi hatalarla karşılaşılabilir.

Dinamik Paketleme: İhtiyaç Anında Teslimat

Dinamik paketleme, uygulamanın tüm kodunu ve kaynaklarını başlangıçta indirmek yerine, ihtiyaç duyulduğunda sunucudan çekilmesini sağlayan stratejileri ifade eder. Bu yaklaşım, özellikle büyük ve karmaşık uygulamalar için idealdir; çünkü kullanıcılar yalnızca uygulamanın temel fonksiyonlarını içeren küçük bir başlangıç paketi indirirler. Geri kalan özellikler ve kaynaklar, kullanıcının bunları talep etmesiyle veya uygulamanın belirli bir bölümünü kullanmaya başladığında indirilir.

Android’de “Dynamic Feature Modules” bu yaklaşımın en belirgin örneğidir. Bu modüller, uygulamanızın belirli özelliklerini ayrı APK’lar olarak paketlemenize olanak tanır. Kullanıcılar ana uygulamayı yükledikten sonra, bu modülleri doğrudan Google Play Store’dan veya uygulamanızın kendi sunucusundan indirebilirler. Bu, ilk indirme boyutunu önemli ölçüde azaltır ve kullanıcıların yalnızca ihtiyaç duydukları özellikleri yüklemelerini sağlar.

iOS tarafında ise “On-Demand Resources” özelliği benzer bir amaca hizmet eder. Geliştiriciler, oyunlar veya büyük medya içeren uygulamalar için ek kaynakları (örneğin, oyun seviyeleri, yüksek çözünürlüklü görseller) sunucuda tutabilir ve kullanıcıların bunları ihtiyaç duyduklarında indirmelerini sağlayabilirler. Bu, uygulamanın App Store’daki boyutunu sınırlar ve kullanıcıların indirme süresini kısaltır.

Bu stratejilerin temel avantajı, ilk indirme boyutunu dramatik şekilde azaltmalarıdır. Bu, özellikle gelişmekte olan pazarlarda veya düşük bant genişliğine sahip bölgelerde kullanıcı kazanımını artırabilir. Ayrıca, kullanıcıların cihaz depolama alanından tasarruf etmelerini sağlar. Ancak, bu yaklaşımın dezavantajları da var. Dinamik modüllerin yönetimi daha karmaşıktır; geliştiricilerin modüller arasındaki bağımlılıkları, indirme durumlarını ve hataları ele almaları gerekir. Ayrıca, kullanıcıların ek indirmeler yapması gerektiği için, özelliklerin kullanıma sunulması biraz daha gecikebilir.

İki Yaklaşımın Karşılaştırılması ve Trade-off’lar

Derleme zamanı optimizasyonları ve dinamik paketleme, birbirini tamamlayan ancak farklı sorunlara çözüm üreten iki yaklaşımdır. Hangi yöntemin daha uygun olduğunu belirlemek, uygulamanın türüne, karmaşıklığına ve hedef kitlesine bağlıdır.

Derleme Zamanı Optimizasyonları:

  • Avantajları:
    • Uygulamanın temel boyutunu kalıcı olarak küçültür.
    • Tüm kullanıcılar için geçerlidir.
    • Genellikle daha az karmaşık bir uygulama mimarisi gerektirir.
    • Güvenlik (obfuscation) faydaları sağlar.
  • Dezavantajları:
    • Derleme süresini uzatabilir.
    • Yanlış yapılandırıldığında çalışma zamanı hatalarına yol açabilir.
    • Çok büyük veya çok fazla kaynak içeren uygulamalar için yeterli olmayabilir.

Dinamik Paketleme:

  • Avantajları:
    • İlk indirme boyutunu önemli ölçüde azaltır.
    • Kullanıcıların yalnızca ihtiyaç duydukları özellikleri indirmelerini sağlar.
    • Depolama alanı kısıtlı cihazlar için idealdir.
    • Daha modüler bir uygulama yapısı teşvik eder.
  • Dezavantajları:
    • Uygulama mimarisi daha karmaşık hale gelir.
    • Modül yönetimi ve bağımlılık takibi zordur.
    • Özelliklerin kullanıma sunulması gecikebilir (ek indirme gerektirir).
    • Sunucu tarafında ek altyapı ve yönetim gerektirir.

Pratikte, en iyi sonuçlar genellikle her iki yaklaşımın bir kombinasyonu kullanılarak elde edilir. Yani, öncelikle derleme zamanı araçlarıyla temel APK/IPA boyutunu mümkün olduğunca küçültürüz. Ardından, uygulamanın büyük ve nadiren kullanılan özelliklerini dinamik modüller veya isteğe bağlı kaynaklar olarak ayırırız. Bu hibrit yaklaşım, hem başlangıç boyutunu optimize eder hem de uygulamanın genel boyutunu yönetilebilir kılar.

Teknik Derinlik: Derleme Optimizasyonları Nasıl Çalışır?

Derleme zamanı optimizasyonlarının arkasındaki mekanizmaları anlamak, onları daha etkili kullanmamızı sağlar. Android’de R8 (veya onun öncülü ProGuard) genellikle üç ana işlevi yerine getirir: küçültme (shrinking), karartma (obfuscation) ve optimizasyon (optimization).

  1. Küçültme (Shrinking): R8, uygulamanın kodunu ve bağımlılıklarını analiz eder. Hangi sınıfların, metotların ve alanların gerçekten kullanıldığını belirler. Kullanılmayan kod parçacıklarını (dead code) tespit edip kaldırır. Bu süreç, özellikle büyük kütüphaneler kullanıldığında veya uygulamanın yalnızca belirli bölümleri aktif olarak kullanıldığında boyut üzerinde büyük bir etkiye sahiptir.
  2. Karartma (Obfuscation): Bu işlem, küçültmeden sonra kalan kodun okunabilirliğini azaltır. Sınıf, metot ve alan isimleri anlamsız kısa isimlere dönüştürülür (örneğin, com.example.MyApp.User sınıfı a.b.c gibi bir isme sahip olabilir). Bu, hem kodun tersine mühendislikle anlaşılmasını zorlaştırır hem de bazen isimlerin kısalığı sayesinde küçük boyut tasarrufları sağlar.
  3. Optimizasyon (Optimization): R8, kodu daha verimli hale getirmek için çeşitli dönüşümler uygular. Örneğin, sabit kod yayılımı (constant inlining), gereksiz metot çağrılarının kaldırılması gibi işlemlerle kodu optimize eder. Bu, hem performans artışı sağlar hem de kodun daha kompakt hale gelmesine yardımcı olur.

Bu araçların en kritik yönlerinden biri, “keep rules” adı verilen yapılandırma dosyalarıdır. Bu kurallar, R8’e hangi sınıfların, metotların veya alanların karartılmaması veya kaldırılmaması gerektiğini söyler. Özellikle refleksiyon (reflection) kullanan, JNI (Java Native Interface) ile etkileşimde bulunan veya serileştirme/deserializasyon mekanizmaları kullanan kodlarda bu kuralların doğru ayarlanması hayati önem taşır. Yanlış keep kuralları, uygulamanın çalışma zamanında çökmesine neden olabilir. Örneğin, bir sınıfın adı çalışma anında dinamik olarak kullanılıyorsa, R8 bu sınıfı kaldırırsa uygulama hata verecektir.

Teknik Derinlik: Dinamik Paketleme Mekanizmaları

Dinamik paketleme mekanizmaları, uygulamanın yaşam döngüsünü ve kaynak yönetimini daha karmaşık hale getirir. Android’deki Dynamic Feature Modules (DFM) örneğine bakalım. Bir DFM, ana uygulama modülünden bağımsız olarak derlenebilen ve dağıtılabilen bir modüldür. Google Play, bu modülleri ana uygulama ile birlikte veya kullanıcı talep ettiğinde indirir.

DFM’lerin yönetimi için Android Gradle Plugin’i özel destek sunar. Geliştiriciler, modüllerini “base module” ve “dynamic feature module” olarak işaretlerler.

  • Base Module: Uygulamanın temel işlevlerini, en sık kullanılan kodları ve kaynakları içerir. Her zaman ana APK ile birlikte gelir.
  • Dynamic Feature Module: Uygulamanın belirli özelliklerini barındırır. Bunlar, kullanıcının isteğine bağlı olarak indirilebilir.

Bu modüllerin indirilmesi ve yönetilmesi için SplitInstallManager API’si kullanılır. Bir geliştirici, bir dinamik özelliği indirmek için bir istek başlatabilir, indirme ilerlemesini izleyebilir ve indirme tamamlandığında özelliği etkinleştirebilir.

// Örnek Kotlin kodu: Dinamik özellik indirme
val splitInstallManager = SplitInstallCore.getInstance(context)
val moduleName = "my_dynamic_feature"

val request = SplitInstallRequest.newBuilder()
    .addModule(moduleName)
    .build()

splitInstallManager.startInstall(request)
    .addOnSuccessListener { installSessionId ->
        // İndirme başlatıldı, ilerleme izlenebilir
        Log.d("DynamicFeature", "İndirme başlatıldı. Session ID: $installSessionId")
    }
    .addOnFailureListener { exception ->
        // İndirme başarısız oldu
        Log.e("DynamicFeature", "İndirme başarısız: ${exception.message}")
    }

Bu yaklaşım, özellikle oyunlar veya büyük içerik kütüphaneleri içeren uygulamalar için devrim niteliğindedir. Örneğin, bir dil öğrenme uygulaması, kullanıcıların yalnızca ilgilendikleri dillerin paketlerini indirmelerine olanak tanıyabilir. Bu, hem ilk indirme boyutunu azaltır hem de kullanıcılara kişiselleştirilmiş bir deneyim sunar.

iOS’taki On-Demand Resources da benzer bir mantıkla çalışır. Geliştiriciler, App Store Connect üzerinden bu kaynakları yüklerler ve uygulama içinden bu kaynaklara erişim isteğinde bulunurlar. Bu kaynaklar, uygulamanın ana indirmesiyle birlikte indirilebilir veya daha sonra isteğe bağlı olarak indirilebilir. Bu, özellikle büyük grafik varlıkları veya oyun seviyeleri içeren uygulamalar için boyut sorununu çözmeye yardımcı olur.

Gerçek Dünya Senaryoları ve Uygulama Önerileri

Kendi deneyimlerimden birkaç örnekle bu iki yaklaşımın nasıl uygulandığını ve ne gibi sonuçlar verdiğini aktarayım.

Bir üretim ERP sistemi üzerinde çalışırken, uygulamanın boyutu ciddi bir sorun haline gelmişti. Temel modül, çeşitli üretim süreçlerini, tedarik zinciri yönetimini ve finansal modülleri içeriyordu. İlk indirme boyutu epey kabarıktı. Bu boyutu düşürmek için öncelikle R8’i etkinleştirdik ve kapsamlı keep rules ayarları yaptık. Bu işlem sonucunda boyut belirgin biçimde azaldı. Bu, ilk adımdı ve önemli bir iyileşme sağladı.

Ancak, ERP’nin bazı gelişmiş modülleri (örneğin, detaylı makine bakım planlama, ileri seviye ERP entegrasyonları) tüm kullanıcılar tarafından kullanılmıyordu ve oldukça büyüktü. Bu modülleri dinamik özellik modülleri olarak ayırmaya karar verdik. Ana uygulamaya bu modüllerin indirme ve kurulum mekanizmalarını entegre ettik. Sonuç olarak, temel ERP uygulaması belirgin ölçüde küçülürken, kullanıcılar yalnızca ihtiyaç duydukları ek modülleri indirme seçeneğine sahip oldu. Bu, yeni kullanıcıların uygulamayı indirme oranını da gözle görülür biçimde artırdı.

Başka bir örnek, Android üzerinde geliştirdiğim bir finansal hesaplayıcı uygulamasıydı. Başlangıçta, çeşitli finansal tablolar ve hesaplama motorları için bir dizi kütüphane kullanıyordum. R8 optimizasyonları ile boyutu kayda değer ölçüde indirmeyi başardım. Ancak, uygulamanın içinde çeşitli ülkelerin vergi tabloları ve özel hesaplama kuralları bulunuyordu. Tüm bunları başlangıçta dahil etmek, boyutu gereksiz yere artırıyordu. Bu nedenle, kullanıcıların konumuna veya seçtiği ülkeye göre ilgili vergi tablolarını ve hesaplama kurallarını dinamik olarak indirecek bir mekanizma ekledim. Bu, başlangıç boyutunu daha da küçülttü ve kullanıcılara daha hızlı bir ilk deneyim sundu.

Genel önerilerim şunlar:

  1. Her zaman R8/ProGuard’ı etkinleştirin: Android geliştiriyorsanız, minifyEnabled true ayarını mutlaka kullanın. iOS’ta da derleyici optimizasyonlarını aktif tutun.
  2. Kullanılmayan kodları temizleyin: Bağımlılıklarınızı düzenli olarak gözden geçirin ve artık kullanmadığınız kütüphaneleri veya modülleri kaldırın.
  3. Görsel varlıkları optimize edin: Görselleri doğru formatta (WebP gibi) ve uygun çözünürlükte kullanın. Gerekirse görselleri sıkıştırın.
  4. Büyük özellikleri dinamik modüllere taşıyın: Uygulamanızın boyutu 50 MB’ın üzerindeyse ve belirli özellikler tüm kullanıcılar tarafından kullanılmıyorsa, bu özellikleri dinamik modüllere taşımayı ciddi olarak düşünün.
  5. Test edin, test edin, test edin: Optimizasyonlar ve dinamik modüller, uygulamanın stabilitesini etkileyebilir. Herhangi bir değişiklik yaptıktan sonra kapsamlı testler yapın.
  6. Kullanıcı deneyimini ön planda tutun: Boyut optimizasyonu yaparken, uygulamanın hızını, kararlılığını ve genel kullanıcı deneyimini olumsuz etkilememesine özen gösterin.

Sonuç: Boyut ve Esneklik Dengesi

Mobil uygulama boyutu, kullanıcıların uygulamanızı indirme ve kullanma kararlarını etkileyen kritik bir faktördür. Derleme zamanı optimizasyonları, uygulamanın temelini küçültmek için güçlü bir araç seti sunarken, dinamik paketleme stratejileri, büyük ve karmaşık uygulamalar için esneklik ve daha iyi bir ilk kullanıcı deneyimi sağlar.

En iyi yaklaşım genellikle bu iki yöntemin akıllıca bir kombinasyonunu kullanmaktır. Uygulamanızın mimarisini, hedef kitlenizi ve özellik setinizi göz önünde bulundurarak, hangi stratejilerin sizin için en uygun olduğunu belirleyebilirsiniz. Unutmayın ki, uygulama boyutu optimizasyonu tek seferlik bir görev değil, sürekli devam eden bir süreçtir. Yeni özellikler eklendikçe ve kütüphaneler güncellendikçe, boyut optimizasyonunu düzenli olarak gözden geçirmek, kullanıcılarınıza en iyi deneyimi sunmanın anahtarı olacaktır.

Paylaş:

Bu yazı faydalı oldu mu?

Yükleniyor...

Bu yazı nasıldı?

Sıkça Sorulanlar

Bu makale ile ilgili okurların sorduğu yaygın sorular.

Derleme zamanında boyut optimizasyonuna nasıl başlıyorum ve hangi araçları tercih etmeliyim?
Ben ilk projelerimde sadece Gradle dosyasını değiştirmekle yetindim, fakat gerçek tasarrufu R8 ve ProGuard gibi shrinker'ları etkinleştirerek elde ettim. Öncelikle `minifyEnabled true` ve `shrinkResources true` ayarlarını `build.gradle` içinde açıyorum, ardından `proguard-rules.pro` dosyasına gereksiz paketleri dışlayan kurallar ekliyorum. Ayrıca `android.enableR8.fullMode=true` ile R8'in tam modunu etkinleştiriyorum; bu sayede dead code ve resource'lar otomatik olarak atılıyor. Test aşamasında APK Analyzer ile boyut farkını ölçmek, hangi sınıfların silindiğini görmek çok faydalı. Bu adımları takip ederek ilk denememde belirgin bir küçülme sağladım.
Dinamik paketleme kullanırken performans maliyeti nedir, build-time optimizasyonla karşılaştırıldığında avantajları ve dezavantajları?
Dinamik paketleme (ör. Android App Bundle) benim için en büyük avantajı, cihaz bazlı modüllerin sadece ihtiyaç duyulan kısmını indirmesi, bu da kullanıcıların indirme süresini belirgin biçimde kısaltıyor. Ancak runtime’da modül yükleme gecikmesi ve ağ hatalarına karşı ek kod yazmam gerekti; bu da başlangıç performansını kısa bir süre yavaşlatabiliyor. Build‑time optimizasyonu ise sabit bir APK sunar, her cihaz aynı dosyayı alır, bu yüzden yükleme anında ekstra bir gecikme olmaz ama tüm kaynakları içerdiği için boyut her zaman daha büyük olur. Projemde, sık kullanılan UI bileşenlerini base module’da tutup, nadir kullanılan özellikleri dinamik modül olarak ayırdım; böylece hem boyut hem de performans dengesini sağladım.
Derleme aşamasında R8/ProGuard ile sorun yaşarsam ne yapmalıyım ve kaç deneme gerekir?
R8 ile ilk kez karşılaştığım bir hata, bazı reflection‑tabanlı kütüphanelerin sınıflarının silinmesiydi. Ben hatayı alınca `-keep` kurallarını `proguard-rules.pro` dosyasına ekleyerek çözdüm. Genelde birkaç deneme yeterli oluyor; önce hatayı tespit edip logları incelemek, ardından ilgili sınıfları korumak, son olarak bütün test senaryolarını çalıştırmak yeterli. Hata mesajları genellikle “ClassNotFoundException” şeklinde gelir, bu da eksik keep kuralının işareti. Ayrıca `./gradlew assembleDebug --stacktrace` komutuyla ayrıntılı log alıp, hangi paketlerin etkilendiğini görebiliyorum. Bu süreci otomatikleştirmek için CI pipeline'ına bir APK Analyzer adımı eklemeyi de öneriyorum.
Uygulama boyutunu küçültmek için sadece kodu küçültmek yeterli mi, kaynak dosyaları ve native kütüphaneler de aynı derecede önemli mi?
Benim deneyimime göre kod küçültme tek başına %20‑30’luk bir iyileşme sağlar, fakat resimler, fontlar ve native .so dosyaları toplam boyutun %50‑60’ını oluşturabilir. Bu yüzden `shrinkResources` ile kullanılmayan drawable’ları kaldırmak, WebP formatına geçmek ve `android:extractNativeLibs=false` ayarıyla native kütüphaneleri sıkıştırmak kritik. Ayrıca, farklı ABI’ler için ayrı APK’lar üretmek (split APK) sayesinde her cihaz sadece ihtiyacı olan .so dosyasını alır, bu da kayda değer bir tasarruf sağlar. Projemde bu üç katmanı birleştirerek toplamda belirgin bir boyut düşüşü elde ettim; dolayısıyla tam bir optimizasyon için kod, kaynak ve native bileşenlerin hepsine odaklanmak şart.
ME

Mustafa Erbay

Sistem Mimarisi · Network Uzmanı · Altyapı, Güvenlik ve Yazılım

2006'dan bu yana sistem mimarisi, network, sunucu altyapıları, büyük yapıların kurulumu, yazılım ve sistem güvenliği ekseninde çalışıyorum. Bu blogda sahada karşılığı olan teknik deneyimlerimi paylaşıyorum.

Kişisel Notlar

Bu notlar sadece sizde saklanır. Tarayıcınızda yerel olarak tutulur.

Hazır 0 karakter

Yorumlar

Sunucu Taraflı AI Moderasyon

Yorumlar sunucuda yapay zeka ile denetlenir ve kalıcı olarak saklanır.

?
0/2000

Sunucu taraflı AI denetim

✉️ Ücretsiz · Spam yok · İstediğin an çık

Yeni yazılardan haberdar olun

Yeni içerikler ve teknik notlar e-postanıza gelsin.

  • 📌
    Haftanın en iyisi Sadece okumaya değer tek yazı
  • 🔧
    Alet çantası Bu hafta kullandığım araçlar
  • 🧠
    Perde arkası Blog'a girmeyen notlar

Spam yapmıyoruz. İstediğiniz zaman ayrılabilirsiniz. · Sadece Umami (self-hosted, Google yok) ile takip.

Okuma İstatistikleriniz

0

Yazı Okundu

0dk

Okuma Süresi

0

Gün Serisi

-

Favori Kategori

İlgili Yazılar