Skip to content

Commit

Permalink
all: modernize handling of Android SDK and NDK paths
Browse files Browse the repository at this point in the history
This change removes Gomobile's dependency on ANDROID_HOME and
ANDROID_NDK_HOME.  Setting ANDROID_HOME is generally optional,
and ANDROID_NDK_HOME is deprecated.

This change also increases the minimum API version to 16, as
all SDKs that supported API 15 are now deprecated.

Fixes golang/go#52470

Change-Id: I546365774a089e5d7ae1be0a538efd72741d92ac
Reviewed-on: https://go-review.googlesource.com/c/mobile/+/401574
TryBot-Result: Gopher Robot <[email protected]>
Reviewed-by: Daniel Skinner <[email protected]>
Reviewed-by: Suzy Mueller <[email protected]>
Reviewed-by: Hajime Hoshi <[email protected]>
Reviewed-by: Hyang-Ah Hana Kim <[email protected]>
Run-TryBot: Hyang-Ah Hana Kim <[email protected]>
  • Loading branch information
Ben Schwartz authored and hyangah committed May 18, 2022
1 parent eae5320 commit 8578da9
Show file tree
Hide file tree
Showing 22 changed files with 527 additions and 176 deletions.
9 changes: 5 additions & 4 deletions bind/java/seq_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"testing"

"golang.org/x/mobile/internal/importers/java"
"golang.org/x/mobile/internal/sdkpath"
)

var gomobileBin string
Expand Down Expand Up @@ -98,8 +99,8 @@ func TestJavaSeqBench(t *testing.T) {
// runTest runs the Android java test class specified with javaCls. If javaPkg is
// set, it is passed with the -javapkg flag to gomobile. The pkgNames lists the Go
// packages to bind for the test.
// This requires the gradle command in PATH and
// the Android SDK whose path is available through ANDROID_HOME environment variable.
// This requires the gradle command to be in PATH and the Android SDK to be
// installed.
func runTest(t *testing.T, pkgNames []string, javaPkg, javaCls string) {
if gomobileBin == "" {
t.Skipf("no gomobile on %s", runtime.GOOS)
Expand All @@ -108,8 +109,8 @@ func runTest(t *testing.T, pkgNames []string, javaPkg, javaCls string) {
if err != nil {
t.Skip("command gradle not found, skipping")
}
if sdk := os.Getenv("ANDROID_HOME"); sdk == "" {
t.Skip("ANDROID_HOME environment var not set, skipping")
if _, err := sdkpath.AndroidHome(); err != nil {
t.Skip("Android SDK not found, skipping")
}

cwd, err := os.Getwd()
Expand Down
12 changes: 7 additions & 5 deletions cmd/gomobile/bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"path/filepath"
"strings"

"golang.org/x/mobile/internal/sdkpath"
"golang.org/x/mod/modfile"
"golang.org/x/tools/go/packages"
)
Expand All @@ -42,9 +43,10 @@ example, in Android Studio (1.2+), an AAR file can be imported using
the module import wizard (File > New > New Module > Import .JAR or
.AAR package), and setting it as a new dependency
(File > Project Structure > Dependencies). This requires 'javac'
(version 1.7+) and Android SDK (API level 15 or newer) to build the
library for Android. The environment variable ANDROID_HOME must be set
to the path to Android SDK. Use the -javapkg flag to specify the Java
(version 1.7+) and Android SDK (API level 16 or newer) to build the
library for Android. The ANDROID_HOME and ANDROID_NDK_HOME environment
variables can be used to specify the Android SDK and NDK if they are
not in the default locations. Use the -javapkg flag to specify the Java
package prefix for the generated classes.
By default, -target=android builds shared libraries for all supported
Expand Down Expand Up @@ -85,7 +87,7 @@ func runBind(cmd *command) error {
if bindPrefix != "" {
return fmt.Errorf("-prefix is supported only for Apple targets")
}
if _, err := ndkRoot(); err != nil {
if _, err := ndkRoot(targets[0]); err != nil {
return err
}
} else {
Expand Down Expand Up @@ -156,7 +158,7 @@ func bootClasspath() (string, error) {
if bindBootClasspath != "" {
return bindBootClasspath, nil
}
apiPath, err := androidAPIPath()
apiPath, err := sdkpath.AndroidAPIPath(buildAndroidAPI)
if err != nil {
return "", err
}
Expand Down
51 changes: 4 additions & 47 deletions cmd/gomobile/bind_androidapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ import (
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"

"golang.org/x/mobile/internal/sdkpath"
"golang.org/x/tools/go/packages"
)

func goAndroidBind(gobind string, pkgs []*packages.Package, targets []targetInfo) error {
if sdkDir := os.Getenv("ANDROID_HOME"); sdkDir == "" {
return fmt.Errorf("this command requires ANDROID_HOME environment variable (path to the Android SDK)")
if _, err := sdkpath.AndroidHome(); err != nil {
return fmt.Errorf("this command requires the Android SDK to be installed: %w", err)
}

// Run gobind to generate the bindings
Expand Down Expand Up @@ -270,7 +270,7 @@ func buildAAR(srcDir, androidDir string, pkgs []*packages.Package, targets []tar

const (
javacTargetVer = "1.7"
minAndroidAPI = 15
minAndroidAPI = 16
)

func buildJar(w io.Writer, srcDir string) error {
Expand Down Expand Up @@ -370,46 +370,3 @@ func writeJar(w io.Writer, dir string) error {
}
return jarw.Close()
}

// androidAPIPath returns an android SDK platform directory under ANDROID_HOME.
// If there are multiple platforms that satisfy the minimum version requirement
// androidAPIPath returns the latest one among them.
func androidAPIPath() (string, error) {
sdk := os.Getenv("ANDROID_HOME")
if sdk == "" {
return "", fmt.Errorf("ANDROID_HOME environment var is not set")
}
sdkDir, err := os.Open(filepath.Join(sdk, "platforms"))
if err != nil {
return "", fmt.Errorf("failed to find android SDK platform: %v", err)
}
defer sdkDir.Close()
fis, err := sdkDir.Readdir(-1)
if err != nil {
return "", fmt.Errorf("failed to find android SDK platform (API level: %d): %v", buildAndroidAPI, err)
}

var apiPath string
var apiVer int
for _, fi := range fis {
name := fi.Name()
if !strings.HasPrefix(name, "android-") {
continue
}
n, err := strconv.Atoi(name[len("android-"):])
if err != nil || n < buildAndroidAPI {
continue
}
p := filepath.Join(sdkDir.Name(), name)
_, err = os.Stat(filepath.Join(p, "android.jar"))
if err == nil && apiVer < n {
apiPath = p
apiVer = n
}
}
if apiVer == 0 {
return "", fmt.Errorf("failed to find android SDK platform (API level: %d) in %s",
buildAndroidAPI, sdkDir.Name())
}
return apiPath, nil
}
28 changes: 14 additions & 14 deletions cmd/gomobile/bind_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,22 @@ import (
"strings"
"testing"
"text/template"

"golang.org/x/mobile/internal/sdkpath"
)

func TestBindAndroid(t *testing.T) {
androidHome := os.Getenv("ANDROID_HOME")
if androidHome == "" {
t.Skip("ANDROID_HOME not found, skipping bind")
}
platform, err := androidAPIPath()
platform, err := sdkpath.AndroidAPIPath(minAndroidAPI)
if err != nil {
t.Skip("No android API platform found in $ANDROID_HOME, skipping bind")
t.Skip("No compatible Android API platform found, skipping bind")
}
platform = strings.Replace(platform, androidHome, "$ANDROID_HOME", -1)
// platform is a path like "/path/to/Android/sdk/platforms/android-32"
components := strings.Split(platform, string(filepath.Separator))
if len(components) < 2 {
t.Fatalf("API path is too short: %s", platform)
}
components = components[len(components)-2:]
platformRel := filepath.Join("$ANDROID_HOME", components[0], components[1])

defer func() {
xout = os.Stderr
Expand Down Expand Up @@ -77,7 +81,7 @@ func TestBindAndroid(t *testing.T) {
JavaPkg string
}{
outputData: output,
AndroidPlatform: platform,
AndroidPlatform: platformRel,
JavaPkg: tc.javaPkg,
}

Expand Down Expand Up @@ -273,12 +277,8 @@ func TestBindWithGoModules(t *testing.T) {
t.Run(target, func(t *testing.T) {
switch target {
case "android":
androidHome := os.Getenv("ANDROID_HOME")
if androidHome == "" {
t.Skip("ANDROID_HOME not found, skipping bind")
}
if _, err := androidAPIPath(); err != nil {
t.Skip("No android API platform found in $ANDROID_HOME, skipping bind")
if _, err := sdkpath.AndroidAPIPath(minAndroidAPI); err != nil {
t.Skip("No compatible Android API platform found, skipping bind")
}
case "ios":
if !xcodeAvailable() {
Expand Down
5 changes: 3 additions & 2 deletions cmd/gomobile/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"strconv"
"strings"

"golang.org/x/mobile/internal/sdkpath"
"golang.org/x/tools/go/packages"
)

Expand Down Expand Up @@ -60,7 +61,7 @@ Flag -iosversion sets the minimal version of the iOS SDK to compile against.
The default version is 13.0.
Flag -androidapi sets the Android API version to compile against.
The default and minimum is 15.
The default and minimum is 16.
The -bundleid flag is required for -target ios and sets the bundle ID to use
with the app.
Expand Down Expand Up @@ -215,7 +216,7 @@ func printcmd(format string, args ...interface{}) {
if tmpdir != "" {
cmd = strings.Replace(cmd, tmpdir, "$WORK", -1)
}
if androidHome := os.Getenv("ANDROID_HOME"); androidHome != "" {
if androidHome, err := sdkpath.AndroidHome(); err == nil {
cmd = strings.Replace(cmd, androidHome, "$ANDROID_HOME", -1)
}
if gomobilepath != "" {
Expand Down
2 changes: 1 addition & 1 deletion cmd/gomobile/build_androidapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import (
)

func goAndroidBuild(pkg *packages.Package, targets []targetInfo) (map[string]bool, error) {
ndkRoot, err := ndkRoot()
ndkRoot, err := ndkRoot(targets...)
if err != nil {
return nil, err
}
Expand Down
10 changes: 4 additions & 6 deletions cmd/gomobile/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (
"strings"
"testing"
"text/template"

"golang.org/x/mobile/internal/sdkpath"
)

func TestRFC1034Label(t *testing.T) {
Expand Down Expand Up @@ -228,12 +230,8 @@ func TestBuildWithGoModules(t *testing.T) {
t.Run(target, func(t *testing.T) {
switch target {
case "android":
androidHome := os.Getenv("ANDROID_HOME")
if androidHome == "" {
t.Skip("ANDROID_HOME not found, skipping bind")
}
if _, err := androidAPIPath(); err != nil {
t.Skip("No android API platform found in $ANDROID_HOME, skipping bind")
if _, err := sdkpath.AndroidAPIPath(minAndroidAPI); err != nil {
t.Skip("No compatible android API platform found, skipping bind")
}
case "ios":
if !xcodeAvailable() {
Expand Down
Loading

0 comments on commit 8578da9

Please sign in to comment.