Android için hızlı, yinelemeli geliştirme
Bu sayfada, bazel mobile-install
ürününün Android için yinelemeli geliştirmeyi nasıl çok daha hızlı hale getirdiği açıklanmaktadır. Burada, bu yaklaşımın avantajlarına kıyasla
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.- USB üzerinden ART (Dalvik değil) çalıştıran cihazınızı bağlayın ve USB hata ayıklama özelliğini etkinleştirin.
bazel mobile-install :your_target
çalıştır. 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 kalmayın.
Bazel için yararlı olabilecek bazı komut satırı seçenekleri:
--adb
, Bazel'e hangi adb ikili programını kullanacağını bildirir--adb_arg
,adb
komut satırına fazladan bağımsız değişkenler eklemek için kullanılabilir. Bu özelliğin kullanışlı bir uygulamalarından biri, iş istasyonunuza bağlı birden fazla cihazınız varsa yüklemek istediğiniz cihazı seçmektir:bazel mobile-install --adb_arg=-s --adb_arg=<SERIAL> :your_target
--start_app
, uygulamayı otomatik olarak başlatır
Şüpheye düştüğünüzde örneği inceleyin veya bizimle iletişime geçin.
Giriş
Bir geliştiricinin araç zincirinin en önemli özelliklerinden biri hızdır: Kodu değiştirmekle kodun bir saniye içinde çalıştığını görmek ile değişikliklerin beklediğiniz gibi olup olmadığıyla ilgili geri bildirim almak için dakikalar, bazen saatler boyunca beklemek zorunda kalmak arasında çok büyük bir fark vardır.
Maalesef, .apk oluşturmaya yönelik geleneksel Android araç zinciri, birçok monolitik, sıralı adım gerektirir ve bunların hepsinin bir Android uygulaması geliştirmek için tamamlanması gerekir. Google'da, tek satırlık bir değişiklik oluşturmak için beş dakika beklemek, Google Haritalar gibi daha büyük projelerde olağan dışı bir durum değildi.
bazel mobile-install
, değişiklikleri budama, iş parçalama ve Android dahili bileşenleri üzerinde zekice değiştirme gibi yöntemleri bir arada kullanarak Android için yinelemeli geliştirmeyi çok daha hızlı hale getirir. Üstelik tüm bunları uygulamanızın hiçbir kodunu değiştirmeden yapar.
Geleneksel uygulama yüklemeyle ilgili sorunlar
Android uygulaması oluştururken aşağıdakiler gibi bazı sorunlar var:
Dexing. Varsayılan olarak "dx", derlemede tam olarak bir kez çağrılır ve önceki derlemelere ait ç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 yeniden deneme yapılır.
Veriler cihaza yükleniyor. Adb, USB 2.0 bağlantısının tam bant genişliğini kullanmaz ve daha büyük uygulamaların yüklenmesi uzun sürebilir. Bir kaynak veya tek bir yöntem gibi yalnızca küçük kısımları değişmiş olsa bile uygulamanın tamamı yüklenir. Bu nedenle bu büyük bir performans sorunu olabilir.
Yerel kod derlemesi. Android L, uygulamaları Dalvik gibi tam zamanında derlemek yerine önceden derleyen yeni Android çalışma zamanı ART'ı kullanıma sundu. Bu da daha uzun yükleme süreleri karşılığında uygulamaları çok daha hızlı hale getirir. Kullanıcılar bir uygulamayı genellikle bir kez yükleyip birçok kez kullandığı için bu durum iyi bir performanstı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ürecinin yavaş olmasına yol açar.
bazel mobile-install
yaklaşımı
bazel mobile-install
aşağıdaki iyileştirmeleri yapar:
Parçalı dexing. Bazel, uygulamanın Java kodunu oluşturduktan sonra sınıf dosyalarını yaklaşık olarak eşit büyüklükteki parçalara ayırır ve
dx
öğesini bu dosyalarda ayrı olarak çağırır.dx
, son derlemeden bu yana değişmeyen kırıklarda ç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, uygulamanın tamamını yeniden yüklemeden kod ve Android kaynaklarını bağımsız olarak güncellemeyi mümkün kılar. Böylece, dosyaların aktarılması daha kısa sürer ve yalnızca değiştirilen .dex dosyaları cihaz üzerinde yeniden derlenir.
Uygulamanın bazı bölümleri .apk dışından yükleniyor. .apk'ye Android kaynaklarını, Java kodunu ve yerel kodu cihaz üzerinde mobil yükleme dizininden yükleyen ve ardından kontrolü gerçek uygulamaya aktaran küçük bir saplama uygulaması yerleştirilir. Aşağıda açıklanan bazı özel durumlar dışında bunların tamamı uygulamaya şeffaf bir şekilde aktarılır.
Parçalı Dex Oluşturma
Parçalama işlemi makul ölçüde basittir: .jar dosyaları oluşturulduktan sonra, bir araç bunları yaklaşık olarak aynı boyutta ayrı .jar dosyaları halinde parçalara ayırır ve ardından, önceki derlemeden bu yana değiştirilmiş olan dosyalarda dx
yöntemini ç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.
Parçalama algoritmasının ilk sürümü sadece .class dosyalarını alfabetik olarak sıralar ve ardından listeyi eşit boyutlu parçalara ayırır. Ancak bunun optimum olmadığı kanıtlanmıştır: Bir sınıf eklenir veya kaldırılırsa (iç içe yerleştirilmiş veya anonim bir sınıf olsa bile), tüm sınıflar alfabetik olarak kayarak bu parçaların tekrar çıkarılmasına neden olur. Bu nedenle, tek tek sınıflar yerine Java paketlerini parçalamaya karar verildi. Elbette bu durum, yeni bir paket eklendiğinde veya kaldırıldığında çok sayıda parçanın dizinlenmesine neden olur. Ancak bu, tek bir sınıfın eklenmesi veya kaldırılmasından çok daha azdır.
Kırık sayısı, BUILD dosyası tarafından kontrol edilir (android_binary.dex_shards
özelliği kullanılarak). İdeal bir dünyada Bazel, en iyi kaç parçanın uygun olduğunu otomatik olarak belirler. Fakat Bazel'in bunlardan herhangi birini çalıştırmadan önce işlem grubunu (örneğin, derleme sırasında yürütülecek komutlar) bilmesi gerekir. Bu nedenle uygulamada kaç Java sınıfı olacağını bilemediği için ideal kırık sayısını belirleyemez. Çünkü uygulamada kaç tane Java sınıfı olacağını bilemez, bağlantı da ne kadar hızlıysa derleme de o kadar yavaş olur. İş için ideal nokta genellikle 10 ila 50 parçadır.
Artımlı dosya aktarımı
Uygulamayı oluşturduktan sonraki adım, tercihen mümkün olan en az çabayla uygulamayı yüklemektir. Yükleme işlemi aşağıdaki adımlardan oluşur:
- .apk yükleniyor (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ü 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. Cihaza yeni dosyalar yüklenir, değiştirilen dosyalar güncellenir ve kaldırılan dosyalar cihazdan silinir. Manifest dosyası 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ı yanıltmanın mümkün olduğunu, ancak manifest dosyasındaki sağlama toplamını değiştirmemenin mümkün olduğunu unutmayın. Cihazdaki dosyaların sağlama toplamı bu riske karşı korunabilirdi, ancak yükleme süresindeki artışa değmeyeceğine karar verildi.
Stub uygulaması
Stub uygulaması, cihaz üzerindeki mobile-install
dizininden dex'ler, yerel kod ve Android kaynaklarını yüklemenin en güzel yoludur.
Gerçek yükleme, BaseDexClassLoader
alt sınıflandırması yapılarak uygulanır ve makul şekilde 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 herhangi bir sınıfı yüklenmeden önce yapılması gerekir. Böylece, .apk'de uygulama sınıfı bulunmaz. Bu da bu sınıflarda yapılan değişiklikler için tamamen 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 uygulaması 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.
Saplama uygulamasının yaptığı bir başka şey de mobil yükleme tarafından yüklenen yerel kitaplıkları başka bir konuma kopyalamaktır. Dinamik bağlayıcının dosyalarda X
bitinin ayarlanması gerektiğinden bu işlem gereklidir. Kök olmayan adb
tarafından erişilebilen hiçbir konum için bu işlem yapılamaz.
Tüm bunlar yapıldıktan sonra, saplama uygulaması gerçek Application
sınıfını örneklendirir ve tüm referansları Android çerçevesinde asıl uygulamayla değiştirir.
Sonuçlar
Performans
Genel olarak, bazel mobile-install
, küçük bir değişiklikten sonra büyük uygulamaların geliştirilme ve yüklenme hızlarında 4 ila 10 kat artış sağlar.
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, işlevin beklendiği gibi çalışmadığı durumlar vurgulanır:
Context
,ContentProvider#onCreate()
içindekiApplication
sınıfına yayınlandığında. Bu yöntem,Application
sınıfı örneğini değiştirme fırsatı bulmadan önce uygulama başlatılırken çağrılır. Bu nedenle,ContentProvider
gerçek uygulama yerine saplama uygulamasına başvuruda bulunur.Context
ürününü bu şekilde eski sürüme geçirmeniz gerekmediği için bu durumun bir hata olduğunu söyleyemeyiz ancak bu durum, Google'daki birkaç uygulamada yaşanmaktadır.bazel mobile-install
tarafından yüklenen kaynaklara yalnızca uygulama içinden erişilebilir. Kaynaklara diğer uygulamalarPackageManager#getApplicationResources()
üzerinden erişiyorsa bu kaynaklar ek olmayan son yükleme işleminden elde edilir.ART çalışmayan cihazlar. Saplama uygulaması Froyo ve sonraki sürümlerde iyi performans gösterse de Dalvik, belirli durumlarda (ör. Java ek açıklamaları belirli bir şekilde) kodun birden çok .dex dosyasına dağıtılması durumunda uygulamanın hatalı olduğunu düşünmesine neden olan bir hataya sahiptir. Uygulamanız bu hataları gidermediği sürece Dalvik ile çalışmalıdır (ancak eski Android sürümlerini desteklemenin tam olarak odak noktamız olmadığını unutmayın.)