From 2a7295750de2d23e09732818780648a2f89916a1 Mon Sep 17 00:00:00 2001 From: Inkeliz Date: Sun, 21 Feb 2021 16:51:39 +0000 Subject: [PATCH] cmd/gogio: fix icon/resources for Android Previously that patch, gogio unzip the `link.apk` (generated by AAPT2) to an temporary folder and then compress it again to a new `app.ap_` file. For some unknown reason, that unzip-then-zip doesn't work. The resources are included but is corrupted in somehow. That PR aims to fix that by avoid the extraction to an temporary folder. Signed-off-by: Inkeliz --- cmd/gogio/androidbuild.go | 124 +++++++++++++++++++------------------- 1 file changed, 63 insertions(+), 61 deletions(-) diff --git a/cmd/gogio/androidbuild.go b/cmd/gogio/androidbuild.go index 3ece6527..fc21d40e 100644 --- a/cmd/gogio/androidbuild.go +++ b/cmd/gogio/androidbuild.go @@ -7,6 +7,8 @@ import ( "bytes" "errors" "fmt" + "golang.org/x/sync/errgroup" + "golang.org/x/tools/go/packages" "io" "io/ioutil" "os" @@ -16,9 +18,6 @@ import ( "strconv" "strings" "text/template" - - "golang.org/x/sync/errgroup" - "golang.org/x/tools/go/packages" ) type androidTools struct { @@ -329,15 +328,15 @@ func exeAndroid(tmpDir string, tools *androidTools, bi *buildInfo, extraJars, pe return nil }) classFiles = append(classFiles, extraJars...) - apkDir := filepath.Join(tmpDir, "apk") - if err := os.MkdirAll(apkDir, 0755); err != nil { + dexDir := filepath.Join(tmpDir, "apk") + if err := os.MkdirAll(dexDir, 0755); err != nil { return err } if len(classFiles) > 0 { d8 := exec.Command( filepath.Join(tools.buildtools, "d8"), "--classpath", tools.androidjar, - "--output", apkDir, + "--output", dexDir, ) d8.Args = append(d8.Args, classFiles...) if _, err := runCmd(d8); err != nil { @@ -440,60 +439,95 @@ func exeAndroid(tmpDir string, tools *androidTools, bi *buildInfo, extraJars, pe return err } - tmpapk := filepath.Join(tmpDir, "link.apk") + linkAPK := filepath.Join(tmpDir, "link.apk") link := exec.Command( aapt2, "link", "--manifest", manifest, "-I", tools.androidjar, - "-o", tmpapk, + "-o", linkAPK, resZip, ) if _, err := runCmd(link); err != nil { return err } // The Go standard library archive/zip doesn't support appending to zip - // files. Unpack the apk from aapt2 and re-zip its contents along with - // classes.dex and the Go libraries. - if err := unzip(apkDir, tmpapk); err != nil { + // files. Copy files from `link.apk` (generated by aapt2) along with classes.dex and + // the Go libraries to a new `app.ap_` file. + + // Load link.apk as zip. + linkAPKZip, err := zip.OpenReader(linkAPK) + if err != nil { return err } - tmpApk := filepath.Join(tmpDir, "app.ap_") - ap_, err := os.Create(tmpApk) + defer linkAPKZip.Close() + + // Create new "APK". + unsignedAPK := filepath.Join(tmpDir, "app.ap_") + unsignedAPKFile, err := os.Create(unsignedAPK) if err != nil { return err } defer func() { - if cerr := ap_.Close(); err == nil { + if cerr := unsignedAPKFile.Close(); err == nil { err = cerr } }() - apkw := newZipWriter(ap_) - defer apkw.Close() - err = filepath.Walk(apkDir, func(path string, f os.FileInfo, err error) error { + unsignedAPKZip := zip.NewWriter(unsignedAPKFile) + defer unsignedAPKZip.Close() + + // Copy files from linkAPK to unsignedAPK. + for _, f := range linkAPKZip.File { + header := zip.FileHeader{ + Name: f.FileHeader.Name, + Method: f.FileHeader.Method, + } + + w, err := unsignedAPKZip.CreateHeader(&header) if err != nil { return err } - if f.IsDir() { - return nil + r, err := f.Open() + if err != nil { + return err } - zpath := path[len(apkDir)+1:] - if filepath.Base(path) == "resources.arsc" { - apkw.Store(zpath, path) - } else { - apkw.Add(zpath, path) + if _, err := io.Copy(w, r); err != nil { + return err } - return nil - }) - if err != nil { + } + + // Append new files (that doesn't exists inside the link.apk). + appendToZip := func(path string, file string) error { + f, err := os.Open(file) + if err != nil { + return err + } + defer f.Close() + w, err := unsignedAPKZip.CreateHeader(&zip.FileHeader{ + Name: filepath.ToSlash(path), + Method: zip.Deflate, + }) + if err != nil { + return err + } + _, err = io.Copy(w, f) return err } + + // Append Go binaries (libgio.so). for _, a := range bi.archs { arch := allArchs[a] libFile := filepath.Join(arch.jniArch, "libgio.so") - apkw.Add(filepath.ToSlash(filepath.Join("lib", libFile)), filepath.Join(tmpDir, "jni", libFile)) + if err := appendToZip(filepath.Join("lib", libFile), filepath.Join(tmpDir, "jni", libFile)); err != nil { + return err + } } - return apkw.Close() + + // Append classes.dex. + if err := appendToZip("classes.dex", filepath.Join(dexDir, "classes.dex")); err != nil { + return err + } + return unsignedAPKZip.Close() } func signAPK(tmpDir string, tools *androidTools, bi *buildInfo) error { @@ -553,38 +587,6 @@ func signAPK(tmpDir string, tools *androidTools, bi *buildInfo) error { return nil } -func unzip(dir, zipfile string) (err error) { - zipr, err := zip.OpenReader(zipfile) - if err != nil { - return err - } - defer zipr.Close() - for _, f := range zipr.File { - path := filepath.Join(dir, f.Name) - if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil { - return err - } - out, err := os.Create(path) - if err != nil { - return err - } - defer func() { - if cerr := out.Close(); err == nil { - err = cerr - } - }() - in, err := f.Open() - if err != nil { - return err - } - defer in.Close() - if _, err := io.Copy(out, in); err != nil { - return err - } - } - return nil -} - func findNDK(androidHome string) (string, error) { ndks, err := filepath.Glob(filepath.Join(androidHome, "ndk", "*")) if err != nil {