Android için hızlı yinelemeli geliştirme
Bu sayfada, bazel mobile-install
'nın Android'de yinelemeli geliştirmeyi nasıl çok daha hızlı hale getirdiği açıklanmaktadır. Bu yaklaşımın avantajları ile 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 cihazda USB hata ayıklamayı etkinleştirin.
- Koşu
bazel mobile-install :your_target
. Uygulama başlatma işlemi normalden biraz daha yavaş olacaktır. - Kodu veya Android kaynaklarını düzenleyin.
- Koşu
bazel mobile-install --incremental :your_target
. - Çok fazla beklemek zorunda kalmazsınız.
Bazel'e iletilebilecek ve işinize yarayabilecek bazı komut satırı seçenekleri:
--adb
, Bazel'a hangi adb ikili dosyasının kullanılacağını bildirir.--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 olmadığınız durumlarda örneğe bakın veya bize ulaşın.
Giriş
Geliştiricinin araç zincirinin en önemli özelliklerinden biri hızdır: Kodu değiştirip bir saniye içinde çalışırken görmek ile değişikliklerinizin beklentilerinizi karşılayıp karşılamadığına dair geri bildirim almadan önce dakikalarca, hatta bazen saatlerce beklemeniz arasında çok büyük bir fark vardır.
Maalesef .apk oluşturmak için geleneksel Android araç zinciri, birçok monolitik ve sıralı adım içerir. Android uygulaması oluşturmak için bu adımların tamamının uygulanması gerekir. Google'da, Google Haritalar gibi daha büyük projelerde tek satırlık bir değişikliği oluşturmak için beş dakika beklemek alışılmadık bir durum değildi.
bazel mobile-install
, değişiklikleri budama, işi parçalama ve Android'in iç yapısını akıllıca değiştirme yöntemlerini kullanarak Android'de yinelemeli geliştirmeyi çok daha hızlı hale getirir. Tüm bunları, uygulamanızın kodunda herhangi bir değişiklik yapmadan gerçekleştirir.
Geleneksel uygulama yükleme ile ilgili sorunlar
Android uygulaması oluşturmayla ilgili bazı sorunlar vardır. Örneğin:
Dexing. Varsayılan olarak, "dx" derlemede tam olarak bir kez çağrılır ve önceki derlemelerdeki çalışmayı nasıl yeniden kullanacağını bilmez: Yalnızca bir yöntem değiştirilmiş olsa bile her yöntemi tekrar dex'ler.
Cihaza veri yükleme. 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 zaman alabilir. Yalnızca küçük bölümler değişmiş olsa bile (ör. bir kaynak veya tek bir yöntem) uygulamanın tamamı yüklendiğinden bu durum büyük bir performans sorununa yol açabilir.
Yerel koda derleme. Android L, uygulamaları Dalvik gibi tam zamanında derlemek yerine önceden derleyen yeni bir Android çalışma zamanı olan ART'yi tanıttı. Bu, uygulamaların çok daha hızlı çalışmasını sağlar ancak yükleme süresini uzatır. Kullanıcılar genellikle bir uygulamayı bir kez yükleyip birçok kez kullandığı için bu durum kullanıcılar açısından iyi bir denge noktasıdır. Ancak bir 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ı dexing. Bazel, uygulamanın Java kodunu oluşturduktan sonra sınıf dosyalarını yaklaşık olarak eşit boyutlu parçalara ayırır ve her birinde
dx
'ı 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 saklanır. Bu sayede, kod ve Android kaynakları, uygulamanın tamamı yeniden yüklenmeden bağımsız olarak güncellenebilir. 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ümlerinin .apk dışından yüklenmesi. .apk dosyasına, cihazdaki mobil yükleme dizininden Android kaynaklarını, Java kodunu ve yerel kodu yükleyen, ardından kontrolü gerçek uygulamaya aktaran küçük bir saplama uygulaması yerleştirilir. Bu işlem, aşağıda açıklanan birkaç istisna dışında uygulama için tamamen şeffaftır.
Parçalı Dexing
Parçalanmış dexing oldukça basittir: .jar dosyaları oluşturulduktan sonra bir araç bunları yaklaşık olarak eşit boyuttaki ayrı .jar dosyalarına böler ve ardından önceki derlemeden bu yana değiştirilenler üzerinde dx
'ı çağırır. Hangi parçaların dex'e dönüştürüleceğini belirleyen mantık Android'e özgü değildir. Yalnızca Bazel'in genel değişiklik temizleme algoritmasını kullanır.
Parçalama algoritmasının ilk sürümü, .class dosyalarını alfabetik olarak sıralayıp listeyi eşit boyutlu parçalara bölüyordu. Ancak bu yaklaşımın ideal olmadığı anlaşıldı: Bir sınıf eklendiğinde veya kaldırıldığında (iç içe yerleştirilmiş ya da anonim bir sınıf olsa bile) alfabetik olarak sonraki tüm sınıflar bir sıra kayıyor ve bu da parçaların yeniden dexlenmesine neden oluyordu. Bu nedenle, ayrı sınıflar yerine Java paketlerinin parçalanmasına karar verildi. Elbette bu durumda yeni bir paket eklenir veya kaldırılırsa yine birçok parça dizine eklenir ancak bu durum, tek bir sınıfın eklenmesi veya kaldırılmasına kıyasla çok daha az görülür.
Parça sayısı, BUILD dosyası tarafından kontrol edilir (android_binary.dex_shards
özelliği kullanılarak). İdeal bir dünyada Bazel, kaç parçanın en iyi olacağını otomatik olarak belirlerdi. Ancak Bazel şu anda herhangi birini yürütmeden önce işlem kümesini (örneğin, derleme sırasında yürütülecek komutlar) bilmelidir. Bu nedenle, uygulamada sonunda kaç Java sınıfı olacağını bilmediği için optimum parça sayısını belirleyemez. Genel olarak, parça sayısı ne kadar fazla olursa derleme ve yükleme o kadar hızlı olur ancak dinamik bağlayıcı daha fazla iş yapmak zorunda kalacağından uygulama başlatma işlemi yavaşlar. İdeal nokta genellikle 10 ile 50 parça arasındadı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 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 dizinine yükleme
İlk adımda çok fazla artış olmaz: Uygulama ya yüklenir ya da yüklenmez. Bazel, her durumda gerekli olup olmadığını belirleyemediği için şu anda kullanıcının --incremental
komut satırı seçeneğiyle bu adımı atması gerekip gerekmediğini belirtmesine bağlıdır.
İkinci adımda, derlemedeki uygulama dosyaları, cihazda hangi uygulama dosyalarının bulunduğu ve bu dosyaların sağlama toplamlarını listeleyen cihazdaki bir manifest dosyasıyla karşılaştırılır. Yeni dosyalar cihaza yüklenir, değiştirilmiş dosyalar güncellenir ve kaldırılmış dosyalar cihazdan silinir. Manifest yoksa her dosyanın yüklenmesi gerektiği varsayılır.
Cihazdaki bir dosyayı değiştirerek ancak manifestteki sağlama toplamını değiştirmeyerek artımlı yükleme algoritmasını yanıltmanın mümkün olduğunu unutmayın. Bu durum, cihazdaki dosyaların sağlama toplamı hesaplanarak önlenebilirdi ancak bu çözüm, yükleme süresindeki artışa değmeyecek bir çözüm olarak değerlendirildi.
Stub uygulaması
Stub uygulaması, cihazdaki mobile-install
dizininden dex'lerin, yerel kodun ve Android kaynaklarının yüklenmesi için gereken işlemleri yapar.
Gerçek yükleme, BaseDexClassLoader
alt sınıfı oluşturularak uygulanır ve makul ölçüde iyi belgelenmiş bir tekniktir. Bu işlem, uygulamanın sınıflarından herhangi biri yüklenmeden önce gerçekleşir. Böylece APK'daki tüm uygulama sınıfları, cihazdaki mobile-install
dizinine yerleştirilerek 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 herhangi bir uygulama sınıfı bulunmaz. Bu da söz konusu sınıflarda yapılan değişikliklerin tam bir yeniden yükleme gerektireceği anlamına gelir.
Bu işlem, Application
içinde belirtilen AndroidManifest.xml
sınıfının stub uygulamasıyla değiştirilmesiyle gerçekleştirilir. Bu, uygulama başlatıldığında kontrolü ele alır ve Android çerçevesinin iç kısımlarında Java yansıtması kullanarak sınıf yükleyiciyi ve kaynak yöneticisini en erken anda (yapıcısı) uygun şekilde ayarlar.
İstemci uygulamasının yaptığı bir diğer işlem de mobil yükleme ile yüklenen yerel kitaplıkları başka bir konuma kopyalamaktır. Bu, dinamik bağlayıcının dosyalarda X
bitinin ayarlanmasını gerektirdiği için zorunludur. Bu işlem, root olmayan bir adb
tarafından erişilebilen hiçbir konumda yapılamaz.
Tüm bu işlemler tamamlandıktan sonra saplama uygulaması, gerçek Application
sınıfını oluşturur 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 oluşturulması ve yüklenmesinde 4 ila 10 kat hızlanma sağlar.
Aşağıdaki sayılar, birkaç Google ürünü için hesaplanmıştır:
Bu süre, değişikliğin niteliğine bağlıdır. Örneğin, temel bir kitaplık değiştirildikten sonra yeniden derleme daha uzun sürer.
Sınırlamalar
Sahte uygulamanın oynadığı oyunlar her durumda işe yaramaz. Aşağıdaki durumlarda bant genişliği beklendiği gibi çalışmaz:
Context
,ContentProvider#onCreate()
uygulamasındaApplication
sınıfına yayınlandığında Bu yöntem, uygulama başlatılırkenApplication
sınıfının örneğini değiştirmeden önce çağrılır. Bu nedenle,ContentProvider
gerçek uygulama yerine hâlâ sahte uygulamaya referans verir. Bu,Context
öğesini bu şekilde yayınlamanız gerekmediğinden bir hata olarak değerlendirilmeyebilir ancak Google'daki birkaç uygulamada bu durumun yaşandığı görülmektedir.bazel mobile-install
tarafından yüklenen kaynaklar yalnızca uygulama içinden kullanılabilir. KaynaklaraPackageManager#getApplicationResources()
aracılığıyla diğer uygulamalar tarafından erişilirse bu kaynaklar, son artımlı olmayan yüklemeden alınır.ART'nin çalıştırılmadığı cihazlar. Stub uygulaması Froyo ve sonraki sürümlerde iyi çalışsa da Dalvik'te, kodunun belirli durumlarda (ör. Java ek açıklamaları belirli bir şekilde kullanıldığında) birden fazla .dex dosyasına dağıtılması halinde 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ışır (ancak eski Android sürümlerine yönelik desteğin önceliğimiz olmadığını unutmayın).