Gradle'da uygulama ve derleme arasındaki fark nedir?


1027

Android Studio 3.0'a güncellenmesi ve yeni bir proje oluşturduktan sonra, ben de fark ettim build.gradleyerine yeni bağımlılıklar eklemek için yeni bir yol var compileolduğunu implementationve yerine testCompileorada testImplementation.

Misal:

 implementation 'com.android.support:appcompat-v7:25.0.0'
 testImplementation 'junit:junit:4.12'

onun yerine

 compile 'com.android.support:appcompat-v7:25.0.0'
 testCompile 'junit:junit:4.12'

Aralarındaki fark nedir ve ne kullanmalıyım?

Yanıtlar:


1280

tl; Dr.

Sadece değiştirin:

  • compileile implementation(geçişe ihtiyacınız yoksa) veya api(geçişe ihtiyacınız varsa)
  • testCompile ile testImplementation
  • debugCompile ile debugImplementation
  • androidTestCompile ile androidTestImplementation
  • compileOnlyhala geçerli. Sağlanan yerine derlemek için değil 3.0 olarak eklendi. ( providedGradle'ın bu kullanım senaryosu için bir yapılandırma adı olmadığında tanıtıldı ve Maven'in sağladığı kapsamdan sonra adlandırıldı.)

Google'ın IO17'de duyurduğu Gradle 3.0 ile gelen en önemli değişikliklerden biri .

compileYapılandırma edilir karakteri artık ve değiştirilmesi gerektiğini implementationya daapi

Gönderen Gradle belgeler :

dependencies {
    api 'commons-httpclient:commons-httpclient:3.1'
    implementation 'org.apache.commons:commons-lang3:3.5'
}

apiKonfigürasyonlarda görünen bağımlılıklar , kütüphanenin tüketicilerine geçişli olarak maruz kalacak ve bu nedenle tüketicilerin derleme sınıfyolunda görünecektir.

implementationKonfigürasyonda bulunan bağımlılıklar , diğer taraftan, tüketicilere maruz kalmayacak ve bu nedenle tüketicilerin derleme sınıfyoluna sızmayacaktır. Bunun birkaç faydası vardır:

  • bağımlılıklar artık tüketicilerin derleme sınıfyoluna sızmıyor, bu yüzden asla yanlışlıkla geçişsel bağımlılığa bağlı olmayacaksınız
  • azaltılmış sınıfyolu boyutu sayesinde daha hızlı derleme
  • uygulama bağımlılıkları değiştiğinde daha az yeniden derleme: tüketicilerin yeniden derlenmesi gerekmez
  • daha temiz yayınlama: Yeni maven-yayımlama eklentisi ile birlikte kullanıldığında, Java kütüphaneleri, kütüphaneye karşı derlemek için gereken ile kitaplığı çalışma zamanında kullanmak için gerekenleri tam olarak ayıran POM dosyaları üretir (başka bir deyişle, kütüphanenin kendisini derlemek için gerekli olanı ve kütüphaneye karşı derlemek için gerekeni karıştırın).

Derleme yapılandırması hala mevcuttur, ancak apive implementationyapılandırmalarının sağladığı garantileri sunmayacağından kullanılmamalıdır .


Not: Uygulama modülünüzde yalnızca ortak bir kitaplık kullanıyorsanız (genel durum) herhangi bir fark görmezsiniz.
farkı yalnızca birbirine bağlı modüller içeren karmaşık bir projeniz varsa veya bir kitaplık oluşturuyorsanız göreceksiniz.


137
"Tüketiciler" kimlerdir?
Suragch

34
tüketici kütüphaneyi kullanan modüldür. Android söz konusu olduğunda Android uygulamasıdır. Bence bu açık ve istediğin şey bu mu emin değilim.
17'de

21
Bana da öyle geliyordu. Ancak bir kütüphane hazırlıyorsam, elbette API'sinin uygulamaya maruz kalmasını istiyorum. Aksi takdirde, uygulama geliştiricisi kitaplığımı nasıl kullanır? Bu yüzden implementationbağımlılığı saklamanın anlamını anlamıyorum . Sorum mantıklı mı?
17'de Suragch

235
evet, uygulamanızın kendisi y, z'ye bağlı olan x kütüphanesine bağlıysa, şimdi mantıklı. kullanmak durumunda implementationyalnızca x API maruz, ancak kullanımı ise apiy, z, aynı zamanda maruz kalırlar.
17'de

36
Anladım! Bu şimdi daha mantıklı. Bu açıklamayı cevabınıza ekleyebilirsiniz. Alıntılanan belgelerden daha açıktır.
Suragch

378

Bu cevap arasındaki farkı gösterecektir implementation, apive compilebir proje üzerinde.


Diyelim ki üç Gradle modülüne sahip bir projem var:

  • uygulaması (bir Android uygulaması)
  • myandroidlibrary (bir Android kütüphanesi)
  • myjavalibrary (bir Java kütüphanesi)

appvardır myandroidlibrarybağımlılıkları olarak. myandroidlibraryvardır myjavalibrary bağımlılıkları olarak.

Dependency1

myjavalibrarybir MySecretsınıfı var

public class MySecret {

    public static String getSecret() {
        return "Money";
    }
}

myandroidlibraryyer alır MyAndroidComponentdeğeri işlemek sınıfı MySecretsınıfı.

public class MyAndroidComponent {

    private static String component = MySecret.getSecret();

    public static String getComponent() {
        return "My component: " + component;
    }    
}

Son olarak, appyalnızcamyandroidlibrary

TextView tvHelloWorld = findViewById(R.id.tv_hello_world);
tvHelloWorld.setText(MyAndroidComponent.getComponent());

Şimdi bağımlılıklar hakkında konuşalım ...

apptüketmek gerekir :myandroidlibrary, bu yüzden appbuild.gradle kullanımı implementation.

( Not : api / compile komutunu da kullanabilirsiniz. Ama bu düşünceyi bir anlığına saklayın.)

dependencies {
    implementation project(':myandroidlibrary')      
}

Dependency2

Ne düşünüyorsunuz myandroidlibrarybuild.gradle gibi görünmelidir? Hangi kapsamı kullanmalıyız?

Üç seçeneğimiz var:

dependencies {
    // Option #1
    implementation project(':myjavalibrary') 
    // Option #2
    compile project(':myjavalibrary')      
    // Option #3
    api project(':myjavalibrary')           
}

Dependency3

Aralarındaki fark nedir ve ne kullanmalıyım?

Derleme veya Api (seçenek # 2 veya # 3) Dependency4

compileVeya kullanıyorsanız api. Android Uygulamamız artık myandroidcomponentbir MySecretsınıf olan bağımlılığa erişebiliyor .

TextView textView = findViewById(R.id.text_view);
textView.setText(MyAndroidComponent.getComponent());
// You can access MySecret
textView.setText(MySecret.getSecret());

Uygulama (seçenek # 1)

Dependency5

implementationYapılandırmayı kullanıyorsanız , gösterilmez MySecret.

TextView textView = findViewById(R.id.text_view);
textView.setText(MyAndroidComponent.getComponent());
// You can NOT access MySecret
textView.setText(MySecret.getSecret()); // Won't even compile

Peki, hangi yapılandırmayı seçmelisiniz? Bu gerçekten gereksiniminize bağlıdır.

Eğer varsa bağımlılıkları sergilemek istediğiniz kullanımını apiveya compile.

Eğer varsa bağımlılıkları ortaya çıkarmak istemiyoruz (dahili modül gizleme) daha sonra kullanmak implementation.

Not:

Bu sadece Gradle yapılandırmalarının bir özeti, bkz. Tablo 49.1. Java Library eklentisi - daha ayrıntılı açıklama için bağımlılıkları bildirmek üzere kullanılan yapılandırmalar .

Bu cevap için örnek proje https://github.com/aldoKelvianto/ImplementationVsCompile adresinde mevcuttur.


1
Ben neden hala almak mümkün ve benim kod iyi çalışıyor erişimini açık değilse uygulama kullanarak bir kavanoz dosyasına bağımlılık eklemek var?
smkrn110

@ smkrn110 uygulaması jar kitaplığınızı ortaya koyar, ancak jar bağımlılık kitaplıklarınızı göstermez.
aldok

2
@WijaySharma kabul edilen cevap compile, aynı şeyleri garanti etmediğini belirtir api.
Alt 6 Kaynaklar

9
Bunun kabul edilen cevap olması gerektiğini düşünüyorum. İyi açıkladı!
Shashank Kapsime

9
@ StevenW.Klassen, şimdiye kadar duyduğum en hak edilmemiş downvote. Bilgi sırasının uygun olmadığını düşünüyorsanız, şikayet etmek yerine bir düzenleme önerin
Tim

65

Compileyapılandırma onaylanmadı ve implementationveya ile değiştirilmelidir api.

Dokümanları https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_separation adresinden okuyabilirsiniz .

Kısa kısım,

Standart Java eklentisi ve Java Kütüphanesi eklentisi arasındaki temel fark, ikincisinin tüketicilere maruz kalan bir API kavramını tanıtmasıdır. Kütüphane, diğer bileşenler tarafından tüketilmesi amaçlanan bir Java bileşenidir. Çok projeli yapılarda çok yaygın bir kullanım durumudur, ancak dış bağımlılıklarınız olur olmaz.

Eklenti bağımlılıkları bildirmek için kullanılabilecek iki yapılandırma ortaya koyar: api ve application. Api yapılandırması, kütüphane API'sı tarafından dışa aktarılan bağımlılıkları bildirmek için kullanılmalı, uygulama yapılandırması ise bileşenin içindeki bağımlılıkları bildirmek için kullanılmalıdır.

Daha fazla açıklama için bu resme bakın. Kısa açıklama


46

Kısa Çözüm:

Daha iyi yaklaşım, tüm compilebağımlılıkları bağımlılıklarla değiştirmektir implementation. Ve sadece bir modülün arayüzünü sızdıran yerde kullanmalısın api. Bu çok daha az yeniden derlemeye neden olmalıdır.

 dependencies {
         implementation fileTree(dir: 'libs', include: ['*.jar'])

         implementation 'com.android.support:appcompat-v7:25.4.0'
         implementation 'com.android.support.constraint:constraint-layout:1.0.2'
         // …

         testImplementation 'junit:junit:4.12'
         androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
             exclude group: 'com.android.support', module: 'support-annotations'
         })
 }

Daha fazla açıklamak:

Android Gradle eklentisi 3.0'dan önce : tek bir kod değişikliği olan tüm modüllerin yeniden derlenmesine neden olan büyük bir sorunumuz vardı. Bunun temel nedeni Gradle'ın bir modülün arayüzünü başka bir modül üzerinden sızdırıp sızdırmadığınızı bilmemesidir.

Android Gradle eklentisi 3.0'dan sonra : en son Android Gradle eklentisi artık bir modülün arayüzünü sızdırıp sızdırmadığınızı açıkça tanımlamanızı gerektiriyor. Buna dayanarak, neyi yeniden derlemesi gerektiği konusunda doğru seçimi yapabilir.

Bu nedenle compilebağımlılık reddedildi ve yerine iki yenisi eklendi:

  • api: bu modülün arayüzünü kendi arayüzünüzden sızdırıyorsunuz, yani eski compilebağımlılıkla tamamen aynı

  • implementation: bu modülü yalnızca dahili olarak kullanırsınız ve arayüzünüz üzerinden sızdırmaz

Şimdi Gradle'a, kullanılmış bir modülün arayüzü değişirse veya değişmezse bir modülü yeniden derlemesini açıkça söyleyebilirsiniz.

İzniyle Jeroen Mols blogda


2
Temiz ve özlü açıklama. Teşekkürler!
LeOn - Han Li

20
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| Name               | Role                 | Consumable? | Resolveable? | Description                             |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| api                | Declaring            |      no     |      no      | This is where you should declare        |
|                    | API                  |             |              | dependencies which are transitively     |
|                    | dependencies         |             |              | exported to consumers, for compile.     |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| implementation     | Declaring            |      no     |      no      | This is where you should                |
|                    | implementation       |             |              | declare dependencies which are          |
|                    | dependencies         |             |              | purely internal and not                 |
|                    |                      |             |              | meant to be exposed to consumers.       |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| compileOnly        | Declaring compile    |     yes     |      yes     | This is where you should                |
|                    | only                 |             |              | declare dependencies                    |
|                    | dependencies         |             |              | which are only required                 |
|                    |                      |             |              | at compile time, but should             |
|                    |                      |             |              | not leak into the runtime.              |
|                    |                      |             |              | This typically includes dependencies    |
|                    |                      |             |              | which are shaded when found at runtime. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| runtimeOnly        | Declaring            |      no     |      no      | This is where you should                |
|                    | runtime              |             |              | declare dependencies which              |
|                    | dependencies         |             |              | are only required at runtime,           |
|                    |                      |             |              | and not at compile time.                |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| testImplementation | Test dependencies    |      no     |      no      | This is where you                       |
|                    |                      |             |              | should declare dependencies             |
|                    |                      |             |              | which are used to compile tests.        |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| testCompileOnly    | Declaring test       |     yes     |      yes     | This is where you should                |
|                    | compile only         |             |              | declare dependencies                    |
|                    | dependencies         |             |              | which are only required                 |
|                    |                      |             |              | at test compile time,                   |
|                    |                      |             |              | but should not leak into the runtime.   |
|                    |                      |             |              | This typically includes dependencies    |
|                    |                      |             |              | which are shaded when found at runtime. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| testRuntimeOnly    | Declaring test       |      no     |      no      | This is where you should                |
|                    | runtime dependencies |             |              | declare dependencies which              |
|                    |                      |             |              | are only required at test               |
|                    |                      |             |              | runtime, and not at test compile time.  |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+

Doğrudan soruya cevap vermiyor
skryvets

1
Ayrıca bir gelişme var Sadece
Hohenheimsenberg

Hem çalışma zamanı hem de derleme süresine ihtiyacım olursa ne kullanmalıyım? Şu anda implementationbir a runtime.
Maroun

8

Layman'ın dönemindeki kısa fark:

  • Belirtilen bağımlılığın üyelerini açığa çıkararak diğer modüllere destek sağlayan bir arabirim veya modül üzerinde çalışıyorsanız, 'api' kullanmalısınız.
  • Belirtilen bağımlılığı dahili olarak uygulayacak veya kullanacak bir uygulama veya modül yapıyorsanız, 'uygulama' kullanın.
  • 'derleme', 'api' ile aynı şekilde çalıştı, ancak yalnızca herhangi bir kütüphane uyguluyorsanız veya kullanıyorsanız, 'uygulama' daha iyi çalışacak ve size kaynak tasarrufu sağlayacaktır.

kapsamlı bir örnek için @ aldok'un cevabını okuyun.


Ama mesele şu ki, eğer bir kişi kasten bu soruların cevabını aramak için geldiyse, o zaman sonuçta bir meslekten olmayan biri değildir.
Rishav

6

Sürüm 5.6.3 Gradle belgeleri , eski bir compilebağımlılığın (veya yeni bir bağımlılığın) bir implementationveya apibağımlılıkla değiştirilmesi gerekip gerekmediğini belirlemek için basit kurallar sağladığından :

  • Tercih implementationbile yapılandırmayı apimümkün olduğunda

Bu, bağımlılıkları tüketicinin derleme sınıfyolundan uzak tutar. Ayrıca, yanlışlıkla herhangi bir uygulama türü genel API'ya sızarsa, tüketiciler derhal derlenemez.

Peki apiyapılandırmayı ne zaman kullanmalısınız ? API bağımlılığı, çoğu zaman ABI (Uygulama İkili Arayüzü) olarak adlandırılan kütüphane ikili arayüzünde gösterilen en az bir tür içeren bir bağımlılıktır. Bu aşağıdakileri içerir, ancak bunlarla sınırlı değildir:

  • süper sınıflarda veya arayüzlerde kullanılan tipler
  • genel parametre parametrelerinde kullanılan türler (genel parametre türleri dahil) (burada halka derleyiciler tarafından görülebilen bir şeydir. Yani, Java dünyasındaki genel, korunan ve özel üyeleri paketleyin)
  • ortak alanlarda kullanılan tipler
  • genel ek açıklama türleri

Aksine, aşağıdaki listede kullanılan herhangi bir tür ABI ile ilgisizdir ve bu nedenle implementationbağımlılık olarak bildirilmelidir :

  • sadece yöntem gövdelerinde kullanılan tipler
  • özel üyelerde özel olarak kullanılan tipler
  • yalnızca dahili sınıflarda bulunur (Gradle'ın gelecekteki sürümleri, hangi paketlerin genel API'ya ait olduğunu bildirmenize izin verir)

6

Gradle 3.0 sonraki değişiklikleri tanıttı:

  • compile -> api

    api anahtar kelime kullanımdan kaldırılmışla aynı compile

  • compile -> implementation

    tercih bazı avantajları vardır, çünkü yol. implementationbağımlılığı derleme süresinde yalnızca bir seviye yukarı için gösterme (bağımlılık çalışma zamanında kullanılabilir). Sonuç olarak daha hızlı bir yapıya sahip olursunuz (1 seviyeden daha yüksek tüketicileri yeniden derlemeye gerek yoktur)

  • provided -> compileOnly

    Bu bağımlılık yalnızca derleme zamanında kullanılabilir (bağımlılık çalışma zamanında kullanılamaz). Bu bağımlılık geçişli olamaz ve olamaz .aar. Derleme zamanı ek açıklama işlemcisi ile kullanılabilir ve son çıktı dosyasını azaltmanıza olanak tanır

  • compile -> annotationProcessor

    compileOnlyGeçişsel bağımlılığın tüketici tarafından görülememesine çok benzer, fakat aynı zamanda garanti eder

  • apk -> runtimeOnly

    Bağımlılık derleme zamanında kullanılamaz, ancak çalışma zamanında kullanılabilir.


Yani başka bir deyişle, api = public, implementation = internalve compileOnly = private- Onların süper kafa karıştırıcı gibi bu fonksiyonlar için böyle bir takma ad oluşturmak gerekir.
t3chb0t
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.