Реализация Gradle против конфигурации API

Я пытаюсь понять, в чем разница между api а также implementation конфигурация при построении моих зависимостей.
В документации сказано, что implementation имеет лучшее время сборки, но, увидев этот комментарий в аналогичном вопросе, я задался вопросом, правда ли это.
Так как я не специалист в Gradle, я надеюсь, что кто-то может помочь. Я уже прочитал документацию, но мне было интересно найти простое объяснение.

8 ответов

Решение

Я думаю, что эта тема нуждается в немного большем освещении, потому что, возможно, это не так актуально для каждого разработчика.

Gradle compile Ключевое слово устарело в пользу нового api а также implementation ключевые слова.

Я не буду объяснять apiпотому что это то же самое, что и использование старого compileтак что если вы замените все свои compile с api все будет работать как всегда.

Чтобы понять implementation Ключевое слово нам нужен пример.

ПРИМЕР

У нас есть эта библиотека называется MyLibrary где внутри мы используем другую библиотеку под названием InternalLibrary, Что-то вроде этого:

//internal library module
public class InternalLibrary {
    public static String giveMeAString(){
        return "hello";
    }
}

//my library module
public class MyLibrary {
    public String myString(){
        return InternalLibrary.giveMeAString();
    }
}

build.gradle зависимости MyLibrary это вот так:

dependencies {
    api project(':InternalLibrary')
}

Теперь в вашем коде вы хотите использовать MyLibrary так что вы должны иметь build.gradle с этой зависимостью

dependencies {
    api project(':MyLibrary')
}

В коде вашего приложения, с api ключевое слово (или используя старый compile) вы можете получить доступ к обоим MyLibrary а также InternalLibrary,

//so you can access the library (as it should)
MyLibrary myLib = new MyLibrary();
System.out.println(myLib.myString());

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

Таким образом, вы потенциально "пропускаете" внутреннюю реализацию чего-то, что вы не должны использовать, потому что оно не импортировано вами напрямую.

Чтобы предотвратить это, Gradle создал новый implementation ключевое слово, так что теперь, если вы переключитесь api в implementation в вашем MyLibrary

dependencies {
    implementation project(':InternalLibrary')
}

И в вашем приложении build.gradle

dependencies {
    implementation project(':MyLibrary')
}

ты не сможешь позвонить InternalLibrary.giveMeAString() в коде вашего приложения больше. Хотя если MyLibrary использует api ключевое слово для импорта InternalLibrary, в вашем приложении вы сможете звонить InternalLibrary.giveMeAString() без проблем, самостоятельно, если вы используете api или же implementation добавить MyLibrary в ваше приложение.

Используя такую ​​стратегию бокса, плагин Android Gradle знает, что если вы редактируете что-то в InternalLibrary это вызовет перекомпиляцию MyLibrary только. Это не вызовет перекомпиляцию всего вашего приложения, потому что у вас нет доступа к InternalLibrary, Этот механизм, когда у вас много вложенных зависимостей, может значительно ускорить сборку.(Смотрите видео в конце для полного понимания)

ВЫВОДЫ

  • Когда вы переключаетесь на новый плагин Android Gradle 3.XX, вы должны заменить все свои compile с implementation ключевое слово (1 *). Затем попробуйте скомпилировать и протестировать ваше приложение. Если все в порядке, оставьте код как есть, если у вас есть проблемы, возможно, у вас что-то не так с вашими зависимостями, или вы использовали что-то, что сейчас является приватным и не более доступным. Предложение от инженера плагинов Gradle для Android Джерома Дочеза (1) *)

  • Если вы управляете библиотекой, вы должны использовать api для каждой зависимости, которая необходима для публичного API вашей библиотеки, при использовании implementation для тестовых зависимостей или зависимостей, которые не должны использоваться конечными пользователями.

ССЫЛКИ(Это то же видео, разделенное для экономии времени)

Google I / O 2017 - Как ускорить сборку Gradle (ПОЛНОЕ ВИДЕО)

Google I / O 2017 - Как ускорить сборку Gradle (ТОЛЬКО ДЛЯ НОВОЙ GRADLE PLUGIN 3.0.0)

Google I / O 2017 - Как ускорить сборку Gradle (ссылка на 1 *)

Android документация

Мне нравится думать о api зависимость как публичная (видимая другими модулями) implementation зависимость как частная (видна только этому модулю).

Обратите внимание, что в отличие от public/private переменные и методы, api/implementation зависимости не применяются во время выполнения. Это просто оптимизация во время сборки, которая позволяет Gradle знать, какие модули нужно перекомпилировать, когда одна из зависимостей меняет свой API.

Считайте, что у вас есть app модуль, который использует lib1 как библиотека и lib1 использования lib2 как библиотека. Что-то вроде этого: app -> lib1 -> lib2,

Теперь при использовании api lib2 в lib1, затем app можно увидеть lib2 коды при использовании: api lib1 или же implementation lib1 в app модуль.

НО при использовании implementation lib2 в lib1, затем app не может видеть lib2 коды.

Пожалуйста, перейдите по ссылке: Конфигурация зависимостей Android Studio доступна на официальном сайте разработчиков Android.

Внутри блока зависимостей вы можете объявить зависимость библиотеки, используя одну из нескольких различных конфигураций зависимостей (например, реализацию, показанную выше). Каждая конфигурация зависимости предоставляет Gradle разные инструкции о том, как использовать зависимость.

реализация

Gradle добавляет зависимость в путь к классам компиляции и упаковывает зависимость в выходные данные сборки. Однако, когда ваш модуль настраивает зависимость реализации, он сообщает Gradle, что вы не хотите, чтобы модуль передавал зависимость другим модулям во время компиляции. То есть зависимость доступна другим модулям только во время выполнения. Использование этой конфигурации зависимостей вместо API или компиляции (устарело) может привести к значительному улучшению времени сборки, поскольку это уменьшает количество модулей, которые система сборки должна перекомпилировать. Например, если зависимость реализации изменяет свой API, Gradle перекомпилирует только эту зависимость и модули, которые напрямую от нее зависят. Большинство модулей приложений и тестов должны использовать эту конфигурацию.

API

Gradle добавляет зависимость к пути к классам компиляции и сборке. Когда модуль включает зависимость API, он сообщает Gradle, что модуль хочет транзитивно экспортировать эту зависимость в другие модули, чтобы она была доступна им как во время выполнения, так и во время компиляции. Эта конфигурация ведет себя так же, как компиляция (которая теперь устарела), но ее следует использовать с осторожностью и только с зависимостями, которые необходимо транзитивно экспортировать другим вышестоящим потребителям. Это связано с тем, что если зависимость API изменяет свой внешний API, Gradle перекомпилирует все модули, имеющие доступ к этой зависимости во время компиляции. Таким образом, наличие большого количества зависимостей API может значительно увеличить время сборки. Если вы не хотите предоставлять API зависимости отдельному модулю, библиотечные модули должны вместо этого использовать зависимости реализации.

Еще одно техническое замечание относительно vs. Предположим, у вас есть следующие зависимости:

      dependencies {
  api "com.example:foo:1.0"
  implementation "com.example:bar:1.0"
}

Если вы установите сгенерированный файл jar в локальном репозитории Maven (с помощью maven-publish плагин) вы увидите, что сгенерированный pom.xml файл будет выглядеть так:

          <dependency>
      <groupId>com.example</groupId>
      <artifactId>foo</artifactId>
      <version>1.0</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>com.example</groupId>
      <artifactId>bar</artifactId>
      <version>1.0</version>
      <scope>runtime</scope>
    </dependency>

Примечание: api был преобразован в compile масштабы и implementation - к runtime сфера.

Это позволяет потребителям этой библиотеки избежать зависимостей времени выполнения в пути к классам компиляции.

Из документации gradle:

Давайте посмотрим на очень простой скрипт сборки для проекта на основе JVM.

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.+'
}

реализация

Зависимости, необходимые для компиляции производственного источника проекта, которые не являются частью API, предоставляемого проектом. Например, в проекте используется Hibernate для реализации внутреннего уровня сохраняемости.

api

Зависимости, необходимые для компиляции производственного источника проекта, которые являются частью API, предоставляемого проектом. Например, проект использует Guava и предоставляет открытые интерфейсы с классами Guava в их сигнатурах методов.

Ответы от MatPag и dev.bmax достаточно ясны, чтобы люди поняли разные способы использования между реализацией и API. Я просто хочу сделать дополнительное объяснение с другой стороны, надеюсь помочь людям, у которых есть тот же вопрос.

Для тестирования создал два проекта:

  • проект A как проект библиотеки Java с именем "frameworks-web-gradle-plugin" зависит от "org.springframework.boot:spring-boot-gradle-plugin:1.5.20.RELEASE"
  • проект B зависит от проекта A реализацией com.example.frameworks.gradle:frameworks-web-gradle-plugin:0.0.1-SNAPSHOT

Описанная выше иерархия зависимостей выглядит так:

[project-b] -> [project-a] -> [spring-boot-gradle-plugin]

Затем я протестировал следующие сценарии:

  1. Сделать проект А зависит от "org.springframework.boot: весна-загрузка Gradle-плагин: 1.5.20.RELEASE" от реализации.

    Пробег gradle dependencies в терминале в корневом каталоге poject B , со следующим снимком экрана вывода мы видим, что 'spring-boot-gradle-plugin' появляется в дереве зависимостей runtimeClasspath, но не в compileClasspath, я думаю, именно поэтому мы не можем использовать библиотеки, объявленной с использованием реализации, просто не будет через компиляцию.

  2. Сделать проект A зависит от 'org.springframework.boot:spring-boot-gradle-plugin:1.5.20.RELEASE' от api

    Пробег gradle dependenciesснова в терминале в корневом каталоге poject B. Теперь 'spring-boot-gradle-plugin' появляется как в дереве зависимостей compileClasspath, так и в дереве зависимостей runtimeClasspath.

Существенное отличие, которое я заметил, заключается в том, что зависимость в проекте производителя / библиотеки, объявленная способом реализации, не будет отображаться в compileClasspath потребительских проектов, поэтому мы не можем использовать соответствующую библиотеку в потребительских проектах.

Теперь в есть хорошее объяснениедокументации

Конфигурация api должна использоваться для объявления зависимостей, которые экспортируются библиотечным API, тогда как конфигурация реализации должна использоваться для объявления зависимостей, которые являются внутренними для компонента.

Другие вопросы по тегам