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_binarykuralını bulun. - Proguard'ı
proguard_specsözelliğini kaldırarak devre dışı bırakın. multidexözelliğininativeolarak ayarlayın.dex_shardsözelliğini10olarak 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. - Bekleme süresinin kısalığının keyfini çıkarın.
Bazel'e iletilebilecek ve işinize yarayabilecek bazı komut satırı seçenekleri:
--adb, Bazel'e hangi adb ikili programının kullanılacağını bildirir.--adb_arg,adbkomut satırına ekstra 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_appuygulamayı otomatik olarak başlatır
Emin değilseniz ö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ışır hâlde 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, çok sayıda tekil ve sıralı adım içerir. Android uygulaması oluşturmak için bu adımların tamamının yapılması gerekir. Google'da, tek satırlık bir değişikliği oluşturmak için beş dakika beklemek, Google Haritalar gibi daha büyük projelerde 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 gibi yöntemleri bir arada 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ştirilir.
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üresi uzar. Kullanıcılar genellikle bir uygulamayı bir kez yükleyip birçok kez kullandıkları için bu yaklaşım onlar açısından iyi bir denge sağlar. 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
dx'yı bunlar üzerinde 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 bölümlerini .apk dışından yükleme. .apk dosyasına, cihazdaki mobil yükleme dizininden Android kaynaklarını, Java kodunu ve yerel kodu yükleyen küçük bir saplama uygulaması yerleştirilir. Ardından kontrol, gerçek uygulamaya aktarılır. Bu işlemlerin tamamı, aşağıda açıklanan birkaç istisna dışında uygulama için ş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 kaydırılıyordu. Bu da parçaların tekrar 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 olduğunca az çabayla uygulamayı yüklemektir. Yükleme aşağıdaki adımlardan oluşur:
- .apk dosyasını yükleme (genellikle
adb installkullanı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ı kandırmanın mümkün olduğunu unutmayın. Bu durum, cihazdaki dosyaların sağlama toplamı hesaplanarak önlenebilirdi ancak bu çözümün, yükleme süresindeki artışa değmeyeceği düşünüldü.
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.
Uygulama sınıflarından herhangi biri yüklenmeden önce bu işlemin 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 yeniden yükleme gerektireceği anlamına gelir.
Bu, AndroidManifest.xml içinde belirtilen Application 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 gereklidir. Bu işlem, root olmayan bir adb tarafından erişilebilen herhangi bir konum için yapılamaz.
Tüm bu işlemler tamamlandıktan sonra saplama uygulaması, 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 durum, değişikliğin niteliğine bağlıdır. Örneğin, temel bir kitaplık değiştirildikten sonra yeniden derleme işlemi daha uzun sürer.
Sınırlamalar
Sahte uygulamanın kullandığı yöntemler her durumda işe yaramaz. Aşağıdaki durumlarda bant genişliği beklendiği gibi çalışmaz:
Context,ContentProvider#onCreate()içindeApplicationsınıfına yayınlandığında. Bu yöntem, uygulama başlatılırkenApplicationsınıfının örneğini değiştirmeden önce çağrılır. Bu nedenle,ContentProvidergerçek uygulama yerine hâlâ sahte uygulamaya referans verir. Bu,Contextöğesini bu şekilde yayınlamamanız gerektiğinden bir hata olarak değerlendirilmeyebilir ancak Google'daki birkaç uygulamada bu durumun yaşandığı görülüyor.bazel mobile-installtarafı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üklemeye ait olur.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ışmalıdır (ancak eski Android sürümlerine yönelik desteğin tam olarak odak noktamız olmadığını unutmayın).