Gradle Uygulaması ve API yapılandırması


232

Bağımlılıklarımı oluştururken arasındaki fark apive implementationyapılandırma arasındaki farkı anlamaya çalışıyorum .
Belgelerde, bunun implementationdaha iyi inşa süresi olduğunu söylüyor , ancak benzer bir soruda bu yorumu görünce bunun doğru olup olmadığını merak ettim.
Gradle konusunda uzman olmadığım için umarım birisi yardımcı olabilir. Belgeleri zaten okudum ama anlaşılması kolay bir açıklama merak ediyordum.


1
Burada okudun mu?
MatPag

gerçekte olduğu gibi, yaptım, ama dediğim gibi, bu yorum bunu merak etti. bu yüzden biraz kayboldum
reinaldomoreira

Muhtemelen kitaplık bağımlılıklarınızı olarak compiledeğiştireceksiniz api. Dahili olarak kullandığınız kütüphaneler, son kütüphanede gösterilmeyen bazı özel uygulamaları kullanabilir, böylece size şeffaf olurlar. Bu "dahili-özel" bağımlılıklar değiştirilebilir implementationve Android sınıfındaki eklenti uygulamanızı derlediğinde, bu bağımlılıkların derlenmesini atlayarak daha kısa bir oluşturma süresine neden olur (ancak bu bağımlılıklar çalışma zamanında kullanılabilir olacaktır). Yerel modül kütüphaneleriniz varsa aynı şeyi yapabilirsiniz
MatPag

1
İşte 'api' ve 'uygulama' ile ilgili kısa bir grafik açıklama: jeroenmols.com/blog/2017/06/14/androidstudio3
albert c braun

1
bu harika bir gönderi! thank you @albertbraun
reinaldomoreira

Yanıtlar:


419

Gradle compileanahtar kelimesi, bağımlılıkları yapılandırmak için apive implementationanahtar kelimeleri lehine kullanımdan kaldırıldı .

Kullanılması apikaldırılmış kullanmanın eşdeğerdir compiletüm değiştirmek eğer öyleyse, compileile apiher şey olacak her zaman olduğu gibi çalışır.

implementationAnahtar kelimeyi anlamak için aşağıdaki örneği inceleyin.

MİSAL

Diyelim MyLibraryki dahili olarak adlandırılan başka bir kitaplık kullanan bir kitaplığınız var InternalLibrary. Bunun gibi bir şey:

    // 'InternalLibrary' module
    public class InternalLibrary {
        public static String giveMeAString(){
            return "hello";
        }
    }
    // 'MyLibrary' module
    public class MyLibrary {
        public String myString(){
            return InternalLibrary.giveMeAString();
        }
    }

Diyelim ki MyLibrary build.gradlekullanım apikonfigürasyonu dependencies{}şöyle:

dependencies {
    api project(':InternalLibrary')
}

MyLibraryKodunuzda kullanmak istiyorsunuz, böylece uygulamanızda build.gradlebu bağımlılığı ekliyorsunuz:

dependencies {
    implementation project(':MyLibrary')
}

Kullanılması apikonfigürasyonunu (ya kaldırılmış compileerişebileceğiniz) InternalLibraryuygulama kodunuzda:

// Access 'MyLibrary' (granted)
MyLibrary myLib = new MyLibrary();
System.out.println(myLib.myString());

// Can ALSO access the internal library too (and you shouldn't)
System.out.println(InternalLibrary.giveMeAString());

Bu şekilde modül MyLibrarypotansiyel olarak bir şeyin dahili uygulamasını "sızdırıyor". Bunu doğrudan kullanmanız gerekmediği için kullanmamalısınız (kullanamamalısınız).

Bunu implementationönlemek için yapılandırma tanıtıldı. Yani şimdi in implementationyerine kullanırsanız :apiMyLibrary

dependencies {
    implementation project(':InternalLibrary')
}

InternalLibrary.giveMeAString()artık uygulama kodunuzu arayamayacaksınız .

Boks stratejinin Bu tür Android Gradle içinde düzenleme şey olmadığını bilmek eklentisi verir InternalLibrary, sadece bir recompilation tetiklemek gerekir MyLibraryve değil Erişiminizin olmadığı için, tüm uygulamanın recompilation InternalLibrary.

Çok fazla iç içe bağımlılığınız olduğunda, bu mekanizma yapıyı çok hızlandırabilir. (Bunu tam olarak anlamak için sonunda bağlanan videoyu izleyin)

SONUÇLAR

  • Eğer 3.xx eklentisi Yeni Android Gradle geçtiğinizde, tüm değiştirmeniz gerekir compileile implementationanahtar kelime (1 *) . Ardından uygulamanızı derlemeye ve test etmeye çalışın. Her şey yolundaysa, kodu olduğu gibi bırakın, sorunlarınız varsa muhtemelen bağımlılıklarınızda yanlış bir şeyiniz var veya şimdi özel ve daha erişilebilir olmayan bir şey kullandınız. Android Gradle eklentisi mühendisi Jerome Dochez (1 ) * ) tarafından öneri

  • Bir kütüphane yöneticisi iseniz , son kullanıcılar tarafından kullanılmaması gereken test bağımlılıkları veya bağımlılıkları için apikullanırken, kitaplığınızın genel API'si için gereken her bağımlılık için kullanmalısınız implementation.

Uygulama ve API arasındaki farkı gösteren faydalı makale

REFERANSLAR (Bu, zamandan kazanmak için ayrılmış video ile aynıdır)

Google I / O 2017 - Gradle'ın hızlandırılması (TAM VİDEO)

Google I / O 2017 - Gradle'ı nasıl hızlandırır (SADECE YENİ GRADLE PLUGIN 3.0.0 BÖLÜMÜ)

Google I / O 2017 - Gradle'ın oluşturma hızını artırma ( 1 * referansı )

Android belgeleri


4
API'nin kütüphane modüllerinde iyi çalışmadığını fark ettim. Eğer kullanırsam, hala uygulama projemden bağımlılıklara erişemiyorum. Bu kitaplıktaki koda sadece erişebilirim.
Allan W

1
Bu iyidir ve hata ayıklama yapıları üzerinde çalışır ancak ProGuard (sürümlerinde) kullanırken ProGuard kaldırılmış MyLibrary#myString()olacağı için çökecektir InternalLibrary. Android-libs için ProGuard uygulamalarında kullanılacak en iyi uygulama hangisidir?
hardysim

3
Cevabın doğru olmadığını düşünüyorum, uygulama MyLibrary için istediği kapsamı kullanabilir. MyLibrary'nin api / application kullanıp kullanmadığına bağlı olarak InternalLibrary öğesini görür veya görmez.
Snicolas

2
teşekkürler dostum. müthiş bir açıklama, android'in resmi belgelerinde verilenlerden çok daha iyi
Henry

2
bu güzel bir açıklama. Teori ve beton zekice karıştı. Aferin. Bunun için teşekkürler
Peter Kahn

134

Bir konuda düşünmek istiyorum apiolarak bağımlılık halka (diğer modüllerle tarafından görülen) ise implementationolarak bağımlılık özel (sadece bu modül tarafından görülen).

public/ privateDeğişkenler ve yöntemlerin aksine , api/ implementationbağımlılıklarının çalışma zamanı tarafından zorlanmadığını unutmayın. Bu yalnızca Gradle, bağımlılıklardan biri API'sını değiştirdiğinde hangi modüllerin yeniden derlenmesi gerektiğini bilmenizi sağlayan bir oluşturma zamanı optimizasyonudur .


16
Bu cevabın basitliğini çok seviyorum Çok teşekkür ederim
Kevin Gilles

2
Gerçek fark (AFAICT), oluşturulan pom dosyasının api"derleme" kapsamına (kitaplığınıza bağımlılık ve kitaplığınıza bağlı herhangi bir şey olarak dahil edilecektir) implementationbağımlılıkları ve "çalışma zamanı" kapsamına bağımlılıkları koymasıdır ( kodunuz çalışırken sınıfyolunu kullanabilirsiniz, ancak kitaplığınızı kullanan diğer kodları derlemelerine gerek yoktur).
Gölge Adam

@ShadowMan Eklentinin, POM dosyasını oluşturmaktan ve Gradle kapsamlarını Maven kapsamlarıyla nasıl eşleştirmesinden sorumlu bir uygulama detayıdır .
dev.bmax

1
Sen kullanmalıdır implementationçalıştırmak için gerekli (ve derleme için kütüphane için) herhangi bir bağımlılık için, ama bu automagicallylar kütüphanenizi kullanmak projelerine çekti edilmemelidir. Bir örnek jax-rs olabilir, kütüphaneniz RESTeasy kullanabilir, ancak bunun yerine Jersey kullanmak isteyebileceğinden bu kütüphaneleri kütüphanenizi kullanan herhangi bir projeye çekmemelidir.
Gölge Adam

1
Birinin eşyalarını aldığını şu şekilde bilirsiniz: D Basit ve net cevap için teşekkürler
Elias Fazel

12

Kütüphane olarak kullanan ve kütüphane olarak appkullanan lib1bir modülünüz olduğunu düşünün . Böyle bir şey: .lib1lib2app -> lib1 -> lib2

Kullanırken Şimdi api lib2de lib1, sonra da app görebilirsiniz lib2 kullanırken kodları: api lib1ya implementation lib1içinde appmodül.

Kullanırken AMA implementation lib2içinde lib1, o zaman app göremiyorumlib2 kodları.


5

@Matpag ve @ dev-bmax'dan gelen yanıtlar, kullanıcıların uygulama ve api arasındaki farklı kullanımları anlamalarını sağlayacak kadar açıktır. Sadece başka bir açıdan daha fazla açıklama yapmak istiyorum, aynı soruya sahip olan insanlara yardım etmeyi umuyorum.

Test için iki proje hazırladım:

  • 'frameworks-web-gradle-plugin' adlı bir java kütüphane projesi olarak A projesi 'org.springframework.boot: spring-boot-gradle-plugin: 1.5.20.RELEASE' belgesine bağlıdır.
  • B projesi 'com.example.frameworks.gradle: frameworks-web-gradle-plugin: 0.0.1-SNAPSHOT' uygulamasıyla A projesine bağlıdır.

Yukarıda açıklanan bağımlılık hiyerarşisi şöyle görünür:

[project-b] -> [project-a] -> [bahar önyükleme-gradle-eklentisi]

Sonra aşağıdaki senaryoları test ettim:

  1. Tarafından yap projesi A '1.5.20.RELEASE: yay önyükleme gradle-eklentisi org.springframework.boot' bağlıdır uygulanması .

    gradle dependenciesPoject B kök dizinindeki bir terminalde komutu çalıştırın following Aşağıdaki çıktı ekran görüntüsü ile 'spring-boot-gradle-plugin' in runtimeClasspath bağımlılıkları ağacında göründüğünü görebiliriz, ancak compileClasspath'larda değil, tam olarak bu yüzden yapamıyoruz uygulama kullanılarak bildirilen kütüphane kullanımı, sadece derleme yoluyla olmaz.

    resim açıklamasını buraya girin

  2. Yap projesi A bağlıdır 'org.springframework.boot: yay önyükleme gradle-eklentisi: 1.5.20.RELEASE' tarafından api

    Run gradle dependenciestekrar poject B kök dir in terminalde komutu. Şimdi 'spring-boot-gradle-plugin' hem compileClasspath hem de runtimeClasspath bağımlılıkları ağacında görünür.

    resim açıklamasını buraya girin

Fark ettiğim önemli bir fark, uygulama şeklinde bildirilen üretici / kütüphane projesine bağımlılığın compileClasspath tüketici projesinde görünmeyeceğidir, böylece tüketici projelerinde karşılık gelen lib'i kullanamayız.


2

Gönderen gradle belgeler :

Şimdi JVM tabanlı bir proje için çok basit bir derleme dosyasına bakalım.

plugins {
    id 'java-library'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.hibernate:hibernate-core:3.6.7.Final'
    api 'com.google.guava:guava:23.0'
    testImplementation 'junit:junit:4.+'
}

uygulama

Proje tarafından ortaya konulan API'nın bir parçası olmayan, projenin üretim kaynağını derlemek için gereken bağımlılıklar. Örneğin proje, dahili kalıcılık katmanı uygulaması için Hazırda Beklet'i kullanır.

api

Projenin maruz kaldığı API'nın bir parçası olan projenin üretim kaynağını derlemek için gereken bağımlılıklar. Örneğin, proje Guava'yı kullanır ve yöntem imzalarında Guava sınıflarıyla ortak arabirimleri ortaya koyar.

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.