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 <inkeliz@inkeliz.com>
This commit is contained in:
Inkeliz
2021-02-21 16:51:39 +00:00
committed by Elias Naur
parent 9d1e3370f4
commit 2a7295750d
+63 -61
View File
@@ -7,6 +7,8 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"golang.org/x/sync/errgroup"
"golang.org/x/tools/go/packages"
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
@@ -16,9 +18,6 @@ import (
"strconv" "strconv"
"strings" "strings"
"text/template" "text/template"
"golang.org/x/sync/errgroup"
"golang.org/x/tools/go/packages"
) )
type androidTools struct { type androidTools struct {
@@ -329,15 +328,15 @@ func exeAndroid(tmpDir string, tools *androidTools, bi *buildInfo, extraJars, pe
return nil return nil
}) })
classFiles = append(classFiles, extraJars...) classFiles = append(classFiles, extraJars...)
apkDir := filepath.Join(tmpDir, "apk") dexDir := filepath.Join(tmpDir, "apk")
if err := os.MkdirAll(apkDir, 0755); err != nil { if err := os.MkdirAll(dexDir, 0755); err != nil {
return err return err
} }
if len(classFiles) > 0 { if len(classFiles) > 0 {
d8 := exec.Command( d8 := exec.Command(
filepath.Join(tools.buildtools, "d8"), filepath.Join(tools.buildtools, "d8"),
"--classpath", tools.androidjar, "--classpath", tools.androidjar,
"--output", apkDir, "--output", dexDir,
) )
d8.Args = append(d8.Args, classFiles...) d8.Args = append(d8.Args, classFiles...)
if _, err := runCmd(d8); err != nil { if _, err := runCmd(d8); err != nil {
@@ -440,60 +439,95 @@ func exeAndroid(tmpDir string, tools *androidTools, bi *buildInfo, extraJars, pe
return err return err
} }
tmpapk := filepath.Join(tmpDir, "link.apk") linkAPK := filepath.Join(tmpDir, "link.apk")
link := exec.Command( link := exec.Command(
aapt2, aapt2,
"link", "link",
"--manifest", manifest, "--manifest", manifest,
"-I", tools.androidjar, "-I", tools.androidjar,
"-o", tmpapk, "-o", linkAPK,
resZip, resZip,
) )
if _, err := runCmd(link); err != nil { if _, err := runCmd(link); err != nil {
return err return err
} }
// The Go standard library archive/zip doesn't support appending to zip // 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 // files. Copy files from `link.apk` (generated by aapt2) along with classes.dex and
// classes.dex and the Go libraries. // the Go libraries to a new `app.ap_` file.
if err := unzip(apkDir, tmpapk); err != nil {
// Load link.apk as zip.
linkAPKZip, err := zip.OpenReader(linkAPK)
if err != nil {
return err return err
} }
tmpApk := filepath.Join(tmpDir, "app.ap_") defer linkAPKZip.Close()
ap_, err := os.Create(tmpApk)
// Create new "APK".
unsignedAPK := filepath.Join(tmpDir, "app.ap_")
unsignedAPKFile, err := os.Create(unsignedAPK)
if err != nil { if err != nil {
return err return err
} }
defer func() { defer func() {
if cerr := ap_.Close(); err == nil { if cerr := unsignedAPKFile.Close(); err == nil {
err = cerr err = cerr
} }
}() }()
apkw := newZipWriter(ap_) unsignedAPKZip := zip.NewWriter(unsignedAPKFile)
defer apkw.Close() defer unsignedAPKZip.Close()
err = filepath.Walk(apkDir, func(path string, f os.FileInfo, err error) error {
// 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 { if err != nil {
return err return err
} }
if f.IsDir() { r, err := f.Open()
return nil if err != nil {
return err
} }
zpath := path[len(apkDir)+1:] if _, err := io.Copy(w, r); err != nil {
if filepath.Base(path) == "resources.arsc" { return err
apkw.Store(zpath, path)
} else {
apkw.Add(zpath, path)
} }
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 return err
} }
// Append Go binaries (libgio.so).
for _, a := range bi.archs { for _, a := range bi.archs {
arch := allArchs[a] arch := allArchs[a]
libFile := filepath.Join(arch.jniArch, "libgio.so") 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 { func signAPK(tmpDir string, tools *androidTools, bi *buildInfo) error {
@@ -553,38 +587,6 @@ func signAPK(tmpDir string, tools *androidTools, bi *buildInfo) error {
return nil 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) { func findNDK(androidHome string) (string, error) {
ndks, err := filepath.Glob(filepath.Join(androidHome, "ndk", "*")) ndks, err := filepath.Glob(filepath.Join(androidHome, "ndk", "*"))
if err != nil { if err != nil {