【macOS】Android Studio 埋め込み JDK の Home のパスを取得する

毎回どこなのかググるので。

まずは、mdfind で Android Studio のインストールされているパスを取得します。

👉 mdfind – macOSのCLIでもSpotlightを使ってファイルを高速全文検索する | DevelopersIO hatena-bookmark


❯ mdfind kMDItemCFBundleIdentifier="com.google.android.studio*"
/Users/mao/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/221.6008.13.2211.9477386/Android Studio.app
/Users/mao/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-1/223.7571.182.2231.9523943/Android Studio Preview.app

JetBrains Toolbox で Android Studio Preview版 も入れてるので複数見つかります。

👉 JetBrains Toolbox で Android Studio の Stable/Beta/Canary が同時に管理できる? hatena-bookmark

パス内の 221.6008.13.2211.9477386 のような文字列は、Android Studio のリリースバージョンです。

Android Studio Releases List

👉 Android Studio Releases List | IntelliJ Platform Plugin SDK hatena-bookmark

find | grep して JDK の Home を探します。


❯ find "/Users/mao/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/221.6008.13.2211.9477386/Android Studio.app" \
  | grep -E "/(jdk|jbr)/Contents/Home$"
/Users/mao/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/221.6008.13.2211.9477386/Android Studio.app/Contents/jbr/Contents/Home

Home のパスが見つかったらバージョンを確認してみます。


"/Users/mao/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/221.6008.13.2211.9477386/Android Studio.app/Contents/jbr/Contents/Home/bin/java" --version
openjdk 11.0.15 2022-04-19
OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)
OpenJDK 64-Bit Server VM (build 11.0.15+0-b2043.56-8887301, mixed mode)

というかんじをスクリプトにしておきます。



JDK の Home パスとバージョンが表示されます。


❯ find-androidstudio-embedded-jdk.sh
"/Users/mao/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/221.6008.13.2211.9477386/Android Studio.app/Contents/jbr/Contents/Home"
openjdk 11.0.15 2022-04-19
OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)
OpenJDK 64-Bit Server VM (build 11.0.15+0-b2043.56-8887301, mixed mode)

"/Users/mao/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-1/223.7571.182.2231.9523943/Android Studio Preview.app/Contents/jbr/Contents/Home"
openjdk 17.0.5 2022-10-18
OpenJDK Runtime Environment (build 17.0.5+0-17.0.5b653.25-9484017)
OpenJDK 64-Bit Server VM (build 17.0.5+0-17.0.5b653.25-9484017, mixed mode)

https://plugins.jetbrains.com/docs/intellij/android-studio-releases-list.html

mdfind って便利で高速です。

👉 Android Studio Electric Eel | 2022.1.1 の JDK11 設定 hatena-bookmark
👉 macOS (Intel) + Homebrew の JDK の現状を確認する hatena-bookmark


Kotlin 1.8 で JetpackCompose を使う

Kotlin を 1.7.21 から 1.8.0 に上げます。


[versions]

# kotlin = "1.7.21"
kotlin = "1.8.0"
compose-compiler = "1.4.0-alpha02"

build します。

はい、エラーでました。


e: This version (1.4.0-alpha01) of the Compose Compiler requires Kotlin version 1.7.21
but you appear to be using Kotlin version 1.7.21 which is not known to be compatible.
Please fix your configuration (or `suppressKotlinVersionCompatibilityCheck` but don't say I didn't warn you!).
https://developer.android.com/jetpack/androidx/releases/compose-kotlin#pre-release_kotlin_compatibility

表示されてるリンクに行きます。

はい、Kotlin 1.8 ありません。

👉 Compose to Kotlin Compatibility Map  |  Android Developers hatena-bookmark

さらに、そのページにあるリンク先へ。

ここにありますね。

👉 Compose Compiler Maven Index hatena-bookmark

さらに、このページにあるリンク先の記述を参考に変更します。


# libs.versions.toml

[versions]

# kotlin = "1.7.21"
# compose-compiler = "1.4.0-alpha02" # composeOptions ↔ kotlin 1.7.21

kotlin = "1.8.0"
compose-compiler = "1.4.0-dev-k1.8.0-33c0ad36f83"


// settings.gradle

dependencyResolutionManagement {
  repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
  repositories {
    google()
    mavenCentral()

    maven {
      url "https://androidx.dev/storage/compose-compiler/repository/"
    }


// build.gradle (:app)

composeOptions {
  kotlinCompilerExtensionVersion libs.versions.compose.compiler.get()
}

👉 jimgoog/ComposeAppUsingPrereleaseComposeCompiler: Demonstrates using Compose with pre-releases of KotlinCompiler and ComposeCompiler hatena-bookmark


 

■ まとめ

Kotlin バージョンと Compose Compiler のバージョンは密接に関係しています。

ちなみに、Compose UI 側のバージョンは以前のままの alpha03 (現最新) で、まあまあ良さげです。


[versions]

kotlin = "1.8.0"
compose-compiler = "1.4.0-dev-k1.8.0-33c0ad36f83"
compose-ui = "1.4.0-alpha03"


[libraries]

compose-ui = { module = "androidx.compose.ui:ui", version.ref = "compose-ui" }
compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "compose-ui" }
compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "compose-ui" }
compose-ui-test-manifest = { module = "androidx.compose.ui:ui-test-manifest", version.ref = "compose-ui" }
compose-ui-test-junit4 = { module = "androidx.compose.ui:ui-test-junit4", version.ref = "compose-ui" }


dyn4j の実力を JetpackCompose wrapper Physics Layout で思い知る

やはり Java のライブラリ群を使えることは素晴らしいことです。

以下、サンプルコードを参考に Activity を書き換えます。


👉 KlassenKonstantin/ComposePhysicsLayout: A custom Compose layout backed by a physics engine hatena-bookmark





class MainActivity : ComponentActivity() {

  @SuppressLint("SourceLockedOrientationActivity")
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    WindowCompat.setDecorFitsSystemWindows(window, false)
    requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
    setContent {
      PhysicsLayoutTheme {
        Surface(
          modifier = Modifier.fillMaxSize(),
          color = MaterialTheme.colorScheme.background
        ) {

          val simulation = rememberSimulation()
          val balls = remember { mutableStateListOf<BallMeta>() }

          GravitySensor {
            simulation.setGravity(it.copy(x = -it.x).times(3f))
          }

          LaunchedEffect(Unit) {
            var i = 0
            val count = colors.count()
            while (true) {
              balls.add(BallMeta(color = colors[i % count]))
              delay(100)
              i++
            }
          }

          LaunchedEffect(Unit) {
            delay(5000)
            while (true) {
              balls.removeFirst()
              delay(100)
            }
          }

          Box {
            PhysicsLayout(
              modifier = Modifier.systemBarsPadding(),
              simulation = simulation
            ) {

              Block(   0, -200)
              Block(-125, -100)
              Block( 125, -100)
              Block(   0,    0)
              Block(-100,  100)
              Block( 100,  100)
              Block(   0,  200)

              balls.forEach { meta ->
                Ball(0, -350, meta = meta)
              }

            }
          }

        }
      }
    }
  }
}

@Composable
fun PhysicsLayoutScope.Block(x: Int, y: Int) {
  val offset = offsetDp(x, y)
  Card(
    modifier = Modifier
      .body(
        isStatic = true,
        initialTranslation =  offset
      )
  ) {
    Spacer(
      modifier = Modifier
        .size(62.dp)
        .background(color = Color.Gray)
    )
  }
}

@Composable
fun PhysicsLayoutScope.Ball(x: Int, y: Int, meta: BallMeta) {

  val initialOffset = offsetDp(x, y)

  Card(
    modifier = Modifier.body(
      id = meta.id,
      shape = RoundedCornerShape(meta.corner),
      initialTranslation = Offset(initialOffset.x, initialOffset.y),
      initialImpulse = Offset((Random.nextFloat() - 0.5f) * 2, (Random.nextFloat()) * 2),
    ),
    shape = RoundedCornerShape(meta.corner),
    colors = CardDefaults.cardColors(containerColor = meta.color)
  ) {
    Icon(
      modifier = Modifier
        .size(32.dp)
        .padding(4.dp),
      imageVector = Icons.Rounded.Rocket,
      contentDescription = null,
      tint = Color.White
    )
  }
}

@Composable
fun offsetDp(x: Int, y: Int) = with(LocalDensity.current) { Offset(x.dp.toPx(), y.dp.toPx()) }


@Immutable
data class BallMeta(
  val id: String = System.currentTimeMillis().toString(),
  val color: Color,
  val corner: Int = listOf(0, 50).shuffled()[0]
)

private val colors = listOf(
  Color(0xFFEF5350), Color(0xFFEC407A), Color(0xFFAB47BC), Color(0xFF7E57C2),
  Color(0xFF29B6FC), Color(0xFF26C6DA), Color(0xFF26A69A), Color(0xFF66BB6A),
  Color(0xFF9CCC65), Color(0xFFD4E157), Color(0xFFFFEE58), Color(0xFFFFCA28),
  Color(0xFFFFA726), Color(0xFFFF7043), Color(0xFF8D6E63), Color(0xFFBDBDBD),
  Color(0xFF78909C)
)

強力です。

👉 dyn4j hatena-bookmark
👉 【Jetpack Compose】dp / px / sp の相互変換 hatena-bookmark




Android Studio Dolphin おすすめの Gradle Plugin と Gradle のバージョン

アプリ開発環境の設定がはややこしいですね。

今現在 (2022-12-01) 時点でのバージョンで順番に整えていきましょう。

 

■ Android Studio

安定版最新は 「Android Studio Dolphin | 2021.3.1」 です。

👉 Android Studio Dolphin | 2021.3.1  |  Android デベロッパー  |  Android Developers hatena-bookmark

使ってるバージョンが分からない場合は、Android Studio を開いた状態でメニューから以下から。


[Android Studio]

  ↓

[About Android Studio]

About Android Studio

 

■ Android Gradle Plugin

Android Gradle Plugin のバージョンは、使用する Android Studio のバージョンに依存しています。

Android Gradle plugin and Android Studio compatibility

👉 Android Gradle plugin and Android Studio compatibility - Android Gradle plugin release notes  |  Android Developers hatena-bookmark

Android Studio 「Android Studio Dolphin | 2021.3.1」 に対応している Android Gradle Plugin のバージョンは 「3.2-7.3」 です。

Google Mavens Repository で見てみます。

Google Mavens Repository

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

現在、「7.3.1」 が安定版最新です。

以下の話が必須になります。

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

 

■ Gradle

Gradle のバージョンは、使用する Android Gradle Plugin のバージョンに依存しています。

When you update Android Studio, you may receive a prompt to also update Gradle to the latest available version. You can choose to accept the update or manually specify a version based on your project's build requirements.

👉 Update Gradle - Android Gradle plugin release notes  |  Android Developers hatena-bookmark

Android Gradle Plugin 「7.3.1」 に対応している Gradle のバージョンは 「7.4 以上」 です。

Gradle Distributions で一覧を見ます。

https://services.gradle.org/distributions

👉 Gradle Distributions hatena-bookmark

Gradle Version Information でも Current Release を見ます。

Gradle Version Information


{
  "version" : "7.6",
  "buildTime" : "20221125133510+0000",
  "current" : true,
  "snapshot" : false,
  "nightly" : false,
  "releaseNightly" : false,
  "activeRc" : false,
  "rcFor" : "",
  "milestoneFor" : "",
  "broken" : false,
  "downloadUrl" : "https://services.gradle.org/distributions/gradle-7.6-bin.zip",
  "checksumUrl" : "https://services.gradle.org/distributions/gradle-7.6-bin.zip.sha256",
  "wrapperChecksumUrl" : "https://services.gradle.org/distributions/gradle-7.6-wrapper.jar.sha256"
}

👉 Gradle Version Information hatena-bookmark

現在、「7.6」 が安定版最新です。

👉 Gradle 7.6 Release Notes hatena-bookmark

 

■ まとめ

今現在、Android アプリ開発環境のおすすめバージョンズは、


Android Studio : Dolphin | 2021.3.1 Patch 1
Android Gradle Plugin : 7.3.1
Gradle : 7.6

となります。

Android Studio 上で簡単に確認することもできますが、


[File]

  ↓

[Project Structure]

  ↓

[Project]

「⚠ This project uses Gradle Version Catalogs: this tool may not behave as expected.」 と表示されたりする Gradle Version Catalog まわりで dependencies の確認や更新作業があやしくなっています。

Terminal から確認してみますか。


❯ ./gradlew -v

------------------------------------------------------------
Gradle 7.6
------------------------------------------------------------

Build time:   2022-11-25 13:35:10 UTC
Revision:     daece9dbc5b79370cc8e4fd6fe4b2cd400e150a8

Kotlin:       1.7.10
Groovy:       3.0.13
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 13.0.1 x86_64

ややこしいですね、バージョンたち。

複数の確認方法があったほうがいいように思います。

👉 Android Studio Electric Eel おすすめの Gradle Plugin と Gradle のバージョン hatena-bookmark
👉 Android 開発環境のいろいろな「バージョン」の 確認方法 と 関係 2022年11月 hatena-bookmark


Gradle Version Catalog 見づらい TOML インラインテーブル を別フォーマットで表示してみる

すべてインラインテーブルで記述したもののなんか見づらい。

なんかいい方法はないかな、と模索。

Python 3.11 で同梱された tomllib を使って別フォーマットで整形して表示してみます。

👉 How to Use Python 3.11's New TOML Parser, tomllib - The Invent with Python Blog hatena-bookmark

記事にするには大きすぎるので [plugins] だけで。


import tomllib
import pprint
import json
import yaml
import pandas
import tabulate

file = "/path/to/libs.versions.toml"

with open(file, "rb") as fp:
  data = tomllib.load(fp)["plugins"] # only plugins

# raw (dic)
print(data)

# pretty print
pprint.pprint(data)

# json
print(json.dumps(data, indent=2))

# yaml
print(yaml.dump(data))

# pandas + tabulate
df = pandas.DataFrame.from_dict(data, orient='index')
print(tabulate.tabulate(df, headers='keys'))

以下、出力結果。

 

■ raw (dic)


{'android-application': {'id': 'com.android.application', 'version': {'ref': 'agp'}}, 'kotlin-android': {'id': 'org.jetbrains.kotlin.android', 'version': {'ref': 'kotlin'}}, 'kotlin-kapt': {'id': 'org.jetbrains.kotlin.kapt', 'version': {'ref': 'kotlin'}}, 'kotlin-plugin-serialization': {'id': 'org.jetbrains.kotlin.plugin.serialization', 'version': {'ref': 'kotlin'}}, 'hilt': {'id': 'com.google.dagger.hilt.android', 'version': {'ref': 'hilt'}}, 'sqldelight': {'id': 'app.cash.sqldelight', 'version': {'ref': 'sqldelight'}}, 'google-services': {'id': 'com.google.gms.google-services', 'version': {'ref': 'google-services'}}, 'firebase-crashlytics': {'id': 'com.google.firebase.crashlytics', 'version': {'ref': 'firebase-crashlytics'}}, 'ben-manes-versions': {'id': 'com.github.ben-manes.versions', 'version': '0.44.0'}}

 

■ pretty print


{'android-application': {'id': 'com.android.application',
                         'version': {'ref': 'agp'}},
 'ben-manes-versions': {'id': 'com.github.ben-manes.versions',
                        'version': '0.44.0'},
 'firebase-crashlytics': {'id': 'com.google.firebase.crashlytics',
                          'version': {'ref': 'firebase-crashlytics'}},
 'google-services': {'id': 'com.google.gms.google-services',
                     'version': {'ref': 'google-services'}},
 'hilt': {'id': 'com.google.dagger.hilt.android', 'version': {'ref': 'hilt'}},
 'kotlin-android': {'id': 'org.jetbrains.kotlin.android',
                    'version': {'ref': 'kotlin'}},
 'kotlin-kapt': {'id': 'org.jetbrains.kotlin.kapt',
                 'version': {'ref': 'kotlin'}},
 'kotlin-plugin-serialization': {'id': 'org.jetbrains.kotlin.plugin.serialization',
                                 'version': {'ref': 'kotlin'}},
 'sqldelight': {'id': 'app.cash.sqldelight', 'version': {'ref': 'sqldelight'}}}

 

■ json


{
  "android-application": {
    "id": "com.android.application",
    "version": {
      "ref": "agp"
    }
  },
  "kotlin-android": {
    "id": "org.jetbrains.kotlin.android",
    "version": {
      "ref": "kotlin"
    }
  },
  "kotlin-kapt": {
    "id": "org.jetbrains.kotlin.kapt",
    "version": {
      "ref": "kotlin"
    }
  },
  "kotlin-plugin-serialization": {
    "id": "org.jetbrains.kotlin.plugin.serialization",
    "version": {
      "ref": "kotlin"
    }
  },
  "hilt": {
    "id": "com.google.dagger.hilt.android",
    "version": {
      "ref": "hilt"
    }
  },
  "sqldelight": {
    "id": "app.cash.sqldelight",
    "version": {
      "ref": "sqldelight"
    }
  },
  "google-services": {
    "id": "com.google.gms.google-services",
    "version": {
      "ref": "google-services"
    }
  },
  "firebase-crashlytics": {
    "id": "com.google.firebase.crashlytics",
    "version": {
      "ref": "firebase-crashlytics"
    }
  },
  "ben-manes-versions": {
    "id": "com.github.ben-manes.versions",
    "version": "0.44.0"
  }
}

 

■ yaml


android-application:
  id: com.android.application
  version:
    ref: agp
ben-manes-versions:
  id: com.github.ben-manes.versions
  version: 0.44.0
firebase-crashlytics:
  id: com.google.firebase.crashlytics
  version:
    ref: firebase-crashlytics
google-services:
  id: com.google.gms.google-services
  version:
    ref: google-services
hilt:
  id: com.google.dagger.hilt.android
  version:
    ref: hilt
kotlin-android:
  id: org.jetbrains.kotlin.android
  version:
    ref: kotlin
kotlin-kapt:
  id: org.jetbrains.kotlin.kapt
  version:
    ref: kotlin
kotlin-plugin-serialization:
  id: org.jetbrains.kotlin.plugin.serialization
  version:
    ref: kotlin
sqldelight:
  id: app.cash.sqldelight
  version:
    ref: sqldelight

 

■ pandas + tabulate


                             id                                         version
---------------------------  -----------------------------------------  -------------------------------
android-application          com.android.application                    {'ref': 'agp'}
kotlin-android               org.jetbrains.kotlin.android               {'ref': 'kotlin'}
kotlin-kapt                  org.jetbrains.kotlin.kapt                  {'ref': 'kotlin'}
kotlin-plugin-serialization  org.jetbrains.kotlin.plugin.serialization  {'ref': 'kotlin'}
hilt                         com.google.dagger.hilt.android             {'ref': 'hilt'}
sqldelight                   app.cash.sqldelight                        {'ref': 'sqldelight'}
google-services              com.google.gms.google-services             {'ref': 'google-services'}
firebase-crashlytics         com.google.firebase.crashlytics            {'ref': 'firebase-crashlytics'}
ben-manes-versions           com.github.ben-manes.versions              0.44.0

 

■ まとめ

Python って、簡単にいろんなことできるんですね!