From 81814e6fa41b75cd1e4bdb3bfb7710c7f8e0a8b0 Mon Sep 17 00:00:00 2001 From: Greg Pomerantz Date: Mon, 7 Oct 2019 10:29:16 -0400 Subject: [PATCH] cmd/gogio: add -minversion flag to specify minimum Android platform Allow the user to specify a minimum supported Android platform version. Signed-off-by: Greg Pomerantz --- cmd/gogio/androidbuild.go | 60 +++++++++++++++++++++++++++++++++------ cmd/gogio/gio.go | 33 +++++++++++---------- 2 files changed, 70 insertions(+), 23 deletions(-) diff --git a/cmd/gogio/androidbuild.go b/cmd/gogio/androidbuild.go index bab42aef..bb0525c1 100644 --- a/cmd/gogio/androidbuild.go +++ b/cmd/gogio/androidbuild.go @@ -85,15 +85,15 @@ func compileAndroid(tmpDir string, tools *androidTools, bi *buildInfo) (err erro var builds errgroup.Group for _, a := range bi.archs { arch := allArchs[a] - clang := filepath.Join(tcRoot, "bin", arch.clang) - if _, err := os.Stat(clang); err != nil { - return fmt.Errorf("no NDK compiler found. Please make sure you have NDK >= r19c installed. Use the command `sdkmanager ndk-bundle` to install it. Path %s", clang) + clang, err := latestCompiler(tcRoot, a, bi.minsdk) + if err != nil { + return fmt.Errorf("%s. Please make sure you have NDK >= r19c installed. Use the command `sdkmanager ndk-bundle` to install it.", err) } if runtime.GOOS == "windows" { // Because of https://github.com/android-ndk/ndk/issues/920, // we need NDK r19c, not just r19b. Check for the presence of // clang++.cmd which is only available in r19c. - clangpp := filepath.Join(tcRoot, "bin", arch.clang+"++.cmd") + clangpp := clang + "++.cmd" if _, err := os.Stat(clangpp); err != nil { return fmt.Errorf("NDK version r19b detected, but >= r19c is required. Use the command `sdkmanager ndk-bundle` to install it") } @@ -177,9 +177,9 @@ func archiveAndroid(tmpDir string, bi *buildInfo) (err error) { aarw.Create("res/") manifest := aarw.Create("AndroidManifest.xml") manifest.Write([]byte(fmt.Sprintf(` - + -`, bi.appID))) +`, bi.appID, bi.minsdk))) proguard := aarw.Create("proguard.txt") proguard.Write([]byte(`-keep class org.gioui.** { *; }`)) @@ -286,13 +286,19 @@ func exeAndroid(tmpDir string, tools *androidTools, bi *buildInfo) (err error) { } // Link APK. + // Currently, new apps must have a target SDK version of at least 28. + // https://developer.android.com/distribute/best-practices/develop/target-sdk + targetSDK := 28 + if bi.minsdk > targetSDK { + targetSDK = bi.minsdk + } appName := strings.Title(bi.name) manifestSrc := fmt.Sprintf(` - + @@ -307,7 +313,7 @@ func exeAndroid(tmpDir string, tools *androidTools, bi *buildInfo) (err error) { -`, bi.appID, bi.version, bi.version, iconSnip, appName, appName) +`, bi.appID, bi.version, bi.version, bi.minsdk, targetSDK, iconSnip, appName, appName) manifest := filepath.Join(tmpDir, "AndroidManifest.xml") if err := ioutil.WriteFile(manifest, []byte(manifestSrc), 0660); err != nil { return err @@ -515,6 +521,44 @@ func latestPlatform(sdk string) (string, error) { return bestPlat, nil } +func latestCompiler(tcRoot, a string, minsdk int) (string, error) { + arch := allArchs[a] + allComps, err := filepath.Glob(filepath.Join(tcRoot, "bin", arch.clangArch+"*-clang")) + if err != nil { + return "", err + } + var bestVer int + var firstVer int + var bestCompiler string + var firstCompiler string + for _, compiler := range allComps { + var ver int + pattern := filepath.Join(tcRoot, "bin", arch.clangArch) + "%d-clang" + if n, err := fmt.Sscanf(compiler, pattern, &ver); n < 1 || err != nil { + continue + } + if firstCompiler == "" || ver < firstVer { + firstVer = ver + firstCompiler = compiler + } + if ver < bestVer { + continue + } + if ver > minsdk { + continue + } + bestVer = ver + bestCompiler = compiler + } + if bestCompiler == "" { + bestCompiler = firstCompiler + } + if bestCompiler == "" { + return "", fmt.Errorf("no NDK compiler found for architecture %s", a) + } + return bestCompiler, nil +} + func latestTools(sdk string) (string, error) { allTools, err := filepath.Glob(filepath.Join(sdk, "build-tools", "*")) if err != nil { diff --git a/cmd/gogio/gio.go b/cmd/gogio/gio.go index ae82d25a..389dce45 100644 --- a/cmd/gogio/gio.go +++ b/cmd/gogio/gio.go @@ -24,6 +24,7 @@ import ( var ( target = flag.String("target", "", "specify target (ios, tvos, android, js).\n") archNames = flag.String("arch", "", "specify architecture(s) to include (arm, arm64, amd64).") + minsdk = flag.Int("minsdk", 16, "specify minimum supported Android platform sdk version (e.g. 28 for android28 a.k.a. Android 9 Pie).") buildMode = flag.String("buildmode", "exe", "specify buildmode (archive, exe)") destPath = flag.String("o", "", "output file or directory.\nFor -target ios or tvos, use the .app suffix to target simulators.") appID = flag.String("appid", "", "app identifier (for -buildmode=exe)") @@ -41,6 +42,7 @@ type buildInfo struct { version int dir string archs []string + minsdk int } func main() { @@ -91,6 +93,7 @@ func mainErr() error { appID: *appID, dir: dir, version: *version, + minsdk: *minsdk, } if bi.appID == "" { bi.appID = appIDFromPackage(pkgPath) @@ -211,31 +214,31 @@ func copyFile(dst, src string) (err error) { } type arch struct { - iosArch string - jniArch string - clang string + iosArch string + jniArch string + clangArch string } var allArchs = map[string]arch{ "arm": arch{ - iosArch: "armv7", - jniArch: "armeabi-v7a", - clang: "armv7a-linux-androideabi16-clang", + iosArch: "armv7", + jniArch: "armeabi-v7a", + clangArch: "armv7a-linux-androideabi", }, "arm64": arch{ - iosArch: "arm64", - jniArch: "arm64-v8a", - clang: "aarch64-linux-android21-clang", + iosArch: "arm64", + jniArch: "arm64-v8a", + clangArch: "aarch64-linux-android", }, "386": arch{ - iosArch: "i386", - jniArch: "x86", - clang: "i686-linux-android16-clang", + iosArch: "i386", + jniArch: "x86", + clangArch: "i686-linux-android", }, "amd64": arch{ - iosArch: "x86_64", - jniArch: "x86_64", - clang: "x86_64-linux-android21-clang", + iosArch: "x86_64", + jniArch: "x86_64", + clangArch: "x86_64-linux-android", }, }