Uygulamanızı mümkün olduğunca küçük ve hızlı hale getirmek için isMinifyEnabled = true
ile sürüm derlemenizi optimize etmeniz ve küçültmeniz gerekir.
Bu sayede, kullanılmayan kodları kaldıran küçültme, uygulamanızın sınıf ve üyelerinin adlarını kısaltan karartma ve uygulamanızın boyutunu daha da küçültmek ve performansını artırmak için gelişmiş kod optimizasyon stratejileri uygulayan optimizasyon etkinleştirilir. Bu sayfada, R8'in projeniz için bu derleme zamanı görevlerini nasıl gerçekleştirdiği ve bunları nasıl özelleştirebileceğiniz açıklanmaktadır.
Projenizi Android Gradle eklentisi 3.4.0 veya sonraki bir sürümü kullanarak derlediğinizde eklenti artık derleme zamanında kod optimizasyonu yapmak için ProGuard'ı kullanmaz. Bunun yerine, aşağıdaki derleme zamanı görevlerini gerçekleştirmek için R8 derleyicisiyle çalışır:
- Kod küçültme (veya ağaç sallama): Uygulamanızdan ve kitaplık bağımlılıklarınızdan kullanılmayan sınıfları, alanları, yöntemleri ve özellikleri tespit edip güvenli bir şekilde kaldırır (bu da 64 bin referans sınırını aşmak için değerli bir araç haline getirir). Örneğin, bir kitaplık bağımlılığının yalnızca birkaç API'sini kullanıyorsanız küçültme işlemi, uygulamanızın kullanmadığı kitaplık kodunu tespit edip yalnızca bu kodu uygulamanızdan kaldırabilir. Daha fazla bilgi edinmek için kodunuzu küçültme ile ilgili bölüme gidin.
- Kaynak küçültme: Uygulamanızın kitaplık bağımlılıklarındaki kullanılmayan kaynaklar da dahil olmak üzere, paketlenmiş uygulamanızdan kullanılmayan kaynakları kaldırır. Kod küçültmeyle birlikte çalışır. Böylece, kullanılmayan kod kaldırıldıktan sonra artık referans verilmeyen tüm kaynaklar da güvenli bir şekilde kaldırılabilir. Daha fazla bilgi edinmek için kaynaklarınızı küçültme ile ilgili bölüme gidin.
- Optimizasyon: Çalışma zamanı performansını artırmak ve uygulamanızın DEX dosyalarının boyutunu daha da küçültmek için kodunuzu inceler ve yeniden yazar. Bu, kodun çalışma zamanı performansını %30'a varan oranda iyileştirerek başlatma ve kare zamanlamasını önemli ölçüde iyileştirir. Örneğin, R8 belirli bir if/else ifadesinin
else {}
dalının hiçbir zaman alınmadığını algılarsaelse {}
dalının kodunu kaldırır. Daha fazla bilgi edinmek için kod optimizasyonu ile ilgili bölüme gidin. - Gizleme (veya tanımlayıcı küçültme): Sınıfların ve üyelerin adını kısaltarak DEX dosya boyutlarını küçültür. Daha fazla bilgi edinmek için kodunuzu karartma ile ilgili bölüme gidin.
Uygulamanızın sürümünü derlediğinizde R8, yukarıda açıklanan derleme zamanı görevlerini sizin için gerçekleştirecek şekilde yapılandırılabilir. Ayrıca ProGuard kural dosyalarını kullanarak belirli görevleri devre dışı bırakabilir veya R8'in davranışını özelleştirebilirsiniz. Aslında R8, mevcut tüm ProGuard kural dosyalarınızla çalışır. Bu nedenle, Android Gradle eklentisini R8'i kullanacak şekilde güncellemek için mevcut kurallarınızı değiştirmeniz gerekmez.
Kod küçültme, kod karartma ve optimizasyonu etkinleştirme
Android Studio 3.4 veya Android Gradle eklentisi 3.4.0 ve sonraki sürümleri kullandığınızda R8, projenizin Java bayt kodunu Android platformunda çalışan DEX biçimine dönüştüren varsayılan derleyicidir. Ancak Android Studio'yu kullanarak yeni bir proje oluşturduğunuzda sıkıştırma, karartma ve kod optimizasyonu varsayılan olarak etkinleştirilmez. Bunun nedeni, bu derleme zamanı optimizasyonlarının projenizin derleme süresini artırması ve kaldırılacak kodu yeterince özelleştirmezseniz hatalara neden olabilmesidir.
Bu nedenle, derleme zamanındaki bu görevleri, uygulamanızın yayınlanmadan önce test ettiğiniz nihai sürümünü oluştururken etkinleştirmeniz en iyisidir. Sıkıştırma, karartma ve optimizasyonu etkinleştirmek için proje düzeyinde derleme komut dosyanıza aşağıdakileri ekleyin.
Kotlin
android { buildTypes { getByName("release") { // Enables code shrinking, obfuscation, and optimization for only // your project's release build type. Make sure to use a build // variant with `isDebuggable=false`. isMinifyEnabled = true // Enables resource shrinking, which is performed by the // Android Gradle plugin. isShrinkResources = true proguardFiles( // Includes the default ProGuard rules files that are packaged with // the Android Gradle plugin. To learn more, go to the section about // R8 configuration files. getDefaultProguardFile("proguard-android-optimize.txt"), // Includes a local, custom Proguard rules file "proguard-rules.pro" ) } } ... }
Groovy
android { buildTypes { release { // Enables code shrinking, obfuscation, and optimization for only // your project's release build type. Make sure to use a build // variant with `debuggable false`. minifyEnabled true // Enables resource shrinking, which is performed by the // Android Gradle plugin. shrinkResources true // Includes the default ProGuard rules files that are packaged with // the Android Gradle plugin. To learn more, go to the section about // R8 configuration files. proguardFiles getDefaultProguardFile( 'proguard-android-optimize.txt'), 'proguard-rules.pro' } } ... }
R8 yapılandırma dosyaları
R8, varsayılan davranışını değiştirmek ve uygulamanızın yapısını (ör. uygulamanızın koduna giriş noktası olarak hizmet eden sınıflar) daha iyi anlamak için ProGuard kural dosyalarını kullanır. Bu kural dosyalarının bazılarını değiştirebilseniz de bazı kurallar AAPT2 gibi derleme zamanı araçları tarafından otomatik olarak oluşturulabilir veya uygulamanızın kitaplık bağımlılıkları tarafından devralınabilir. Aşağıdaki tabloda, R8'in kullandığı ProGuard kuralları dosyalarının kaynakları açıklanmaktadır.
Kaynak | Konum | Açıklama |
Android Studio | <module-dir>/proguard-rules.pro
|
Android Studio'yu kullanarak yeni bir modül oluşturduğunuzda IDE, söz konusu modülün kök dizininde bir proguard-rules.pro dosyası oluşturur.
Varsayılan olarak bu dosyada herhangi bir kural uygulanmaz. Bu nedenle, özel saklama kurallarınız gibi kendi ProGuard kurallarınızı buraya ekleyin. |
Android Gradle eklentisi | Derleme sırasında Android Gradle eklentisi tarafından oluşturulur. | Android Gradle eklentisi, çoğu Android projesi için yararlı olan ve @Keep*
ek açıklamaları etkinleştiren kurallar içeren proguard-android-optimize.txt dosyasını oluşturur.
Android Studio'yu kullanarak yeni bir modül oluşturduğunuzda modül düzeyindeki derleme komut dosyası, bu kurallar dosyasını varsayılan olarak sürüm derlemenize dahil eder.
Not: Android Gradle eklentisi, önceden tanımlanmış ek ProGuard kural dosyaları içerir ancak |
Kitaplık bağımlılıkları |
AAR kitaplığında:
JAR kitaplığında: Android Gradle eklentisi 3.6 veya sonraki sürümler, bu konumlara ek olarak hedefli sıkıştırma kurallarını da destekler. |
Bir AAR veya JAR kitaplığı kendi kuralları dosyasıyla yayınlanırsa ve bu kitaplığı derleme zamanındaki bir bağımlılık olarak eklerseniz R8, projenizi derlerken bu kuralları otomatik olarak uygular. Android Gradle eklentisi 3.6 veya sonraki sürümler, geleneksel ProGuard kurallarına ek olarak hedefli sıkıştırma kurallarını da destekler. Bunlar, belirli sıkıştırıcıları (R8 veya ProGuard) ve belirli sıkıştırıcı sürümlerini hedefleyen kurallardır. Kitaplığın düzgün çalışması için belirli kuralların gerekli olduğu durumlarda, kitaplıklarla birlikte paketlenmiş kural dosyalarını kullanmak faydalıdır. Yani kitaplık geliştiricisi, sorun giderme adımlarını sizin için gerçekleştirmiştir. Ancak kurallar toplayıcı olduğundan, bir kitaplık bağımlılığının içerdiği belirli kuralların kaldırılamayacağını ve uygulamanızın diğer bölümlerinin derlenmesini etkileyebileceğini unutmayın. Örneğin, bir kitaplık kod optimizasyonlarını devre dışı bırakma kuralını içeriyorsa bu kural, projenizin tamamı için optimizasyonları devre dışı bırakır. |
Android Öğe Paketleme Aracı 2 (AAPT2) | Projenizi minifyEnabled true ile oluşturduktan sonra:
<module-dir>/build/intermediates/aapt_proguard_file/.../aapt_rules.txt
|
AAPT2, uygulamanızın manifest dosyasında, düzenlerinde ve diğer uygulama kaynaklarındaki sınıflara yapılan referanslara göre tutma kuralları oluşturur. Örneğin, AAPT2, uygulamanızın manifest dosyasına giriş noktası olarak kaydettiğiniz her etkinlik için bir tutma kuralı içerir. |
Özel yapılandırma dosyaları | Android Studio'yu kullanarak varsayılan olarak yeni bir modül oluşturduğunuzda IDE, kendi kurallarınızı eklemeniz için <module-dir>/proguard-rules.pro oluşturur.
|
Ek yapılandırmalar ekleyebilirsiniz. R8 bunları derleme zamanında uygular. |
minifyEnabled
mülkünü true
olarak ayarladığınızda R8, yukarıda listelenen tüm mevcut kaynaklardaki kuralları birleştirir. Kitaplık bağımlılıkları gibi derleme zamanı bağımlılıkları, R8 davranışında sizin bilmediğiniz değişikliklere neden olabileceğinden R8 ile ilgili sorunları giderirken bunu göz önünde bulundurmanız önemlidir.
Projenizi oluştururken R8'in uyguladığı tüm kuralların tam raporunu almak için modülünüzün proguard-rules.pro
dosyasına aşağıdakileri ekleyin:
// You can specify any path and filename.
-printconfiguration ~/tmp/full-r8-config.txt
Hedeflenen sıkıştırma kuralları
Android Gradle eklentisi 3.6 veya sonraki sürümler, kitaplıkların belirli sıkıştırıcıları (R8 veya ProGuard) ve belirli sıkıştırıcı sürümlerini hedefleyen kurallarını destekler. Bu sayede kitaplık geliştiricileri, kuralları yeni sıkıştırıcı sürümlerini kullanan projelerde optimum şekilde çalışacak şekilde uyarlayabilir. Ayrıca mevcut kuralların, eski sıkıştırıcı sürümlerini kullanan projelerde kullanılmaya devam etmesine izin verilir.
Hedeflenen sıkıştırma kurallarını belirtmek için kitaplık geliştiricilerin, aşağıda açıklandığı gibi bir AAR veya JAR kitaplığının belirli konumlarına eklemesi gerekir.
In an AAR library:
proguard.txt (legacy location)
classes.jar
└── META-INF
└── com.android.tools (targeted shrink rules location)
├── r8-from-<X>-upto-<Y>/<R8-rules-file>
└── proguard-from-<X>-upto-<Y>/<ProGuard-rules-file>
In a JAR library:
META-INF
├── proguard/<ProGuard-rules-file> (legacy location)
└── com.android.tools (targeted shrink rules location)
├── r8-from-<X>-upto-<Y>/<R8-rules-file>
└── proguard-from-<X>-upto-<Y>/<ProGuard-rules-file>
Yani hedeflenen sıkıştırma kuralları, JAR dosyasının META-INF/com.android.tools
dizininde veya AAR dosyasının classes.jar
içindeki META-INF/com.android.tools
dizininde depolanır.
Bu dizin altında, dizinlerdeki kuralların hangi sıkıştırıcının hangi sürümleri için yazıldığını belirtmek üzere r8-from-<X>-upto-<Y>
veya proguard-from-<X>-upto-<Y>
biçiminde adlara sahip birden fazla dizin bulunabilir.
-from-<X>
ve -upto-<Y>
bölümlerinin isteğe bağlı olduğunu, <Y>
sürümünün özel olduğunu ve sürüm aralıklarının kesintisiz olması gerektiğini unutmayın.
Örneğin, r8-upto-8.0.0
, r8-from-8.0.0-upto-8.2.0
ve r8-from-8.2.0
geçerli bir hedeflenen küçültme kuralı grubu oluşturur. r8-from-8.0.0-upto-8.2.0
dizinindeki kurallar, R8 tarafından 8.0.0 sürümünden 8.2.0 sürümüne kadar ancak 8.2.0 sürümünü içermeden kullanılır.
Bu bilgiler doğrultusunda, Android Gradle eklentisi 3.6 veya sonraki sürümler, eşleşen R8 dizinlerinden kuralları seçer. Bir kitaplıkta hedeflenen sıkıştırma kuralları belirtilmezse Android Gradle eklentisi, kuralları eski konumlardan (AAR için proguard.txt
veya JAR için META-INF/proguard/<ProGuard-rules-file>
) seçer.
Kitaplık geliştiriciler, kitaplıklarına hedeflenen sıkıştırma kurallarını veya eski ProGuard kurallarını ya da 3.6'dan eski Android Gradle eklentisiyle veya diğer araçlarla uyumluluğu korumak istiyorlarsa her iki türü de eklemeyi seçebilir.
Ek yapılandırmalar ekleme
Android Studio'yu kullanarak yeni bir proje veya modül oluşturduğunuzda IDE, kendi kurallarınızı ekleyebileceğiniz bir <module-dir>/proguard-rules.pro
dosyası oluşturur. Diğer dosyalardaki ek kuralları, modülünüzün derleme komut dosyasında proguardFiles
özelliğine ekleyerek de dahil edebilirsiniz.
Örneğin, ilgili productFlavor
bloğuna başka bir proguardFiles
mülkü ekleyerek her derleme varyantına özel kurallar ekleyebilirsiniz. Aşağıdaki Gradle dosyası, flavor2
ürün çeşidine flavor2-rules.pro
ekler.
Artık flavor2
, release
bloğundakiler de uygulandığı için üç ProGuard kuralını da kullanıyor.
Ayrıca, yalnızca test APK'sına dahil edilen ProGuard dosyalarının listesini belirten testProguardFiles
mülkünü ekleyebilirsiniz:
Kotlin
android { ... buildTypes { getByName("release") { isMinifyEnabled = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), // List additional ProGuard rules for the given build type here. By default, // Android Studio creates and includes an empty rules file for you (located // at the root directory of each module). "proguard-rules.pro" ) testProguardFiles( // The proguard files listed here are included in the // test APK only. "test-proguard-rules.pro" ) } } flavorDimensions.add("version") productFlavors { create("flavor1") { ... } create("flavor2") { proguardFile("flavor2-rules.pro") } } }
Groovy
android { ... buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), // List additional ProGuard rules for the given build type here. By default, // Android Studio creates and includes an empty rules file for you (located // at the root directory of each module). 'proguard-rules.pro' testProguardFiles // The proguard files listed here are included in the // test APK only. 'test-proguard-rules.pro' } } flavorDimensions "version" productFlavors { flavor1 { ... } flavor2 { proguardFile 'flavor2-rules.pro' } } }
Kodunuzu küçültme
minifyEnabled
mülkünü true
olarak ayarladığınızda R8 ile kod küçültme varsayılan olarak etkinleştirilir.
Kod küçültme (ağaç sallama olarak da bilinir), R8'in çalışma zamanında gerekli olmadığını belirlediği kodların kaldırılması işlemidir. Örneğin, uygulamanız birçok kitaplık bağımlılığı içeriyor ancak bu kitaplıkların işlevlerinin yalnızca küçük bir kısmını kullanıyorsa bu işlem uygulamanızın boyutunu önemli ölçüde azaltabilir.
R8, uygulamanızın kodunu küçültmek için önce birleştirilmiş yapılandırma dosyası grubuna göre uygulamanızın koduna tüm giriş noktalarını belirler. Bu giriş noktaları, Android platformunun uygulamanızın etkinliklerini veya hizmetlerini açmak için kullanabileceği tüm sınıfları içerir. R8, her giriş noktasından başlayarak uygulamanızın kodunda inceleme yapar. Böylece uygulamanızın çalışma zamanında erişebileceği tüm yöntemlerin, üye değişkenlerinin ve diğer sınıfların grafiğini oluşturur. Bu grafiğe bağlı olmayan kodlar erişilemez olarak kabul edilir ve uygulamadan kaldırılabilir.
Şekil 1'de, çalışma zamanı kitaplığı bağımlılığı olan bir uygulama gösterilmektedir. R8, uygulamanın kodunu incelerken foo()
, faz()
ve bar()
yöntemlerinin MainActivity.class
giriş noktasından erişilebilir olduğunu belirler. Ancak OkayApi.class
sınıfı veya baz()
yöntemi, uygulamanız tarafından çalışma zamanında hiçbir zaman kullanılmaz ve R8, uygulamanızı küçütürken bu kodu kaldırır.
R8, projenin R8 yapılandırma dosyalarındaki -keep
kuralları aracılığıyla giriş noktalarını belirler. Diğer bir deyişle, koruma kuralları, R8'in uygulamanızı küçütürken atmaması gereken sınıfları belirtir ve R8 bu sınıfları uygulamanıza olası giriş noktaları olarak kabul eder. Android Gradle eklentisi ve AAPT2, çoğu uygulama projesinin sizin için ihtiyaç duyduğu koruma kurallarını (ör. uygulamanızın etkinlikleri, görünümleri ve hizmetleri) otomatik olarak oluşturur. Ancak bu varsayılan davranışı ek saklama kurallarıyla özelleştirmeniz gerekiyorsa hangi kodun saklanacağını özelleştirme ile ilgili bölümü okuyun.
Bunun yerine yalnızca uygulamanızın kaynaklarının boyutunu küçültmek istiyorsanız kaynaklarınızı küçültme ile ilgili bölüme atlayın.
Bir kitaplık projesi küçültülürse bu kitaplığa bağlı uygulamaların küçültülmüş kitaplık sınıflarını içerdiğini unutmayın. Kitaplık APK'sında eksik sınıflar varsa kitaplık saklama kurallarını ayarlamanız gerekebilir. AAR biçiminde bir kitaplık oluşturup yayınlıyorsanız kitaplığınızın bağlı olduğu yerel JAR dosyaları AAR dosyasında küçültülmez.
Hangi kodun saklanacağını özelleştirme
Çoğu durumda, R8'in yalnızca kullanılmayan kodu kaldırması için varsayılan ProGuard kuralları dosyası (proguard-android-optimize.txt
) yeterlidir. Ancak bazı durumların R8 tarafından doğru şekilde analiz edilmesi zordur ve uygulamanızın gerçekten ihtiyaç duyduğu kodları kaldırabilir. Kodun yanlışlıkla kaldırılmasına neden olabilecek bazı durumlar:
- Uygulamanız Java Native Interface'tan (JNI) bir yöntem çağırdığında
- Uygulamanız çalışma zamanında kod aradığında (yansıtma gibi)
Uygulamanızı test ettiğinizde, uygunsuz şekilde kaldırılan koddan kaynaklanan hataları görebilirsiniz. Ayrıca, kaldırılan kodla ilgili bir rapor oluşturarak hangi kodun kaldırıldığını da inceleyebilirsiniz.
Hataları düzeltmek ve R8'i belirli bir kodu tutmaya zorlamak için ProGuard kurallar dosyasına bir -keep
satırı ekleyin. Örnek:
-keep public class MyClass
Alternatif olarak, @Keep
ek açıklamasını, korumak istediğiniz koda ekleyebilirsiniz. Bir sınıfa @Keep
eklendiğinde sınıfın tamamı olduğu gibi kalır. Bir yönteme veya alana eklendiğinde ise sınıf adı gibi yöntem/alan (ve adı) da olduğu gibi kalır. Bu ek açıklamanın yalnızca AndroidX Annotations Library kullanılırken ve küçültmeyi etkinleştirme ile ilgili bölümde açıklandığı gibi Android Gradle eklentisiyle paketlenmiş ProGuard kuralları dosyasını eklediğinizde kullanılabileceğini unutmayın.
-keep
seçeneğini kullanırken dikkate almanız gereken birçok nokta vardır. Kural dosyanızı özelleştirme hakkında daha fazla bilgi için ProGuard Kılavuzu'nu okuyun.
Sorun giderme bölümünde, kodunuz kaldırıldığında karşılaşabileceğiniz diğer yaygın sorunlar özetlenmiştir.
Yerel kitaplıkları kaldırma
Yerel kod kitaplıkları, varsayılan olarak uygulamanızın sürüm derlemelerinde soyulur. Bu soyma işlemi, uygulamanız tarafından kullanılan tüm yerel kitaplıklardaki simge tablosunun ve hata ayıklama bilgilerinin kaldırılmasını içerir. Yerel kod kitaplıklarının soyulması, önemli ölçüde boyut tasarrufu sağlar ancak eksik bilgiler (ör. sınıf ve işlev adları) nedeniyle Google Play Console'da kilitlenmelerin teşhis edilmesi imkansızdır.
Yerel kilitlenme desteği
Google Play Console, yerel kilitlenmeleri Android vitals altında raporlar. Birkaç adımda uygulamanız için yerel hata ayıklama sembolleri dosyası oluşturabilir ve yükleyebilirsiniz. Bu dosya, uygulamanızı üretimde hata ayıklamaya yardımcı olmak için Android hayati verilerinde simgeselleştirilmiş yerel kilitlenme yığın izlemelerini (sınıf ve işlev adlarını içerir) etkinleştirir. Bu adımlar, projenizde kullanılan Android Gradle eklentisinin sürümüne ve projenizin derleme çıkışına göre değişir.
Android Gradle eklentisi 4.1 veya sonraki sürümleri
Projeniz Android App Bundle derliyorsa yerel hata ayıklama simgeleri dosyasını otomatik olarak buna ekleyebilirsiniz. Bu dosyayı yayın sürümlerine dahil etmek için uygulamanızın build.gradle.kts
dosyasına aşağıdakileri ekleyin:
android.buildTypes.release.ndk.debugSymbolLevel = { SYMBOL_TABLE | FULL }
Aşağıdakiler arasından hata ayıklama sembolü düzeyini seçin:
- Play Console'un sembolize edilmiş yığın izlemelerinde işlev adlarını almak için
SYMBOL_TABLE
simgesini kullanın. Bu düzeyde mezar taşları desteklenir. - Play Console'un simgelenmiş yığın izlemelerinde işlev adlarını, dosyaları ve satır numaralarını almak için
FULL
öğesini kullanın.
Projeniz APK derliyorsa yerel hata ayıklama simgeleri dosyasını ayrı olarak oluşturmak için daha önce gösterilen build.gradle.kts
derleme ayarını kullanın. Yerel hata ayıklama simgeleri dosyasını Google Play Console'a manuel olarak yükleyin. Android Gradle eklentisi, derleme işleminin bir parçası olarak bu dosyayı aşağıdaki proje konumuna çıkarır:
app/build/outputs/native-debug-symbols/variant-name/native-debug-symbols.zip
Android Gradle eklentisi 4.0 ve önceki sürümler (ayrıca diğer derleme sistemleri)
Android Gradle eklentisi, derleme işleminin bir parçası olarak, sadeleştirilmemiş kitaplıkların kopyasını proje dizininde saklar. Bu dizin yapısı aşağıdakine benzer:
app/build/intermediates/cmake/universal/release/obj/
├── armeabi-v7a/
│ ├── libgameengine.so
│ ├── libothercode.so
│ └── libvideocodec.so
├── arm64-v8a/
│ ├── libgameengine.so
│ ├── libothercode.so
│ └── libvideocodec.so
├── x86/
│ ├── libgameengine.so
│ ├── libothercode.so
│ └── libvideocodec.so
└── x86_64/
├── libgameengine.so
├── libothercode.so
└── libvideocodec.so
Bu dizinin içeriğini zip dosyası olarak kaydedin:
cd app/build/intermediates/cmake/universal/release/obj
zip -r symbols.zip .
symbols.zip
dosyasını Google Play Console'a manuel olarak yükleyin.
Kaynaklarınızı küçültme
Kaynak daraltma yalnızca kod daraltma ile birlikte çalışır. Kod küçültücü, kullanılmayan tüm kodları kaldırdıktan sonra kaynak küçültücü, uygulamanın hâlâ hangi kaynakları kullandığını belirleyebilir. Bu durum özellikle kaynak içeren kod kitaplıkları eklediğinizde geçerlidir. Kitaplık kaynaklarının referanslarının kaldırılması ve böylece kaynak sıkıştırıcı tarafından kaldırılabilmesi için kullanılmayan kitaplık kodunu kaldırmanız gerekir.
Kaynak küçültmeyi etkinleştirmek için derleme komut dosyanızda shrinkResources
özelliğini true
olarak ayarlayın (kod küçültme için minifyEnabled
ile birlikte). Örnek:
Kotlin
android { ... buildTypes { getByName("release") { isShrinkResources = true isMinifyEnabled = true proguardFiles( getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" ) } } }
Groovy
android { ... buildTypes { release { shrinkResources true minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } }
Uygulamanızı kod küçültme için minifyEnabled
kullanarak oluşturmadıysanız shrinkResources
'ü etkinleştirmeden önce bunu deneyin. Çünkü kaynakları kaldırmaya başlamadan önce dinamik olarak oluşturulan veya çağrılan sınıfları ya da yöntemleri korumak için proguard-rules.pro
dosyanızı düzenlemeniz gerekebilir.
Hangi kaynakların saklanacağını özelleştirme
Saklamak veya silmek istediğiniz belirli kaynaklar varsa projenizde <resources>
etiketi içeren bir XML dosyası oluşturun ve saklanacak her kaynağı tools:keep
özelliğinde, silecek her kaynağı ise tools:discard
özelliğinde belirtin. Her iki özellik de kaynak adlarının virgülle ayrılmış bir listesini kabul eder. Yıldız işaretini joker karakter olarak kullanabilirsiniz.
Örnek:
<?xml version="1.0" encoding="utf-8"?> <resources xmlns:tools="http://schemas.android.com/tools" tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*" tools:discard="@layout/unused2" />
Bu dosyayı proje kaynaklarınıza (ör. res/raw/my.package.keep.xml
) kaydedin. Derleme bu dosyayı uygulamanıza paketlemez.
Not: keep
dosyası için benzersiz bir ad kullandığınızdan emin olun. Farklı kitaplıklar birbirine bağlandığında, saklama kuralları çakışır ve yoksayılan kurallar veya gereksiz şekilde saklanan kaynaklarla ilgili olası sorunlara neden olur.
Silebilirsiniz ancak hangi kaynakların atılacağı belirtmek saçma gelebilir. Ancak bu, derleme varyantları kullanırken yararlı olabilir. Örneğin, tüm kaynaklarınızı ortak proje dizinine koyabilir, ardından belirli bir kaynağın kodda kullanıldığını (ve bu nedenle sıkıştırıcı tarafından kaldırılmadığını) ancak söz konusu derleme varyantında kullanılmayacağını bildiğiniz her derleme varyantı için farklı bir my.package.build.variant.keep.xml
dosyası oluşturabilirsiniz. Derleme araçlarının bir kaynağı gerektiği gibi yanlış tanımlaması da mümkündür. Bu durum, derleyicinin kaynak kimliklerini satır içi olarak eklemesi nedeniyle ortaya çıkabilir. Ardından kaynak analizörü, gerçekten referans verilen bir kaynak ile koddaki aynı değere sahip bir tam sayı değeri arasındaki farkı bilmeyebilir.
Katı referans kontrollerini etkinleştirme
Normalde kaynak sıkıştırıcı, bir kaynağın kullanılıp kullanılmadığını doğru bir şekilde belirleyebilir. Ancak kodunuz
Resources.getIdentifier()
adını çağırıyorsa (veya kitaplıklarınızdan biri bunu yapıyorsa - AppCompat kitaplığı bunu yapar) kodunuz dinamik olarak oluşturulan dizelere göre kaynak adlarını arıyor demektir. Bunu yaptığınızda kaynak sıkıştırıcı varsayılan olarak savunma modunda davranır ve eşleşen bir ad biçimine sahip tüm kaynakları potansiyel olarak kullanılmış ve kaldırılamaz olarak işaretler.
Örneğin, aşağıdaki kod img_
ön ekiyle başlayan tüm kaynakların "kullanıldı" olarak işaretlenmesine neden olur.
Kotlin
val name = String.format("img_%1d", angle + 1) val res = resources.getIdentifier(name, "drawable", packageName)
Java
String name = String.format("img_%1d", angle + 1); res = getResources().getIdentifier(name, "drawable", getPackageName());
Kaynak sıkıştırıcı, kodunuzdaki tüm dize sabitlerinin yanı sıra çeşitli res/raw/
kaynaklarını da inceleyerek file:///android_res/drawable//ic_plus_anim_016.png
'a benzer bir biçimde kaynak URL'leri arar. Bu tür dizeler veya bu tür URL'ler oluşturmak için kullanılabilecek gibi görünen başka dizeler bulursa bunları kaldırmaz.
Bunlar, varsayılan olarak etkin olan güvenli sıkıştırma moduna örnektir.
Ancak bu "emin olmak için önlem almak" işlemini devre dışı bırakabilir ve kaynak sıkıştırıcının yalnızca kullanıldığından emin olduğu kaynakları tutacağını belirtebilirsiniz. Bunu yapmak için keep.xml
dosyasında shrinkMode
değerini aşağıdaki gibi strict
olarak ayarlayın:
<?xml version="1.0" encoding="utf-8"?> <resources xmlns:tools="http://schemas.android.com/tools" tools:shrinkMode="strict" />
Sıkı sıkıştırma modunu etkinleştirirseniz ve kodunuz yukarıda gösterildiği gibi dinamik olarak oluşturulmuş dizelerle kaynaklara da referans verirse bu kaynakları tools:keep
özelliğini kullanarak manuel olarak tutmanız gerekir.
Kullanılmayan alternatif kaynakları kaldırma
Gradle kaynak küçültücü yalnızca uygulama kodunuz tarafından referans verilmeyen kaynakları kaldırır. Yani farklı cihaz yapılandırmaları için
alternatif kaynakları kaldırmaz. Gerekirse, uygulamanızın ihtiyaç duymadığı alternatif kaynak dosyalarını kaldırmak için Android Gradle eklentisinin resConfigs
mülkünü kullanabilirsiniz.
Örneğin, dil kaynakları içeren bir kitaplık (ör. AppCompat veya Google Play Hizmetleri) kullanıyorsanız uygulamanızın geri kalanı aynı dillere çevrilmiş olsun veya olmasın, uygulamanız bu kitaplıklardaki mesajların tüm çevrilmiş dil dizelerini içerir. Yalnızca uygulamanızın resmi olarak desteklediği dilleri tutmak istiyorsanız resConfig
mülkünü kullanarak bu dilleri belirtebilirsiniz. Belirtilmeyen diller için tüm kaynaklar kaldırılır.
Aşağıdaki snippet'te, dil kaynaklarınızı yalnızca İngilizce ve Fransızca ile nasıl sınırlayacağınız gösterilmektedir:
Kotlin
android { defaultConfig { ... resourceConfigurations.addAll(listOf("en", "fr")) } }
Groovy
android { defaultConfig { ... resConfigs "en", "fr" } }
Android App Bundle biçimini kullanarak bir uygulama yayınlarken, uygulama yüklenirken varsayılan olarak yalnızca kullanıcının cihazında yapılandırılmış diller indirilir. Benzer şekilde, indirme işlemine yalnızca cihazın ekran yoğunluğuyla eşleşen kaynaklar ve cihazın ABI'siyle eşleşen yerel kitaplıklar dahil edilir. Daha fazla bilgi için Android Uygulama Paketi yapılandırması bölümüne bakın.
APK ile yayınlanan eski uygulamalarda (Ağustos 2021'den önce oluşturulan), her biri farklı bir cihaz yapılandırmasını hedefleyen birden fazla APK oluşturarak APK'nıza hangi ekran yoğunluğu veya ABI kaynaklarının dahil edileceğini özelleştirebilirsiniz.
Yinelenen kaynakları birleştirme
Gradle varsayılan olarak aynı ada sahip kaynakları (ör. farklı kaynak klasörlerinde bulunabilecek aynı ada sahip çizilebilir öğeler) da birleştirir. Bu davranış, shrinkResources
mülkü tarafından kontrol edilmez ve birden fazla kaynak, kodunuzun aradığı adla eşleştiğinde hataları önlemek için devre dışı bırakılamaz.
Kaynak birleştirme yalnızca iki veya daha fazla dosya aynı kaynak adını, türünü ve tanımlayıcıyı paylaştığı zaman gerçekleşir. Gradle, kopyalar arasında en iyi seçenek olduğunu düşündüğü dosyayı seçer (aşağıda açıklanan öncelik sırasına göre) ve nihai yapıda dağıtılmak üzere AAPT'ye yalnızca bu kaynağı iletir.
Gradle, aşağıdaki konumlarda yinelenen kaynakları arar:
- Ana kaynak kümesiyle ilişkili ana kaynaklar genellikle
src/main/res/
içinde bulunur. - Derleme türü ve derleme sürümlerinden varyant yer paylaşımları.
- Kitaplık projesinin bağımlılıkları.
Gradle, yinelenen kaynakları aşağıdaki basamaklı öncelik sırasına göre birleştirir:
Bağımlılıklar → Ana → Derleme aroması → Derleme türü
Örneğin, hem ana kaynaklarınızda hem de bir derleme çeşidinde yinelenen bir kaynak görünürse Gradle, derleme çeşidindeki kaynağı seçer.
Aynı kaynak grubunda aynı kaynaklar görünüyorsa Gradle bunları birleştiremez ve kaynak birleştirme hatası verir. Bu durum, build.gradle.kts
dosyanızın sourceSet
mülkünde birden fazla kaynak grubu tanımlarsanız (örneğin, hem src/main/res/
hem de src/main/res2/
aynı kaynakları içeriyorsa) ortaya çıkabilir.
Kodunuzu karartma
Kod karartma işleminin amacı, uygulamanızın sınıf, yöntem ve alan adlarını kısaltarak uygulamanızın boyutunu küçültmektir. Aşağıda, R8'in kullanıldığı bir karartma örneği verilmiştir:
androidx.appcompat.app.ActionBarDrawerToggle$DelegateProvider -> a.a.a.b:
androidx.appcompat.app.AlertController -> androidx.appcompat.app.AlertController:
android.content.Context mContext -> a
int mListItemLayout -> O
int mViewSpacingRight -> l
android.widget.Button mButtonNeutral -> w
int mMultiChoiceItemLayout -> M
boolean mShowTitle -> P
int mViewSpacingLeft -> j
int mButtonPanelSideLayout -> K
Kod karartma, uygulamanızdan kod kaldırmasa da birçok sınıf, yöntem ve alanı dizine ekleyen DEX dosyalarına sahip uygulamalarda önemli ölçüde boyut tasarrufu elde edilebilir. Ancak kod karartma, kodunuzun farklı bölümlerini yeniden adlandırdığı için yığın izlemelerini incelemek gibi belirli görevler için ek araçlar gerekir. Karartma işleminden sonra yığın izinizi anlamak için karartılmış yığın izlerinin kodunu çözme ile ilgili bölümü okuyun.
Ayrıca, kodunuz uygulamanızın yöntemleri ve sınıfları için tahmin edilebilir adlandırma kullanıyorsa (ör. yansıma kullanırken) bu imzaları giriş noktası olarak değerlendirmeniz ve hangi kodun saklanacağını özelleştirme ile ilgili bölümde açıklandığı gibi bunlar için saklama kuralları belirtmeniz gerekir. Bu koruma kuralları, R8'e bu kodu yalnızca uygulamanızın nihai DEX'inde tutmakla kalmayıp orijinal adını da korumasını söyler.
Kodu karartılmış yığın izlemenin kodunu çözme
R8, kodunuzu kararttıktan sonra sınıf ve yöntemlerin adları değişmiş olabileceğinden yığın izlemeyi anlamak zordur (imkansız olmasa da). Orijinal yığın izlemeyi almak için yığın izlemeyi yeniden izlemeniz gerekir.
Kod optimizasyonu
R8, uygulamanızı daha da optimize etmek için kullanılmayan daha fazla kodu kaldırmak veya mümkün olduğunda kodunuzu daha az ayrıntılı hale getirmek için kodunuzu daha ayrıntılı bir şekilde inceler. Aşağıda bu tür optimizasyonlara dair birkaç örnek verilmiştir:
- Kodunuz belirli bir if/else ifadesi için hiçbir zaman
else {}
dalını kullanmıyorsa R8,else {}
dalının kodunu kaldırabilir. - Kodunuz bir yöntemi yalnızca birkaç yerde çağırıyorsa R8, yöntemi kaldırıp birkaç çağrı sitesinde satır içi olarak yerleştirebilir.
- R8, bir sınıfın yalnızca tek bir benzersiz alt sınıfa sahip olduğunu ve sınıfın kendisinin örneklenmediğini belirlerse (örneğin, yalnızca bir somut uygulama sınıfı tarafından kullanılan soyut bir temel sınıf) R8 iki sınıfı birleştirebilir ve bir sınıfı uygulamadan kaldırabilir.
- Daha fazla bilgi için Jake Wharton'ın R8 optimizasyon blog yayınlarını okuyun.
R8, ayrı optimizasyonları devre dışı bırakmanıza veya etkinleştirmenize ya da bir optimizasyonun davranışını değiştirmenize izin vermez. Aslında R8, -optimizations
ve -optimizationpasses
gibi varsayılan optimizasyonları değiştirmeye çalışan ProGuard kurallarını yoksayar. Bu kısıtlama önemlidir çünkü R8 iyileşmeye devam ettikçe optimizasyonlar için standart bir davranışın korunması, Android Studio ekibinin karşılaşabileceğiniz sorunları kolayca gidermesine yardımcı olur.
Optimizasyonu etkinleştirmenin, uygulamanızın yığın izlemelerini değiştireceğini unutmayın. Örneğin, içe aktarma işleminde yığın çerçeveleri kaldırılır. Orijinal yığın izleme bilgilerini nasıl alacağınızı öğrenmek için yeniden izleme ile ilgili bölüme bakın.
Çalışma zamanı performansı üzerindeki etkisi
Sıkıştırma, karartma ve optimizasyonun tümü etkinleştirilirse R8, kodun çalışma zamanındaki performansını (kullanıcı arayüzü iş parçacığındaki başlatma ve kare süresi dahil) %30'a varan oranda iyileştirir. Bunlardan herhangi birini devre dışı bırakmak, R8'in kullandığı optimizasyon grubunu önemli ölçüde sınırlandırır.
R8 etkinse daha da iyi bir başlangıç performansı için Başlangıç Profilleri oluşturmanız da gerekir.
Geliştirilmiş optimizasyonları etkinleştirme
R8, ProGuard'dan farklı davranmasını sağlayan bir dizi ek optimizasyon ("tam mod" olarak adlandırılır) içerir. Bu optimizasyonlar, Android Gradle eklentisi 8.0.0 sürümü'nden beri varsayılan olarak etkindir.
Projenizin gradle.properties
dosyasına aşağıdakileri ekleyerek bu ek optimizasyonları devre dışı bırakabilirsiniz:
android.enableR8.fullMode=false
Ek optimizasyonlar R8'in ProGuard'dan farklı davranmasına neden olduğundan, ProGuard için tasarlanmış kurallar kullanıyorsanız çalışma zamanındaki sorunları önlemek için ek ProGuard kuralları eklemeniz gerekebilir. Örneğin, kodunuzun Java Reflection API aracılığıyla bir sınıfa referans verdiğini varsayalım. "Tam mod" kullanılmadığında R8, kodunuzda böyle bir işlem yapılmasa bile çalışma zamanında bu sınıfın nesnelerini incelemek ve değiştirmek istediğinizi varsayar ve sınıfı ve statik başlatıcısını otomatik olarak korur.
Ancak "tam mod" kullanıldığında R8 bu varsayımı yapmaz ve kodunuzun çalışma zamanında sınıfı hiçbir zaman kullanmadığını tespit ederse sınıfı uygulamanızın nihai DEX'inden kaldırır. Yani sınıfı ve statik başlatıcısını korumak istiyorsanız bunu yapmak için kurallar dosyanıza bir keep kuralı eklemeniz gerekir.
R8'in "tam modunu" kullanırken herhangi bir sorunla karşılaşırsanız olası bir çözüm için R8 SSS sayfasına bakın. Sorunu çözemezseniz lütfen hata bildirin.
Yığın izlemelerini yeniden izleme
R8 tarafından işlenen kod, yığın izlemelerinin kaynak koda tam olarak karşılık vermemesi nedeniyle yığın izlemelerinin anlaşılmasını zorlaştırabilecek çeşitli şekillerde değiştirilir. Hata ayıklama bilgileri saklanmadığı zaman satır numaralarında yapılan değişiklikler bu duruma neden olabilir. Bu durum, satır içi ekleme ve ana hat oluşturma gibi optimizasyonlardan kaynaklanabilir. En büyük katkıyı, sınıfların ve yöntemlerin bile adlarının değişeceği karartma sağlar.
R8, orijinal yığın izlemeyi kurtarmak için komut satırı araçları paketiyle birlikte sunulan yeniden izleme komut satırı aracını sağlar.
Uygulamanızın yığın izlemelerinin yeniden izlenmesini desteklemek için modülünüzün proguard-rules.pro
dosyasına aşağıdaki kuralları ekleyerek derlemenin yeniden izleme için yeterli bilgiyi içerdiğinden emin olmanız gerekir:
-keepattributes LineNumberTable,SourceFile
-renamesourcefileattribute SourceFile
LineNumberTable
özelliği, yöntemlerdeki konum bilgilerini, bu konumların yığın izlemelerinde basılması için saklar. SourceFile
özelliği, tüm olası çalışma zamanlarının konum bilgilerini gerçekten yazdırmasını sağlar. -renamesourcefileattribute
yönergesi, yığın izlemelerindeki kaynak dosya adını yalnızca SourceFile
olarak ayarlar. Eşleme dosyası orijinal kaynak dosyayı içerdiğinden, yeniden izleme sırasında gerçek orijinal kaynak dosyası adı gerekmez.
R8 her çalıştırıldığında, yığın izlemelerini orijinal yığın izlemeleriyle eşlemek için gereken bilgileri içeren bir mapping.txt
dosyası oluşturur. Android Studio, dosyayı <module-name>/build/outputs/mapping/<build-type>/
dizinine kaydeder.
Uygulamanızı Google Play'de yayınlarken uygulamanızın her sürümü için mapping.txt
dosyasını yükleyebilirsiniz. Android App Bundle'ı kullanarak yayınlarken bu dosya, uygulama paketi içeriğinin bir parçası olarak otomatik olarak eklenir. Ardından Google Play, kullanıcı tarafından bildirilen sorunlardan gelen yığın izlemelerini geri izleyerek Play Console'da inceleyebilmenizi sağlar. Daha fazla bilgi için kilitlenme yığın izlemelerinin kodunu kaldırma hakkındaki Yardım Merkezi makalesine göz atın.
R8 ile ilgili sorunları giderme
Bu bölümde, R8'i kullanarak sıkıştırma, karartma ve optimizasyonu etkinleştirirken karşılaşılan sorunları gidermeye yönelik bazı stratejiler açıklanmaktadır. Sorununuzun çözümünü aşağıda bulamazsanız R8 SSS sayfasını ve ProGuard'ın sorun giderme kılavuzunu da okuyun.
Kaldırılan (veya tutulan) kodun raporunu oluşturma
Belirli R8 sorunlarını gidermenize yardımcı olması için R8'in uygulamanızdan kaldırdığı tüm kodun raporunu görmek yararlı olabilir. Bu raporu oluşturmak istediğiniz her modül için özel kurallar dosyanıza -printusage <output-dir>/usage.txt
ekleyin. R8'i etkinleştirip uygulamanızı derlediğinizde R8, belirttiğiniz yolu ve dosya adını içeren bir rapor oluşturur. Kaldırılan kodun raporu aşağıdaki gibi görünür:
androidx.drawerlayout.R$attr
androidx.vectordrawable.R
androidx.appcompat.app.AppCompatDelegateImpl
public void setSupportActionBar(androidx.appcompat.widget.Toolbar)
public boolean hasWindowFeature(int)
public void setHandleNativeActionModesEnabled(boolean)
android.view.ViewGroup getSubDecor()
public void setLocalNightMode(int)
final androidx.appcompat.app.AppCompatDelegateImpl$AutoNightModeManager getAutoNightModeManager()
public final androidx.appcompat.app.ActionBarDrawerToggle$Delegate getDrawerToggleDelegate()
private static final boolean DEBUG
private static final java.lang.String KEY_LOCAL_NIGHT_MODE
static final java.lang.String EXCEPTION_HANDLER_MESSAGE_SUFFIX
...
Bunun yerine , R8'in projenizin saklama kurallarına göre belirlediği giriş noktalarının raporunu görmek istiyorsanız özel kurallar dosyanıza -printseeds <output-dir>/seeds.txt
ekleyin. R8'i etkinleştirip uygulamanızı oluşturduğunuzda R8, belirttiğiniz yolu ve dosya adını içeren bir rapor oluşturur. Saklanan giriş noktalarının raporu aşağıdaki gibi görünür:
com.example.myapplication.MainActivity
androidx.appcompat.R$layout: int abc_action_menu_item_layout
androidx.appcompat.R$attr: int activityChooserViewStyle
androidx.appcompat.R$styleable: int MenuItem_android_id
androidx.appcompat.R$styleable: int[] CoordinatorLayout_Layout
androidx.lifecycle.FullLifecycleObserverAdapter
...
Kullanılmayan kaynakları kaldırmayla ilgili sorunları giderme
Kaynakları küçülttüğünüzde Derleme penceresinde, uygulamadan kaldırılan kaynakların bir özeti gösterilir. (Gradle'den ayrıntılı metin çıkışını görüntülemek için önce pencerenin sol tarafındaki Görünümü değiştir'i tıklamanız gerekir.) Örnek:
:android:shrinkDebugResources
Removed unused resources: Resource data reduced from 2570KB to 1711KB: Removed 33%
:android:validateDebugSigning
Gradle ayrıca <module-name>/build/outputs/mapping/release/
(ProGuard'ın çıkış dosyalarıyla aynı klasör) içinde resources.txt
adlı bir teşhis dosyası oluşturur. Bu dosya, hangi kaynakların diğer kaynaklara referans verdiği ve hangi kaynakların kullanıldığı veya kaldırıldığı gibi ayrıntıları içerir.
Örneğin, @drawable/ic_plus_anim_016
dosyasının uygulamanızda neden hâlâ bulunduğunu öğrenmek için resources.txt
dosyasını açıp dosya adını arayın. Aşağıdaki gibi başka bir kaynaktan referans aldığını görebilirsiniz:
16:25:48.005 [QUIET] [system.out] @drawable/add_schedule_fab_icon_anim : reachable=true
16:25:48.009 [QUIET] [system.out] @drawable/ic_plus_anim_016
Artık @drawable/add_schedule_fab_icon_anim
kaynağının neden erişilebilir olduğunu bilmeniz gerekiyor. Yukarı doğru arama yaparsanız kaynağın "Kök erişilebilir kaynaklar şunlardır:" bölümünde listelendiğini görürsünüz. Bu, add_schedule_fab_icon_anim
için bir kod referansı olduğu anlamına gelir (yani, R.drawable kimliği erişilebilir kodda bulunmuştur).
Katı denetim kullanmıyorsanız dinamik olarak yüklenen kaynakların kaynak adlarını oluşturmak için kullanılabilecek gibi görünen dize sabitleri varsa kaynak kimlikleri erişilebilir olarak işaretlenebilir. Bu durumda, kaynak adı için derleme çıkışını ararsanız aşağıdaki gibi bir mesaj görebilirsiniz:
10:32:50.590 [QUIET] [system.out] Marking drawable:ic_plus_anim_016:2130837506
used because it format-string matches string pool constant ic_plus_anim_%1$d.
Bu dizelerden birini görürseniz ve dizenin, belirli bir kaynağı dinamik olarak yüklemek için kullanılmadığından eminseniz tools:discard
özelliğini kullanarak derleme sistemini kaldırmak üzere bilgilendirebilirsiniz. Bu işlem, kaldırılacak kaynakları özelleştirme ile ilgili bölümde açıklanmaktadır.