sdkpath.go 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. // Copyright 2022 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // Package sdkpath provides functions for locating the Android SDK.
  5. // These functions respect the ANDROID_HOME environment variable, and
  6. // otherwise use the default SDK location.
  7. package sdkpath
  8. import (
  9. "fmt"
  10. "os"
  11. "path/filepath"
  12. "runtime"
  13. "strconv"
  14. "strings"
  15. )
  16. // AndroidHome returns the absolute path of the selected Android SDK,
  17. // if one can be found.
  18. func AndroidHome() (string, error) {
  19. androidHome := os.Getenv("ANDROID_HOME")
  20. if androidHome == "" {
  21. home, err := os.UserHomeDir()
  22. if err != nil {
  23. return "", err
  24. }
  25. switch runtime.GOOS {
  26. case "windows":
  27. // See https://android.googlesource.com/platform/tools/adt/idea/+/85b4bfb7a10ad858a30ffa4003085b54f9424087/native/installer/win/setup_android_studio.nsi#100
  28. androidHome = filepath.Join(home, "AppData", "Local", "Android", "sdk")
  29. case "darwin":
  30. // See https://android.googlesource.com/platform/tools/asuite/+/67e0cd9604379e9663df57f16a318d76423c0aa8/aidegen/lib/ide_util.py#88
  31. androidHome = filepath.Join(home, "Library", "Android", "sdk")
  32. default: // Linux, BSDs, etc.
  33. // See LINUX_ANDROID_SDK_PATH in ide_util.py above.
  34. androidHome = filepath.Join(home, "Android", "Sdk")
  35. }
  36. }
  37. if info, err := os.Stat(androidHome); err != nil {
  38. return "", fmt.Errorf("%w; Android SDK was not found at %s", err, androidHome)
  39. } else if !info.IsDir() {
  40. return "", fmt.Errorf("%s is not a directory", androidHome)
  41. }
  42. return androidHome, nil
  43. }
  44. // AndroidAPIPath returns an android SDK platform directory within the configured SDK.
  45. // If there are multiple platforms that satisfy the minimum version requirement,
  46. // AndroidAPIPath returns the latest one among them.
  47. func AndroidAPIPath(api int) (string, error) {
  48. sdk, err := AndroidHome()
  49. if err != nil {
  50. return "", err
  51. }
  52. sdkDir, err := os.Open(filepath.Join(sdk, "platforms"))
  53. if err != nil {
  54. return "", fmt.Errorf("failed to find android SDK platform: %w", err)
  55. }
  56. defer sdkDir.Close()
  57. fis, err := sdkDir.Readdir(-1)
  58. if err != nil {
  59. return "", fmt.Errorf("failed to find android SDK platform (API level: %d): %w", api, err)
  60. }
  61. var apiPath string
  62. var apiVer int
  63. for _, fi := range fis {
  64. name := fi.Name()
  65. if !strings.HasPrefix(name, "android-") {
  66. continue
  67. }
  68. n, err := strconv.Atoi(name[len("android-"):])
  69. if err != nil || n < api {
  70. continue
  71. }
  72. p := filepath.Join(sdkDir.Name(), name)
  73. _, err = os.Stat(filepath.Join(p, "android.jar"))
  74. if err == nil && apiVer < n {
  75. apiPath = p
  76. apiVer = n
  77. }
  78. }
  79. if apiVer == 0 {
  80. return "", fmt.Errorf("failed to find android SDK platform (API level: %d) in %s",
  81. api, sdkDir.Name())
  82. }
  83. return apiPath, nil
  84. }