【Plugin DSL】「com.android.tools.build:gradle」の記述は不要?

Plugin DSL に移行ながらの気持ちが悪いのは以下の変化。


// 2020-10-13
// build.gradle ( root | Project )
classpath "com.android.tools.build:gradle:4.0.2"

// build.gradle ( module | Module )
apply plugin: 'com.android.application'


// 2022-10-25
// build.gradle ( root | Project )
plugins {
  id 'com.android.application' version '7.3.1' apply false
  id 'com.android.library' version '7.3.1' apply false
}

// build.gradle ( module | Module )
plugins {
  id 'com.android.application'
}

👉 今現在 AndroidStudio が推してくる Gradle の設定記述と構成を2年前と比較 - libs.versions.toml, settings.gradle, build.gradle hatena-bookmark

ここに登場する3つの文字列。


com.android.tools.build:gradle
com.android.application
com.android.library

ここらがなんとなくあやふやに使っていたのでよく調べてみます。

 

■ アプリケーションかライブラリか

root の build.gradle でプラグインのバージョンを指定しておいて、


// 2022-10-25
// build.gradle ( root | Project )
plugins {
  id 'com.android.application' version '7.3.1' apply false
  id 'com.android.library' version '7.3.1' apply false
}

その子のモジュールの build.gradle で適用する、


// 2022-10-25
// build.gradle ( module | Module )
plugins {
  id 'com.android.application'
}

ということです。

👉 Applying external plugins with same version to subprojects - Using Gradle Plugins hatena-bookmark

そのときに、そのモジュールがアプリケーションかライブラリかで適用するGradleプラグインのIDが変わります。


plugins {
  id 'com.android.application'
}


plugins {
  id 'com.android.library'
}

👉 Android ライブラリの作成  |  Android デベロッパー  |  Android Developers hatena-bookmark

 

■ 'com.android.tools.build:gradle' の記述

Plugin DSL が登場する前は以下のような記述でしたが、


// 2020-10-13
// build.gradle ( root | Project )
classpath "com.android.tools.build:gradle:4.0.2"

// build.gradle ( module | Module )
apply plugin: 'com.android.application'

Plugin DSL では消えてます、"com.android.tools.build:gradle"

👉 【Plugin DSL】Android Gradle Plugin のバージョンがわからない hatena-bookmark

ここで、Plugin ID から参照されるリポジトリの内容を見てみます。

Google Maven Repository では、

Plugin Marker Artifacts
Since the plugins {} DSL block only allows for declaring plugins by their globally unique plugin id and version properties, Gradle needs a way to look up the coordinates of the plugin implementation artifact. To do so, Gradle will look for a Plugin Marker Artifact with the coordinates plugin.id:plugin.id.gradle.plugin:plugin.version. This marker needs to have a dependency on the actual plugin implementation. Publishing these markers is automated by the java-gradle-plugin.

プラグインマーカーアーティファクト
plugins {} DSLブロックでは、グローバルにユニークなプラグインIDとバージョンプロパティによってのみプラグインを宣言できるので、Gradleはプラグイン実装アーティファクトの座標を検索する方法が必要です。そのために、Gradleは plugin.id:plugin.id.gradle.plugin:plugin.version という座標を持つプラグインマーカーアーティファクトを探します。このマーカーは、実際のプラグイン実装への依存関係を持つ必要があります。これらのマーカーの発行は、java-gradle-pluginによって自動化されます。

👉 Plugin Marker Artifacts - Using Gradle Plugins hatena-bookmark


plugin.id:plugin.id.gradle.plugin:plugin.version
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

ということなので、

Plugin ID : com.android.application は、


Group Id    : com.android.application
Artifact ID : com.android.application.gradle.plugin

で、

Plugin ID : com.android.library は、


Group Id    : com.android.library
Artifact ID : com.android.library.gradle.plugin

で、検索します。


Group ID	com.android.application
Artifact ID	com.android.application.gradle.plugin
Version	8.0.0-alpha06
Gradle Groovy DSL	
implementation 'com.android.application:com.android.application.gradle.plugin:8.0.0-alpha06'
Gradle Kotlin DSL	
implementation("com.android.application:com.android.application.gradle.plugin:8.0.0-alpha06") 
Last Updated Date	10/24/2022


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.android.application</groupId>
  <artifactId>com.android.application.gradle.plugin</artifactId>
  <version>8.0.0-alpha06</version>
  <packaging>pom</packaging>
  <description>Gradle plug-in to build Android applications.</description>
  <url>https://developer.android.com/studio/build</url>
  <name>com.android.tools.build.gradle</name>
  <licenses>
    <license>
      <name>The Apache Software License, Version 2.0</name>
      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
      <distribution>repo</distribution>
    </license>
  </licenses>
  <developers>
    <developer>
      <name>The Android Open Source Project</name>
    </developer>
  </developers>
  <scm>
    <connection>git://android.googlesource.com/platform/tools/base.git</connection>
    <url>https://android.googlesource.com/platform/tools/base</url>
  </scm>
  <dependencies>
    <dependency>
      <groupId>com.android.tools.build</groupId>
      <artifactId>gradle</artifactId>
      <version>8.0.0-alpha06</version>
    </dependency>
  </dependencies>
</project>

👉 com.android.application.com.android.application.gradle.plugin-8.0.0-alpha06 - Google's Maven Repository hatena-bookmark


Group ID	com.android.library
Artifact ID	com.android.library.gradle.plugin
Version	8.0.0-alpha06
Gradle Groovy DSL	
implementation 'com.android.library:com.android.library.gradle.plugin:8.0.0-alpha06' 
Gradle Kotlin DSL	
implementation("com.android.library:com.android.library.gradle.plugin:8.0.0-alpha06")
Last Updated Date	10/24/2022


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.android.library</groupId>
  <artifactId>com.android.library.gradle.plugin</artifactId>
  <version>8.0.0-alpha06</version>
  <packaging>pom</packaging>
  <description>Gradle plug-in to build Android applications.</description>
  <url>https://developer.android.com/studio/build</url>
  <name>com.android.tools.build.gradle</name>
  <licenses>
    <license>
      <name>The Apache Software License, Version 2.0</name>
      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
      <distribution>repo</distribution>
    </license>
  </licenses>
  <developers>
    <developer>
      <name>The Android Open Source Project</name>
    </developer>
  </developers>
  <scm>
    <connection>git://android.googlesource.com/platform/tools/base.git</connection>
    <url>https://android.googlesource.com/platform/tools/base</url>
  </scm>
  <dependencies>
    <dependency>
      <groupId>com.android.tools.build</groupId>
      <artifactId>gradle</artifactId>
      <version>8.0.0-alpha06</version>
    </dependency>
  </dependencies>
</project>

👉 com.android.library.com.android.library.gradle.plugin-8.0.0-alpha06 - Google's Maven Repository hatena-bookmark

それぞれ、同じ


<dependency>
  <groupId>com.android.tools.build</groupId>
  <artifactId>gradle</artifactId>
  <version>8.0.0-alpha06</version>
</dependency>

となってますので、以下の実装アーティファクトを解決できてるのでしょう。


Group ID	com.android.tools.build
Artifact ID	gradle
Version	8.0.0-alpha06
Gradle Groovy DSL	
implementation 'com.android.tools.build:gradle:8.0.0-alpha06'
Gradle Kotlin DSL	
implementation("com.android.tools.build:gradle:8.0.0-alpha06") 
Last Updated Date	10/24/2022

👉 com.android.tools.build.gradle-8.0.0-alpha06 - Google's Maven Repository hatena-bookmark

よって、'com.android.tools.build:gradle' の記述は、plugin DSL では記述の必要はないのでしょう。

少し古いコードに以下のような記述が見られるのは、プラグインマーカーアーティファクトが公開される前のものだったということで納得できます。


pluginManagement {
  // ...
  resolutionStrategy {
    eachPlugin {
      if(requested.id.namespace == "com.android") {
        useModule("com.android.tools.build:gradle:${requested.version}")
      }
    }
  }

 

■ まとめ

最後に、AndroidStudio のプロジェクトテンプレートを利用して確認します。

例にならって、 New Project から Empty Activity を選択後、 New Module から Android Library を作成します。

【Plugin DSL】'com.android.tools.build:gradle'

以下、Gradle まわりの設定ファイル該当部分です。


// settings.gradle
pluginManagement {
  repositories {
    gradlePluginPortal()
    google()
    mavenCentral()
  }
  repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
  repositories {
    google()
    mavenCentral()
  }

include ':app'
include ':el'


// build.gradle
plugins {
  id 'com.android.application' version '7.3.1' apply false
  id 'com.android.library' version '7.3.1' apply false
  id 'org.jetbrains.kotlin.android' version '1.7.20' apply false


// app/build.gradle
plugins {
  id 'com.android.application'
  id 'org.jetbrains.kotlin.android'
  implementation project(path: ':el')


// el/build.gradle
plugins {
  id 'com.android.library'
  id 'org.jetbrains.kotlin.android'

'com.android.tools.build:gradle' は見当たりませんね!

素晴らしいです、Plugin DSL !!

👉 Jetpack Compose Samples でも使われている「Version catalog update plugin」で libs.versions.toml を書き出してみる hatena-bookmark
👉 今現在 AndroidStudio が推してくる Gradle の設定記述と構成を2年前と比較 - libs.versions.toml, settings.gradle, build.gradle hatena-bookmark


【Gradle Version Catalog】libs.versions.toml キー名の形式 camelCase vs kebab-case

一流のプログラマーのコードには、それぞれのこだわりや哲学があります。

Gradle Version Catalog で利用される設定ファイルの libs.versions.toml を眺めながら、気になったことがありました。

キー名の形式です。

Gradle Version Catalog

 

■ いろんな形式がある

Naming convention (programming)
👉 Naming convention (programming) - Wikipedia hatena-bookmark

 

■ TOML 的には

Case についてははっきりとしたきまりはないようです。

キーはベア・キー、クォート付きキー、ドット付きキーのいずれかです。
ベア・キーはASCII英数字とアンダースコア、ダッシュのみで構成されます(A-Za-z0-9_-)。 ASCII数字のみでも構いませんが、文字列として解釈されることに注意してください(例: 1234)。

👉キー TOML: 日本語 v1.0.0-rc.2 hatena-bookmark

こんなきまりもあります。

インライン・テーブルは一行で表現されるべきです。インライン・テーブルでは、配列と違って、最後の要素のあとにコンマを足すことはできません。波括弧の内側では改行は認められません。ただし、それぞれの値の中で改行することは、それぞれの値型で認められている範囲でできます。ですが、できるとしてもインライン・テーブルを複数行に分割することはなるべく避けるべきです。もしあなたがその必要があるように感じたのならば、普通のテーブルを用いるべきです。


name = { first = "Tom", last = "Preston-Werner" }
point = { x = 1, y = 2 }
animal = { type.name = "pug" }

👉 インライン・テーブル TOML: 日本語 v1.0.0-rc.2 hatena-bookmark

 

■ GitHub で見てみる

camelCase


[libraries]
androidPlugin = { module = "com.android.tools.build:gradle", version = "4.2.2" }
robovmPlugin = { module = "com.mobidevelop.robovm:robovm-gradle-plugin", version.ref = "robovm" }
kotlinStdLib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
kotlinCoroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version = "1.5.1" }
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }

👉 retrofit/libs.versions.toml at 5180f481c58b0be80ad81a0c1ec540fe7e91ee81 · square/retrofit hatena-bookmark

kebab-case


[libraries]
plugin-android = { module = "com.android.tools.build:gradle", version.ref = "plugin-android" }
plugin-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "plugin-kotlin" }
plugin-kotlin-serialization = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "plugin-kotlin" }
plugin-gver = { module = "com.github.ben-manes:gradle-versions-plugin", version.ref = "plugin-gver" }

👉 kmm-production-sample/libs.versions.toml at aed57893bab7e88a0df50285196e942be6934bf8 · Kotlin/kmm-production-sample hatena-bookmark
👉 PosterBox/libs.versions.toml at 9e988e7fb62620a6913493aeecc51cb71aba3595 · JakeWharton/PosterBox hatena-bookmark
👉 awesome-kotlin/libs.versions.toml at ae83263c467da6f81bb1abc7536ab6af7bc5b4d0 · KotlinBy/awesome-kotlin hatena-bookmark

camelCase - kebab-case


[libraries]
gradlePlugin-android = { module = "com.android.tools.build:gradle", version = "4.2.2" }
gradlePlugin-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlinCompiler" }
gradlePlugin-dokka = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version = "1.6.20" }

👉 leakcanary/libs.versions.toml at f9462209ab553c76ad77673f7bebbd155fa76fa9 · square/leakcanary hatena-bookmark

その他


jsoup = { module = "org.jsoup:jsoup", version.ref = "1.15.3" }

でなく


jsoup = "org.jsoup:jsoup:1.15.3"

とも書ける。

👉 okhttp/libs.versions.toml at a94769c31ff18c5c768f790a92eab1de9b27fd83 · square/okhttp hatena-bookmark

あと、どこを選択するか、という問題もある。


com.google.firebase:firebase-bom
                    ^^^^^^^^^^^^

com.google.firebase:firebase-*
                    ^^^^^^^^^^

com.google.accompanist:accompanist-*
    ^^^^^^.^^^^^^^^^^^

com.google.accompanist:accompanist-imageloading-core
    ^^^^^^.^^^^^^^^^^^.            ^^^^^^^^^^^^^^^^^

com.google.accompanist:accompanist-glide
    ^^^^^^.^^^^^^^^^^^.            ^^^^^

com.google.android.libraries.places:places
    ^^^^^^.^^^^^^^.          ^^^^^^

com.google.maps.android:*
    ^^^^^^.     ^^^^^^^.^

com.google.maps.android:android-maps-utils
    ^^^^^^.     ^^^^^^^.        ^^^^^^^^^^

com.google.maps.android:maps-ktx
    ^^^^^^.     ^^^^^^^.^^^^^^^^

👉 refreshVersions/google-version-alias-rules.txt at main · jmfayard/refreshVersions hatena-bookmark

 

■ まとめ

「.(ドット)」に置き換えられて読み込まれる build,gradle 側の考慮も必要になります。

「重複しない直感的に分かりやすい名前」「kebab-case」にするのがスッキリしていいように思うけどみんなはどうしてますか?

👉 Jetpack Compose Samples でも使われている「Version catalog update plugin」で libs.versions.toml を書き出してみる hatena-bookmark
👉 Gradle Version Catalog への書き換えツールを作る【python】 hatena-bookmark
👉 「⚠ This project uses Gradle Version Catalogs: this tool may not behave as expected.」→ 今現在、Gradle Version Catalog には gradle-versions-plugin が必須では? hatena-bookmark


【KMM】KDoctor って生きてるの?

公式にこんなの書いてるけど。

kdoctor

👉 Set up an environment | Kotlin hatena-bookmark


❯ kdoctor                       
[v] System                                           
    OS: macOS (12.6)
    CPU: Intel(R) Core(TM) i9-9900K CPU @ 3.60GHz
[v] Java
    Java (openjdk version "11.0.13" 2021-10-19)
    Location: /Users/maochanz/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/213.7172.25.2113.9014738/Android Studio.app/Contents/jre/Contents/Home/bin/java
    
    JAVA_HOME=/Users/maochanz/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/213.7172.25.2113.9014738/Android Studio.app/Contents/jre/Contents/Home
    
    * Note that, by default, Xcode uses Java environment returned by /usr/libexec/java_home:
      /usr/local/Cellar/openjdk@11/11.0.16.1_1/libexec/openjdk.jdk/Contents/Home
      It does not match current JAVA_HOME environment variable:
      /Users/maochanz/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/213.7172.25.2113.9014738/Android Studio.app/Contents/jre/Contents/Home
          Set JAVA_HOME in XCode -> Preferences -> Locations -> Custom Paths to
          /Users/maochanz/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/213.7172.25.2113.9014738/Android Studio.app/Contents/jre/Contents/Home
    
    * Note that, by default, Android Studio uses bundled JDK for Gradle tasks execution.
          Gradle JDK can be configured in Android Studio Preferences under Build, Execution, Deployment -> Build Tools -> Gradle section
    
[x] Android Studio
    * Android Studio (2021.3)
      Location: /Users/maochanz/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/213.7172.25.2113.9014738/Android Studio.app
      Bundled Java: openjdk 11.0.13 2021-10-19
      Kotlin Plugin: 213-1.7.10-release-for-android-studio-AS6777.52
      Kotlin Multiplatform Mobile Plugin: not installed
          Install Kotlin Multiplatform Mobile plugin - https://plugins.jetbrains.com/plugin/14936-kotlin-multiplatform-mobile
    
[v] Xcode
    Xcode (14.0.1)
    Location: /Applications/Xcode.app
    
[x] Cocoapods
    ruby (ruby 2.7.6p219 (2022-04-12 revision c9c2245c0a) [x86_64-darwin21])
    
    ruby gems (3.3.11)
    
    cocoapods (1.11.3)
    
    * cocoapods-generate plugin not found
          Get cocoapods-generate from https://github.com/square/cocoapods-generate#installation
    
Failures: 2
KDoctor has diagnosed one or more problems while checking your environment.
Please check the output for problem description and possible solutions.

Failures: 2 ですけど!!

👉 Kotlin/kdoctor: Environment analysis tool hatena-bookmark

 

■ JAVA_HOME

Homebrew で OpenJDK11 最新を入れておく。

👉 Mac に Homebrew で OpenJDK11 を インストール する hatena-bookmark


export JAVA_HOME=$(/usr/libexec/java_home -v11)
export PATH="$JAVA_HOME/bin:$PATH"


❯ java -version
openjdk version "11.0.16.1" 2022-08-12
OpenJDK Runtime Environment Homebrew (build 11.0.16.1+0)
OpenJDK 64-Bit Server VM Homebrew (build 11.0.16.1+0, mixed mode)

❯ javac -version
javac 11.0.16.1

❯ which java
/usr/local/Cellar/openjdk@11/11.0.16.1_1/libexec/openjdk.jdk/Contents/Home/bin/java

❯ which javac
/usr/local/Cellar/openjdk@11/11.0.16.1_1/libexec/openjdk.jdk/Contents/Home/bin/javac

❯ ./gradlew --version

------------------------------------------------------------
Gradle 7.5.1
------------------------------------------------------------

Build time:   2022-08-05 21:17:56 UTC
Revision:     d1daa0cbf1a0103000b71484e1dbfe096e095918

Kotlin:       1.6.21
Groovy:       3.0.10
Ant:          Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM:          11.0.16.1 (Homebrew 11.0.16.1+0)
OS:           Mac OS X 12.6 x86_64

AndroidStudio 内の設定で選択肢から指定するだけでいい。

JAVA_HOME

👉 AndroidStudio 利用する Java (JDK) の選択・設定の方法 hatena-bookmark

 

■ Kotlin Multiplatform Mobile Plugin

KMM プラグインをインストールしても、ずっと


Kotlin Multiplatform Mobile Plugin: not installed

のままです。

どうやら、JetBrains ToolBox で Android Studio を使ってる場合の現象のようです。

KDoctor が KMM プラグインを見つけられないようです。

Android Studio: Cannot detect installed Kotlin Multiplatform Mobile Plugin
👉 Android Studio: Cannot detect installed Kotlin Multiplatform Mobile Plugin · Issue #25 · Kotlin/kdoctor hatena-bookmark

 

■ cocoapods-generate


~/AndroidStudioProjects/KMM main
❯ gem 'cocoapods-generate'
ERROR:  While executing gem ... (Gem::UnknownCommandError)
    Unknown command cocoapods-generate

~/AndroidStudioProjects/KMM main
❯ gem install cocoapods-generate
ERROR:  While executing gem ... (Errno::EACCES)
    Permission denied @ dir_s_mkdir - /usr/local/lib/ruby/gems/2.7.0/gems/cocoapods-disable-podfile-validations-0.1.1

❯ pod env --verbose
  CDN: trunk Relative path: CocoaPods-version.yml exists! Returning local because checking is only performed in repo update

### Stack

```
   CocoaPods : 1.11.3
        Ruby : ruby 2.7.6p219 (2022-04-12 revision c9c2245c0a) [x86_64-darwin21]
    RubyGems : 3.3.11
        Host : macOS 12.6 (21G115)
       Xcode : 14.0.1 (14A400)
         Git : git version 2.33.0
Ruby lib dir : /usr/local/Cellar/ruby@2.7/2.7.6_1/lib
Repositories : trunk - CDN - https://cdn.cocoapods.org/
```

### Installation Source

```
Executable Path: /usr/local/bin/pod
```

### Plugins

```
cocoapods-deintegrate : 1.0.5
cocoapods-plugins     : 1.0.0
cocoapods-search      : 1.0.1
cocoapods-trunk       : 1.6.0
cocoapods-try         : 1.2.0

```

Kotlin 1.7.0 以降は、


sudo gem install cocoapods

だけでいいんじゃね?

Set up an environment to work with CocoaPods

👉 CocoaPods overview and setup | Kotlin hatena-bookmark

 

■ まとめ

GitHub リポジトリを見てる限り、

KDoctor is a command-line tool that helps to set up the environment for Kotlin Multiplatform Mobile app development.
最終更新日時、

古すぎん?

生きてないのかな、KDoctor。

 

■ バージョン 0.0.5 公開 : 2022-12-04 追記

0.0.5 が公開されています。

正常に診断できるようになってます!!

--verbose で実行すると状態の詳細が分かりやすいです。


❯ kdoctor -h       
Usage: kdoctor options_list
Options: 
    --version -> print KDoctor version 
    --verbose, -v -> print extended information 
    --debug -> debug mode 
    --help, -h -> Usage info


👉 Kotlin/kdoctor: Environment analysis tool hatena-bookmark
👉 CocoaPods/CocoaPods: The Cocoa Dependency Manager. hatena-bookmark
👉 square/cocoapods-generate: A CocoaPods plugin that allows you to easily generate a workspace from a podspec. hatena-bookmark

👉 テキストアニメーションで Progress Indicator hatena-bookmark