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 işlem, 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 işlemlerini etkinleştirir. 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, derleme zamanında kod optimizasyonu yapmak için artık 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 tanımlayabilir ve 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 ifadesi için
else {}
kolunun hiç alınmadığını tespit ederse R8,else {}
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ğiniz sırada 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 kullanacak şekilde güncellemek mevcut kurallarınızı değiştirmenizi gerektirmemelidir.
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 veren 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ı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şturuldu. | Android Gradle eklentisi proguard-android-optimize.txt oluşturur. Bu eklenti, çoğu Android projesi için yararlı olan kuralları içerir ve @Keep* ek açıklamaları etkinleştirir.
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ındaki, düzenleri ve diğer uygulama kaynaklarındaki sınıflara yapılan referanslara dayalı olarak saklama 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ı | Varsayılan olarak, Android Studio'yu kullanarak 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 diğer derleme süresi bağımlılıkları, R8 davranışında bilmediğiniz değişikliklere neden olabileceğinden R8 ile ilgili sorunları giderirken bunu aklınızda bulundurmanız önemlidir.
Projenizi oluştururken R8'in geçerli olduğu tüm kuralların tam kapsamlı bir raporunun çıktısını 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
Hedefli daraltma 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, kitaplık geliştiricilerinin kurallarını yeni daraltıcı sürümlerin kullanıldığı projelerde en iyi şekilde çalışacak şekilde uyarlamalarına olanak tanırken, mevcut kuralların eski daraltıcı sürümlere sahip projelerde kullanılmaya devam etmesine olanak tanır.
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 dizinin 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 hariç 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 kuralları 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ı veya eski ProGuard kuralları eklemeyi 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çebilirler.
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. Ayrıca, diğer dosyaları modülünüzün derleme komut dosyasındaki proguardFiles
özelliğine ekleyerek diğer dosyalardan ek kurallar da dahil edebilirsiniz.
Örneğin, karşılık gelen productFlavor
bloğuna başka bir proguardFiles
özelliği 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ı kaldırma 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. Bununla birlikte, 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üldüyse bu kitaplığı kullanan bir uygulamanın, daraltılmış kitaplık sınıflarını içereceğ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.
Saklanacak kodu ö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ı R8'in doğru şekilde analiz etmesi zordur ve uygulamanızın gerçekten ihtiyaç duyduğu kodu kaldırabilir. Kodun hatalı bir şekilde kaldırılabileceği durumlara örnek olarak şunlar verilebilir:
- 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 etmek, uygunsuz bir şekilde kaldırılan kodun neden olduğu hataları ortaya çıkarır. Bununla birlikte, kaldırılan kod raporu oluşturarak hangi kodun kaldırıldığını de 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ı, saklamak 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ğıdakilerden hata ayıklama sembolü düzeyini seçin:
- Play Console'un simgeselleştirilmiş yığın izlemelerinde işlev adlarını almak için
SYMBOL_TABLE
kullanın. Bu düzey mezar taşlarını destekler. - Play Console'un sembolik yığın izlemelerinde işlev adlarını, dosyaları ve satır numaralarını almak için
FULL
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ına referans verilmemesi için kullanılmayan kitaplık kodunu kaldırmanız gerekir. Böylece, kaynak daraltıcı tarafından kaldırılabilir.
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 karakterini joker
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.
Hangi kaynakların silineceğini belirtmek, bu kaynakları silmek yerine silineceği zaman saçma gelebilir, ancak derleme varyantları kullanılırken faydalı olabilir. Örneğin, tüm kaynaklarınızı ortak proje dizinine yerleştirebilir, daha sonra belirli bir kaynağın kodda kullanıldığını (ve dolayısıyla da daraltıcı tarafından kaldırılmadığını) bildiğinizde ancak belirtilen derleme varyantı için kullanılmayacağını bildiğinizde 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ış bir şekilde tanımlaması da mümkündür. Bu durum, derleyicinin kaynak kimliklerini satır içi olarak eklemesi ve daha sonra kaynak analizcisinin, gerçekten başvurulan bir kaynak ile koddaki aynı değere sahip olan tam sayı değeri arasındaki farkı bilmemesi olabilir.
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çimdeki kaynak URL'lerini 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 çevrilmiş dil dizelerinin tümünü 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 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" } }
Bir uygulama, Android App Bundle biçimini kullanarak yayınlarken varsayılan olarak yalnızca kullanıcının cihazında yapılandırılan diller indirilir. Benzer şekilde, yalnızca cihazın ekran yoğunluğuyla eşleşen kaynaklar ve cihazın ABI'siyle eşleşen yerel kitaplıklar da indirme işlemine 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ığında gerçekleşir. Gradle, yinelenenler arasında en iyi seçenek olarak değerlendirdiği dosyayı seçer (aşağıda açıklanan öncelik sırasına göre) ve nihai yapıda dağıtım için yalnızca bir kaynağı AAPT'ye 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 çeşitlerine ait 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 derleme türünde yinelenen bir kaynak görünüyorsa Gradle, derleme türünden olanı 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
özelliğinde birden fazla kaynak kümesi tanımlarsanız (örneğin, hem src/main/res/
hem de src/main/res2/
aynı kaynakları içeriyorsa) bu durum ortaya çıkabilir.
Kodunuzu karartma
Kod karartma işleminin amacı, uygulamanızdaki sınıfların, yöntemlerin ve alanların 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. Kod karartma işleminden sonra yığın izlemenizi anlamak için karartılmış yığın izlemenin 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 saklama kuralları R8'e, bu kodu hem uygulamanızın son DEX'inde tutmasını hem de orijinal adını korumasını bildirir.
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 kodları kaldırmak veya mümkün olduğunda kodunuzu daha az ayrıntı içerecek şekilde yeniden yazmak amacıyla 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
else {}
dalını hiçbir zaman almazsa 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 edinmek için Jake Wharton'ın R8 optimizasyonu 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. Hatta R8, -optimizations
ve -optimizationpasses
gibi varsayılan optimizasyonları değiştirmeye çalışan tüm ProGuard kurallarını yok sayar. Bu kısıtlama önemlidir çünkü R8 iyileşmeye devam ederken optimizasyonlar için standart bir davranış sürdürülmesi, Android Studio ekibinin karşılaşabileceğiniz sorunları kolayca gidermesine ve çözmesine yardımcı olur.
Optimizasyonu etkinleştirmenin, uygulamanızın yığın izlemelerini değiştireceğini unutmayın. Örneğin, satır içi ekleme 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, bir dizi ek optimizasyon ("tam mod" olarak adlandırılır) içerir. Bu da, ProGuard'dan farklı davranışlara neden olur. Bu optimizasyonlar, Android Gradle eklentisi 8.0.0 sürümünden itibaren 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 başvurduğunu düşünelim. "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ı iddia ederse sınıfı uygulamanızın nihai DEX'inden kaldırır. Yani sınıfı ve statik başlatıcıyı 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 etken, sınıfların ve yöntemlerin bile adları değiştireceği kod karartmadır.
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 çökmeyle sonuçlanan yığın izlemelerin (stack trace) kodunu gösterme ile ilgili Yardım Merkezi makalesine bakı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. Aşağıda sorununuza bir çözüm 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 kodların bir raporunu görmek faydalı 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 kod raporu aşağıdakine benzer:
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ştirdiğinizde ve uygulamanızı derlediğinizde, R8 belirttiğiniz yolu ve dosya adını içeren bir rapor oluşturur. Tutulan giriş noktalarının raporu aşağıdakine benzer:
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
...
Kaynak daraltma sorunlarını 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 "Erişilebilen kök kaynaklar:" 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.