Android için hızlı iteratif geliştirme
Bu sayfada, bazel mobile-install
'ün Android için iteratif geliştirmeyi nasıl çok daha hızlı hale getirdiği açıklanmaktadır. Bu yaklaşımın avantajları ve geleneksel uygulama yükleme yönteminin zorlukları açıklanmaktadır.
Özet
Bir Android uygulamasındaki küçük değişiklikleri çok hızlı bir şekilde yüklemek için aşağıdakileri yapın:
- Yüklemek istediğiniz uygulamanın
android_binary
kuralını bulun. proguard_specs
özelliğini kaldırarak Proguard'ı devre dışı bırakın.multidex
özelliğininative
olarak ayarlayın.dex_shards
özelliğini10
olarak ayarlayın.- ART (Dalvik değil) çalıştıran cihazınızı USB üzerinden bağlayın ve USB hata ayıklama özelliğini etkinleştirin.
bazel mobile-install :your_target
'ü çalıştırın. Uygulama başlatma işlemi normalden biraz daha yavaş olacaktır.- Kodu veya Android kaynaklarını düzenleyin.
bazel mobile-install --incremental :your_target
çalıştır.- Çok fazla beklemek zorunda kalmamanın tadını çıkarın.
Bazel'de yararlı olabilecek bazı komut satırı seçenekleri:
--adb
, Bazel'e hangi adb ikili programını kullanacağını söyler--adb_arg
,adb
komut satırına ek bağımsız değişkenler eklemek için kullanılabilir. Bu özelliğin kullanışlı bir uygulaması, iş istasyonunuza bağlı birden fazla cihazınız varsa hangi cihaza yüklemek istediğinizi seçmektir:bazel mobile-install --adb_arg=-s --adb_arg=<SERIAL> :your_target
--start_app
uygulamayı otomatik olarak başlatır
Emin değilseniz örneğe göz atın veya bize ulaşın.
Giriş
Bir geliştiricinin araç zincirinin en önemli özelliklerinden biri hızdır: Kodu değiştirmek ve bir saniye içinde çalışmasını görmek ile değişikliklerinizin beklediğiniz sonucu verip vermediğine dair geri bildirim almak için dakikalarca, bazen de saatlerce beklemek arasında dünyalar kadar fark vardır.
Maalesef .apk oluşturmak için kullanılan geleneksel Android araç zinciri, birçok tekil ve sıralı adım içerir. Android uygulaması oluşturmak için bunların hepsinin yapılması gerekir. Google'da, Google Haritalar gibi büyük projelerde tek satırlık bir değişiklik yapmak için beş dakika beklemek alışılmış bir durumdu.
bazel mobile-install
, uygulamanızın kodunda herhangi bir değişiklik yapmadan Android için yinelemeli geliştirmeyi çok daha hızlı hale getirmek amacıyla değişiklik budama, iş parçalara ayırma ve Android'in dahili işlevlerini akıllıca değiştirme işlemlerini bir arada kullanır.
Geleneksel uygulama yüklemeyle ilgili sorunlar
Android uygulaması oluşturmanın bazı sorunları vardır. Örneğin:
Dexing. Varsayılan olarak "dx", derlemede tam olarak bir kez çağrılır ve önceki derlemelerdeki çalışmaların nasıl yeniden kullanılacağını bilmez. Yalnızca bir yöntem değiştirilmiş olsa bile her yöntem için ayrı ayrı yöntemlere başvurur.
Verileri cihaza yükleme. adb, USB 2.0 bağlantısının tam bant genişliğini kullanmaz ve büyük uygulamaların yüklenmesi çok uzun sürebilir. Yalnızca küçük parçalar (ör. bir kaynak veya tek bir yöntem) değişmiş olsa bile uygulamanın tamamı yüklenir. Bu nedenle, bu önemli bir darboğaz olabilir.
Yerel koda derleme. Android L, Dalvik gibi uygulamaları tam zamanında derlemek yerine önceden derleyen yeni bir Android çalışma zamanı olan ART'yi kullanıma sundu. Bu, yükleme süresinin uzaması pahasına uygulamaları çok daha hızlı hale getirir. Kullanıcılar genellikle bir uygulamayı bir kez yükleyip birçok kez kullandığından bu, kullanıcılar açısından iyi bir takastır. Ancak uygulamanın birçok kez yüklendiği ve her sürümün en fazla birkaç kez çalıştırıldığı durumlarda geliştirme süreci yavaşlar.
bazel mobile-install
'ün yaklaşımı
bazel mobile-install
aşağıdaki iyileştirmeleri yapar:
Parçalı dizine ekleme. Bazel, uygulamanın Java kodunu derledikten sonra sınıf dosyalarını yaklaşık olarak eşit büyüklükte parçalara ayırır ve
dx
'ı bunlarda ayrı ayrı çağırır.dx
, son derlemeden bu yana değişmeyen parçalarda çağrılmaz.Artımlı dosya aktarımı. Android kaynakları, .dex dosyaları ve yerel kitaplıklar ana .apk'den kaldırılır ve ayrı bir mobil yükleme dizininde depolanır. Bu sayede, uygulamanın tamamını yeniden yüklemeden kodu ve Android kaynaklarını bağımsız olarak güncelleyebilirsiniz. Böylece, dosyaların aktarılması daha az zaman alır ve yalnızca değişen .dex dosyaları cihazda yeniden derlenir.
Uygulamanın bazı bölümleri .apk dışından yükleniyor. .apk dosyasına, cihaz üzerindeki mobil yükleme dizininden Android kaynaklarını, Java kodunu ve yerel kodu yükleyen, ardından kontrolü asıl uygulamaya aktaran küçük bir stub uygulaması yerleştirilir. Aşağıda açıklanan birkaç özel durum dışında, bu işlemler uygulama için şeffaftır.
Parçalı Dexing
Parçalara ayrılmış dexing işlemi oldukça basittir: .jar dosyaları oluşturulduktan sonra bir araç, bunları yaklaşık olarak eşit boyutta ayrı .jar dosyalarına böler ve önceki derlemeden bu yana değiştirilenlerde dx
'yi çağırır. Hangi parçaların ayrıştırılacağını belirleyen mantık Android'e özgü değildir: Yalnızca Bazel'in genel değişiklik budama algoritmasını kullanır.
Bölme algoritmasının ilk sürümü, .class dosyalarını alfabetik olarak sıralayıp listeyi eşit büyüklükte parçalara ayırıyordu. Ancak bu yöntemin en uygun çözüm olmadığı anlaşıldı: Bir sınıf eklendiğinde veya kaldırıldığında (iç içe yerleştirilmiş veya anonim bir sınıf bile olsa), alfabetik olarak bu sınıftan sonraki tüm sınıflar birer basamak kaydırılır ve bu parçalar tekrar dizine eklenir. Bu nedenle, sınıflar yerine Java paketlerini bölme kararı alındı. Elbette yeni bir paket eklendiğinde veya kaldırıldığında bu, birçok parçanın dizine eklenmesine neden olur ancak bu durum tek bir sınıfın eklenmesinden veya kaldırılmasından çok daha seyrektir.
Parça sayısı, BUILD dosyası tarafından kontrol edilir (android_binary.dex_shards
özelliği kullanılır). İdeal bir durumda Bazel, en iyi kaç parçanın olacağını otomatik olarak belirler. Ancak Bazel, şu anda herhangi birini yürütmeden önce işlem grubunu (ör. derleme sırasında yürütülecek komutlar) bilmesi gerekir. Bu nedenle, uygulamada nihai olarak kaç Java sınıfı olacağını bilmediği için en uygun parça sayısını belirleyemez. Genel olarak, parça sayısı arttıkça derleme ve yükleme işlemi de hızlanır ancak dinamik bağlayıcının daha fazla çalışması gerektiğinden uygulamanın başlatılması da yavaşlar. Tercih edilen alan genellikle 10 ila 50 parçadır.
Artımlı dosya aktarımı
Uygulamayı oluşturduktan sonraki adım, tercihen mümkün olduğunca az çabayla yüklemektir. Kurulum aşağıdaki adımlardan oluşur:
- .apk dosyasını yükleme (genellikle
adb install
kullanılarak) - .dex dosyalarını, Android kaynaklarını ve yerel kitaplıkları mobil yükleme dizinine yükleme
İlk adımda çok fazla artımlılık yoktur: Uygulama yüklüdür veya yüklü değildir. Şu anda Bazel, her durumda gerekli olup olmadığını belirleyemediğinden, bu adımı --incremental
komut satırı seçeneği üzerinden yapması gerekip gerekmediğini belirtmelidir.
İkinci adımda, derlemedeki uygulamanın dosyaları, cihazda hangi uygulama dosyalarının bulunduğunu ve bunların sağlamalarını listeleyen cihaz üzerindeki bir manifest dosyasıyla karşılaştırılır. Yeni dosyalar cihaza yüklenir, değişen dosyalar güncellenir ve kaldırılan dosyalar cihazdan silinir. Manifest mevcut değilse her dosyanın yüklenmesi gerektiği varsayılır.
Cihazdaki bir dosyayı değiştirerek artımlı yükleme algoritmasını kandırabileceğinizi ancak manifest'teki sağlama toplamını değiştiremeyeceğinizi unutmayın. Bu durum, cihazdaki dosyaların sağlama toplamının hesaplanması yoluyla önlenebilirdi ancak bu işlemin yükleme süresini uzatacağı düşünülerek bu yöntemden vazgeçildi.
Stub uygulaması
Dex dosyalarını, yerel kodu ve Android kaynaklarını cihaz üzerindeki mobile-install
dizininden yükleme işlemi, stub uygulamasında gerçekleşir.
Gerçek yükleme, BaseDexClassLoader
alt sınıfı oluşturularak uygulanır ve oldukça iyi belgelenmiş bir tekniktir. Bu işlem, uygulamanın herhangi bir sınıfı yüklenmeden önce gerçekleşir. Böylece, apk'de bulunan uygulama sınıfları, cihaz üzerindeki mobile-install
dizinine eklenebilir. Böylece, adb install
olmadan güncellenebilirler.
Bu işlemin, uygulamanın sınıflarından herhangi biri yüklenmeden önce yapılması gerekir. Böylece .apk dosyasında hiçbir uygulama sınıfı bulunmaz. Bu da bu sınıflarda yapılan değişiklikler için tam bir yeniden yükleme yapılması gerektiği anlamına gelir.
Bu işlem, AndroidManifest.xml
politikasında belirtilen Application
sınıfının stub application ile değiştirilmesiyle gerçekleştirilir. Bu, uygulamanın başlatılacağı zamanı kontrol altına alır ve Android çerçevesinin dahili öğeleri hakkındaki Java yansımalarını kullanarak sınıf yükleyicisi ile kaynak yöneticisini en kısa zamanda (oluşturucusu) uygun şekilde düzenler.
Rıdvan uygulamanın yaptığı bir diğer işlem de mobil yükleme tarafından yüklenen yerel kitaplıkları başka bir konuma kopyalamasıdır. Bu, dinamik bağlayıcının dosyalarda X
bitinin ayarlanmasını gerektirdiği için gereklidir. Bu, kök olmayan bir adb
tarafından erişilebilen herhangi bir konum için yapılamaz.
Tüm bu işlemler tamamlandıktan sonra, stub uygulaması gerçek Application
sınıfını örneklendirir ve kendisine yapılan tüm referansları Android çerçevesindeki gerçek uygulamayla değiştirir.
Sonuçlar
Performans
Genel olarak bazel mobile-install
, küçük bir değişiklikten sonra büyük uygulamaların derlenmesi ve yüklenmesi işlemlerini 4 ila 10 kat hızlandırır.
Aşağıdaki sayılar birkaç Google ürünü için hesaplandı:
Bu, elbette değişikliğin yapısına bağlıdır: Temel kitaplığın değiştirilmesinden sonra yeniden derleme işlemi daha fazla zaman alır.
Sınırlamalar
Saplama uygulamasında yapılan hileler her durumda işe yaramaz. Aşağıdaki durumlarda bu özellik beklendiği gibi çalışmaz:
Context
,ContentProvider#onCreate()
sınıfındakiApplication
sınıfına aktarıldığında. Bu yöntem,Application
sınıfının örneğini değiştirme fırsatımız olmadan uygulama başlatılırken çağrılır. Bu nedenle,ContentProvider
gerçek uygulama yerine yine şablon uygulamaya referans verir.Context
değerini bu şekilde aşağı aktarmanız gerekmediğinden bu bir hata değildir ancak Google'daki birkaç uygulamada bu durum yaşanıyor.bazel mobile-install
tarafından yüklenen kaynaklara yalnızca uygulama içinden erişilebilir. Diğer uygulamalarPackageManager#getApplicationResources()
aracılığıyla kaynaklara erişirse bu kaynaklar, son artımlı olmayan yüklemeden alınır.ART çalışmayan cihazlar. Stub uygulaması Froyo ve sonraki sürümlerde iyi çalışırken Dalvik'te, Java ek açıklamaları belirli bir şekilde kullanıldığında olduğu gibi, belirli durumlarda kodu birden fazla .dex dosyasına dağıtılırsa uygulamanın yanlış olduğunu düşünmesine neden olan bir hata vardır. Uygulamanız bu hataları tetiklemediği sürece Dalvik ile de çalışmalıdır (Ancak eski Android sürümlerine yönelik desteğin tam olarak odak noktamız olmadığını unutmayın).