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",
},
}