Android için hızlı iteratif geliştirme
Bu sayfada, bazel mobile-install
uygulamasının yinelemeli geliştirmeyi nasıl yaptığı açıklanmaktadır
çok daha hızlı sağlıyor. Bu yaklaşımın avantajları ile
ve geleneksel uygulama yükleme yönteminin
zorlukları üzerine konuştuk.
Ö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. 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.- Çok fazla beklemek zorunda kalmayın.
Bazel'de 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. Bunun yararlı uygulamalarından biri, yüklemek istediğiniz cihazı seçmektir iş istasyonunuza bağlı birden fazla cihazınız varsa aşağıdaki adımları uygulayın:bazel mobile-install --adb_arg=-s --adb_arg=<SERIAL> :your_target
--start_app
, uygulamayı otomatik olarak başlatır
Şüpheye düştüğünüzde örnek 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ştururken aşağıdakiler gibi bazı sorunlar var:
Dexing. Varsayılan olarak "dx" çağrıldığı için derlemede tam olarak bir kez çağrılır. önceki derlemelerdeki çalışmaları nasıl yeniden kullanacağınızı bilir: Bu sistem, çalışmalarınızı ancak tek bir yöntem değiştirildi.
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. Uygulama tamamen küçük kısımları değişmiş olsa bile (örneğin, bir kaynak veya bir bu yüzden büyük bir performans sorunu olabilir.
Yerel kod derlemesi. Android L, yeni Android çalışma zamanı olan ART'yi Böylece uygulamaları tam zamanında derlemek yerine önceden derler. Dalvik. Bu da daha uzun yükleme maliyetiyle uygulamaları çok daha hızlı hale getirir gerekir. 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
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 kırıklarda çağrılmaz.Artımlı dosya aktarımı. Android kaynakları, .dex dosyaları ve yerel dosyalar kitaplıklar ana .apk'den kaldırılır ve ayrı bir mobil yükleme dizini. Bu, kodu ve Android'i güncellemeyi mümkün kılar ve kaynakların birbirinden bağımsız olmasını sağlayın. Böylece, dosyaları aktarmak daha az zaman alır ve yalnızca yapılan değişiklikler cihaz üzerinde yeniden derlenir.
Uygulamanın bazı bölümlerinin .apk dışından yüklenmesi. .apk dosyasına, cihaz üzerindeki mobil yükleme dizininden Android kaynaklarını, Java kodunu ve yerel kodu yükleyen ve 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ı Dex Oluşturma
Parçalı dex oluşturma işlemi makul ölçüde basittir: .jar dosyaları oluşturulduktan sonra,
araç
bunları yaklaşık olarak eşit boyutta ayrı .jar dosyalarına ayırır, daha sonra
Önceki derlemeden sonra değiştirilenler üzerinde dx
. Projenin gidişatını
hangi kırıkların Android'e özgü olmadığını belirler, yalnızca
genel değişiklik budama algoritmasıdır.
Parçalama algoritmasının ilk sürümü, .class dosyalarını sonra listeyi eşit boyutlarda parçalara böldük, ancak daha büyük bir suboptimal: bir sınıf eklendiyse veya kaldırıldıysa (iç içe yerleştirilmiş veya anonim bir sınıf da dahil olmak üzere) sonra tüm sınıfların alfabetik olarak kaymasına neden olur. bu da kırıkların tekrar çözülmesine neden oluyor. Bu nedenle, sınıflar yerine Java paketlerini bölme kararı alındı. Elbette bu yine de yeni bir paket eklendiğinde veya kaldırıldığında çok sayıda parçayı tek bir sınıf eklenmesine veya çıkarılmasına göre daha sıktır.
Kırık sayısı BUILD dosyası tarafından kontrol edilir (
android_binary.dex_shards
özelliği) ekleyebilirsiniz. İdeal bir dünyada Bazel
otomatik olarak kaç parçanın en iyi olduğunu belirler, ancak Bazel'in bunu şu anda bilmesi gerekir
yapılandırmadan önce bir dizi işlem (örneğin, derleme sırasında yürütülecek komutlar)
yürütür, böylece ideal kırık sayısını belirleyemez
çünkü eninde sonunda kaç Java sınıfı olacağını
uygulamasını indirin. Genelde, ne kadar fazla kırık olursa, derleme o kadar hızlı ve
ancak uygulama başlatma işlemi daha yavaş olur. Bunun nedeni,
bağlayıcının daha fazla işlem yapması gerekir. 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 olan en az çabayla. 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ı mobile-install dizine yükleme
İlk adımda çok fazla artımlılık yoktur: Uygulama yüklüdür
hakkında bilgi edindiniz. 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, uygulamanın derlemedeki dosyaları cihaz üzerindeki bir dosyayla karşılaştırılır cihazda hangi uygulama dosyalarının bulunduğunu ve bunların sağlamaları da vardır. Cihaza yüklenen yeni dosyalar, değiştirilen dosyalar güncellenir ve kaldırılan dosyalar olanak tanır. Manifest mevcut değilse her dosyanın yüklenmesi gerektiği varsayılır.
Ek yükleme algoritmasının, artımlı yükleme algoritmasının yanı sıra cihazdaki bir dosyayı değiştirir, ancak manifest'teki sağlama toplamını değiştirmez. 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ı
Stub uygulaması, dex'leri, yerel kodları ve öğeleri
Cihaz üzerindeki mobile-install
dizinindeki Android kaynakları gerçekleşir.
Asıl yükleme, BaseDexClassLoader
alt sınıfıyla uygulanır ve bir
ortaya koymuş olabilir. Bu işlem, uygulamanın sınıflarından herhangi biri yüklenmeden önce gerçekleşir. Böylece, apk'da bulunan 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ı yüklendiğinden, .apk biçiminde yapılır. Bu da bu sınıflarda yapılan değişikliklerin yeniden yükleyin.
Bu, AndroidManifest.xml
içinde belirtilen Application
sınıfının stub uygulama ile değiştirilmesiyle yapılır. 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 gereklidir çünkü
dinamik bağlayıcının dosyalarda X
bitinin ayarlanmasını gerektirir ve bu
kök olmayan bir adb
tarafından erişilebilen herhangi bir konum için yapmanız gerekir.
Tüm bunlar yapıldıktan sonra saplama uygulaması,
gerçek Application
sınıfı; tüm referansları gerçek haliyle değiştirerek
bir uygulamadır.
Sonuçlar
Performans
Genel olarak, bazel mobile-install
ile inşaat hızı 4 ila 10 kat artırılır
sonra küçük bir değişiklikten sonra büyük
uygulamalar yüklemeyi ümit ediyoruz.
Aşağıdaki sayılar birkaç Google ürünü için hesaplandı:
Bu, elbette değişikliğin yapısına bağlı: temel kitaplığı değiştirmek 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
,Application
sınıfına yayınlandığındaContentProvider#onCreate()
. Bu yöntem, uygulama sırasında çağrılırApplication
örneğini değiştirme fırsatımız olmadan startup'ı sınıfını kullanır. Bu nedenle,ContentProvider
, saplama uygulamasına başvurmaya devam eder. e-posta alırsınız. Muhtemelen bu bir hata değildir çünküContext
uygulamasını bu şekilde eski sürüme geçirmem gerekiyordu ancak bu işlemi birkaç dakika içinde yapacağım bazı yöntemleri dinlediniz.bazel mobile-install
tarafından yüklenen kaynaklara yalnızca şunun içinden erişilebilir: görebilirsiniz. Diğer uygulamalar kaynaklaraPackageManager#getApplicationResources()
, bu kaynaklar artımlı olmayan son yükleme.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ı gidermediği sürece Dalvik, (ancak eski Android sürümlerini desteklemenin tam olarak bizim için tam olarak odak)