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
Android uygulamasında 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. Uygulamanın başlatılması normalden biraz daha yavaş olur.- Kodu veya Android kaynaklarını düzenleyin.
bazel mobile-install --incremental :your_target
'ü çalıştırın.- Çok beklemeniz gerekmez.
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 faydalı 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ı nasıl yeniden kullanacağını bilmez: Yalnızca bir yöntem değişmiş olsa bile her yöntemi tekrar dizine ekler.
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'dan 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ümlerini .apk dışından yükleme. .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 dex'e dönüştürüleceğini belirleyen mantık Android'e özgü değildir. Bu mantıkta, Bazel'in genel değişiklik budama algoritması kullanılı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, tek bir sınıfın eklenmesinden veya kaldırılmasından çok daha seyrek bir durumdur.
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ı yavaşlar. En iyi performansı genellikle 10 ila 50 parça arasında elde edersiniz.
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ı mobile-install dizine yükleme
İlk adımda çok fazla artımlı değer yoktur: Uygulama ya yüklenmiştir ya da yüklenmemiştir. Bazel şu anda bu adımın gerekli olup olmadığını her durumda belirleyemediği için --incremental
komut satırı seçeneği aracılığıyla bu adımı yapıp yapmayacağını kullanıcıya sorar.
İkinci adımda, derlemedeki uygulama dosyaları, cihazdaki uygulama dosyalarını ve bunların sağlama toplamlarını listeleyen cihaz üzerinde 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 yoksa 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 sınıflarından herhangi biri yüklenmeden önce gerçekleşir. Böylece, apk'da bulunan tüm uygulama sınıfları cihaz üzerindeki mobile-install
dizinine yerleştirilebilir ve adb install
olmadan güncellenebilir.
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, AndroidManifest.xml
içinde belirtilen Application
sınıfının stub uygulaması ile değiştirilmesiyle gerçekleştirilir. Bu sınıf, uygulama başlatılırken kontrolü ele alır ve Android çerçevesinin iç kısımlarında Java yansımasını kullanarak sınıf yükleyiciyi ve kaynak yöneticisini en erken anda (yapıcısı) uygun şekilde değiştirir.
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 uygulama 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ı oluşturma ve yükleme işlemlerini 4 ila 10 kat hızlandırır.
Aşağıdaki sayılar birkaç Google ürünü için hesaplanmıştır:
Bu süre elbette değişikliğin niteliğine bağlıdır: Temel kitaplık değiştirildikten sonra yeniden derleme işlemi daha uzun sürer.
Sınırlamalar
Stub uygulamasının uyguladığı 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ıştırmayan 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).