Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added app-unsigned.apk
Binary file not shown.
69 changes: 69 additions & 0 deletions app/AndroidManifest.hex
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
03 00 # xml chunk type
08 00 # header size
98 00 00 00 # chunk size

01 00 # string pool type
18 00 # header size, 24 bytes
40 00 00 00 # chunk size
03 00 00 00 # string count
00 00 00 00 # style count
00 01 00 00 # flags, utf-8 bit is set
24 00 00 00 # strings start

# string offsets:

00 00 00 00
0b 00 00 00
15 00 00 00

# string data:

08 08 6d 61 # len=8, "manifest"
6e 69 66 65
73 74 00

07 07 70 61 # len=7, "package"
63 6b 61 67
65 00

03 03 63 2e # len=3, "c.c"
63 00

00 # 0-padding

# xml contents:

02 01 # XML start element
10 00 # header size
38 00 00 00 # chunk size
00 00 00 00 # line number
00 00 00 00 # comment, index into string pool
00 00 00 00 # namespace index, 0
00 00 00 00 # name of the node, "manifest"
14 00 # attributes offset
14 00 # attributes size
01 00 # attribute count
00 00 # id index
00 00 # class index
00 00 # style index

# attribute data

ff ff ff ff # namespace index, -1
01 00 00 00 # name, "package"
02 00 00 00 # raw value, "c.c"

# typed value for attribute[0]

08 00 # size
00 # always 0
03 # TYPE_STRING
02 00 00 00 # value index, "c.c"

03 01 # XML end element
10 00 # header size
18 00 00 00 # chunk size
00 00 00 00 # line number
00 00 00 00 # comment
00 00 00 00 # namespace index, 0
00 00 00 00 # name of the node, "manifest"
Binary file modified app/AndroidManifest.xml
Binary file not shown.
Binary file modified app/keystore.jks
Binary file not shown.
1 change: 0 additions & 1 deletion app/res/layout/manifest.xml

This file was deleted.

32 changes: 5 additions & 27 deletions build.sh
Original file line number Diff line number Diff line change
@@ -1,38 +1,16 @@
#!/usr/bin/env bash
#!/usr/bin/env bash -ex

rm -rf build
mkdir -p build/apk

set -x

# Use zopfli compression if available
recompress() {
if hash advzip 2>/dev/null; then
advzip -4 -i 256 --recompress "$@"
else
echo "Use advcomp for better compression (http://www.advancemame.it/download) / (brew install advancecomp)"
fi
}

#TODO ensure that ANDROID_HOME is set

echo "Creating base AndroidManifest.xml"
$ANDROID_HOME/build-tools/26.0.2/aapt p -M app/AndroidManifest.xml -S app/res -I $ANDROID_HOME/platforms/android-26/android.jar -f -F build/base.apk
unzip build/base.apk -d build/apk

# Don't use the original manifest with all the generated junk, use the compiled xml from layout instead
rm build/apk/AndroidManifest.xml
rm build/apk/resources.arsc
mv build/apk/res/layout/manifest.xml build/apk/AndroidManifest.xml
rm -rf build/apk/res
: ${ANDROID_HOME:?"Need to set ANDROID_HOME"}

echo "Creating base apk"
cp app/AndroidManifest.xml build/apk/
echo "Creating empty classes.dex"
touch build/apk/classes.dex

echo "Creating unsigned archive"
zip -j -r build/app-unsigned.apk build/apk

recompress build/app-unsigned.apk
python3 zipcrush.py build/app-unsigned.apk build/apk/*

echo "Signing archive"
KEYSTORE_PASS=android $ANDROID_HOME/build-tools/26.0.2/apksigner sign --v1-signing-enabled false --ks app/keystore.jks --out build/signed-release.apk --ks-pass env:KEYSTORE_PASS --ks-key-alias android --min-sdk-version 24 build/app-unsigned.apk
Expand Down
Binary file modified signed-release.apk
Binary file not shown.
76 changes: 76 additions & 0 deletions zipcrush.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#!/usr/bin/python3

import subprocess
import zipfile
import tempfile
import os

def zopfli_compress(data):
with tempfile.NamedTemporaryFile() as outf:
outf.write(data)
outf.flush()
result = subprocess.check_output(['zopfli', '--deflate', '-c', '--i1000', outf.name])
return result

class ZopfliCompressor:
def __init__(self):
self.data = bytearray()

def compress(self, data):
self.data += data
return b''

def flush(self):
return zopfli_compress(self.data)


orig_get_compressor = zipfile._get_compressor

def get_compressor(compress_type):
if compress_type == zipfile.ZIP_DEFLATED:
return ZopfliCompressor()
else:
return orig_get_compressor(compress_type)

zipfile._get_compressor = get_compressor

def main(argv):
import argparse

description = 'Create the tiniest zipfiles possible.'
parser = argparse.ArgumentParser(description=description)
parser.add_argument('zipfile')
parser.add_argument('files', nargs='+')
args = parser.parse_args(argv)

zip_name = args.zipfile
files = args.files

def addToZip(zf, path, zippath):
if os.path.isfile(path):
# XXX this compresses things twice :(
with open(path, 'rb') as inf:
infdata = inf.read()
if len(infdata) < len(zopfli_compress(infdata)):
zf.write(path, zippath, zipfile.ZIP_STORED)
else:
zf.write(path, zippath, zipfile.ZIP_DEFLATED)
elif os.path.isdir(path):
if zippath:
zf.write(path, zippath)
for nm in os.listdir(path):
addToZip(zf,
os.path.join(path, nm), os.path.join(zippath, nm))

with zipfile.ZipFile(zip_name, 'w') as zf:
for path in files:
zippath = os.path.basename(path)
if not zippath:
zippath = os.path.basename(os.path.dirname(path))
if zippath in ('', os.curdir, os.pardir):
zippath = ''
addToZip(zf, path, zippath)

if __name__ == "__main__":
import sys
main(sys.argv[1:])