[Android] 在Gradle中實現和編譯有什麼區別


Answers

這個答案將展示項目implementationapicompile之間的區別。 假設我有一個包含三個Gradle模塊的項目:

  • 應用程序(Android應用程序)
  • myandroidlibrary(一個Android庫)
  • myjavalibrary(一個Java庫)

app已將myandroidlibrary作為依賴項。 myandroidlibrarymyjavalibrary作為依賴關係。

應用程序 - > myandroidlibrary - > myjavalibrary

myjavalibrary有一個MySecret

public class MySecret {

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

myandroidlibrary具有MyAndroidComponent類,用於處理MySecret類中的值。

public class MyAndroidComponent {

    private static String component = MySecret.getSecret();

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

最後, app只對myandroidlibrary的價值myandroidlibrary

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

現在,我們來討論一下app build.gradle的依賴關係。 它非常簡單直觀。

dependencies {
    implementation project(':myandroidlibrary')      
}

你認為myandroidlibrary build.gradle應該是什麼樣子的? 我們有三種選擇:

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

他們和我應該使用什麼有什麼區別?

編譯和Api

如果你使用的是compileapi 。 我們的Android應用程序現在能夠訪問myandroidcomponent依賴項,這是一個MySecret類。

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

履行

如果您使用implementation配置,則不公開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

那麼,你應該選擇哪種配置? 這真的取決於你的要求。

如果你想公開依賴使用apicompile ,如果你不想公開依賴(隱藏你的內部模塊),然後使用implementation

這只是Gradle配置的一個要點,請參閱表49.1。 Java庫插件 - 用於聲明依賴關係的配置以獲取更詳細的解釋。

Question

在更新到Android Studio 3.0並創建一個新項目後,我注意到在build.gradle有一種新的方法來添加新的依賴項,而不是compileimplementation ,而不是testCompiletestImplementation

例:

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

代替

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

他們和我應該使用什麼有什麼區別?




簡要解答:

更好的方法是用implementation依賴關係替換所有的compile依賴關係。 只有當你洩漏模塊的接口時,你應該使用api 。 這應該會導致很少的重新編譯。

 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'
         })
 }

解釋更多:

在Android Gradle插件3.0之前 :我們遇到了一個很大的問題,那就是一次代碼更改導致所有模塊重新編譯。 造成這種情況的根本原因是Gradle不知道是否通過另一個模塊洩漏了模塊的接口。

在Android Gradle插件3.0之後 :最新的Android Gradle插件現在需要您明確定義是否洩露模塊的接口。 基於此,它可以對應該重新編譯的內容做出正確的選擇。

因此, compile依賴已被棄用,並由兩個新的替代:

  • api :你通過你自己的接口洩漏了這個模塊的接口,這意味著和舊的compile依賴完全一樣

  • implementation :你只在內部使用這個模塊,不會通過你的接口洩漏它

所以現在你可以明確地告訴Gradle如果所使用的模塊的接口改變或不改變,就重新編譯一個模塊。

致謝Jeroen Mols博客