mirror of
https://github.com/go-i2p/gomobile-java.git
synced 2025-07-13 14:18:23 -04:00

Current output byte-for-byte of pkg binres is close, but not exact, to output of aapt. The current exceptions to this are as follows: * sort order of certain attributes * typed value of minSdkVersion These differences do not appear to affect the encoded manifest from working correctly. Further details on the byte differences can be seen in TestEncode. Fixes golang/go#13109 Change-Id: Ibfb7731143f0e2baeeb7dd5b04aa649566606a53 Reviewed-on: https://go-review.googlesource.com/20030 Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
142 lines
3.0 KiB
Go
142 lines
3.0 KiB
Go
package binres
|
|
|
|
import (
|
|
"archive/zip"
|
|
"bytes"
|
|
"compress/gzip"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path"
|
|
)
|
|
|
|
// MinSDK is the targetted sdk version for support by package binres.
|
|
const MinSDK = 15
|
|
|
|
// Requires environment variable ANDROID_HOME to be set.
|
|
func apiResources() ([]byte, error) {
|
|
sdkdir := os.Getenv("ANDROID_HOME")
|
|
if sdkdir == "" {
|
|
return nil, fmt.Errorf("ANDROID_HOME env var not set")
|
|
}
|
|
platform := fmt.Sprintf("android-%v", MinSDK)
|
|
zr, err := zip.OpenReader(path.Join(sdkdir, "platforms", platform, "android.jar"))
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return nil, fmt.Errorf(`%v; consider installing with "android update sdk --all --no-ui --filter %s"`, err, platform)
|
|
}
|
|
return nil, err
|
|
}
|
|
defer zr.Close()
|
|
|
|
buf := new(bytes.Buffer)
|
|
for _, f := range zr.File {
|
|
if f.Name == "resources.arsc" {
|
|
rc, err := f.Open()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
_, err = io.Copy(buf, rc)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
rc.Close()
|
|
break
|
|
}
|
|
}
|
|
if buf.Len() == 0 {
|
|
return nil, fmt.Errorf("failed to read resources.arsc")
|
|
}
|
|
return buf.Bytes(), nil
|
|
}
|
|
|
|
// PackResources produces a stripped down gzip version of the resources.arsc from api jar.
|
|
func PackResources() ([]byte, error) {
|
|
tbl, err := OpenSDKTable()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
tbl.pool.strings = []string{} // should not be needed
|
|
pkg := tbl.pkgs[0]
|
|
|
|
// drop language string entries
|
|
for _, typ := range pkg.specs[3].types {
|
|
if typ.config.locale.language != 0 {
|
|
for j, nt := range typ.entries {
|
|
if nt == nil { // NoEntry
|
|
continue
|
|
}
|
|
pkg.keyPool.strings[nt.key] = ""
|
|
typ.indices[j] = NoEntry
|
|
typ.entries[j] = nil
|
|
}
|
|
}
|
|
}
|
|
|
|
// drop strings from pool for specs to be dropped
|
|
for _, spec := range pkg.specs[4:] {
|
|
for _, typ := range spec.types {
|
|
for _, nt := range typ.entries {
|
|
if nt == nil { // NoEntry
|
|
continue
|
|
}
|
|
// don't drop if there's a collision
|
|
var collision bool
|
|
for _, xspec := range pkg.specs[:4] {
|
|
for _, xtyp := range xspec.types {
|
|
for _, xnt := range xtyp.entries {
|
|
if xnt == nil {
|
|
continue
|
|
}
|
|
if collision = nt.key == xnt.key; collision {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if !collision {
|
|
pkg.keyPool.strings[nt.key] = ""
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// entries are densely packed but probably safe to drop nil entries off the end
|
|
for _, spec := range pkg.specs[:4] {
|
|
for _, typ := range spec.types {
|
|
var last int
|
|
for i, nt := range typ.entries {
|
|
if nt != nil {
|
|
last = i
|
|
}
|
|
}
|
|
typ.entries = typ.entries[:last+1]
|
|
typ.indices = typ.indices[:last+1]
|
|
}
|
|
}
|
|
|
|
// keeping 0:attr, 1:id, 2:style, 3:string
|
|
pkg.typePool.strings = pkg.typePool.strings[:4]
|
|
pkg.specs = pkg.specs[:4]
|
|
|
|
bin, err := tbl.MarshalBinary()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
zw := gzip.NewWriter(buf)
|
|
if _, err := zw.Write(bin); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := zw.Flush(); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := zw.Close(); err != nil {
|
|
return nil, err
|
|
}
|
|
return buf.Bytes(), nil
|
|
}
|