Sign zips with apksigner

This commit is contained in:
topjohnwu 2020-12-26 16:04:41 -08:00
parent ab78a81d15
commit e9e6ad3bb0
1 changed files with 82 additions and 62 deletions

126
build.py
View File

@ -2,13 +2,17 @@
import sys import sys
import os import os
import subprocess import subprocess
import argparse
is_windows = os.name == 'nt' import multiprocessing
is_ci = 'CI' in os.environ and os.environ['CI'] == 'true' import zipfile
import datetime
if not is_ci and is_windows: import errno
import colorama import shutil
colorama.init() import lzma
import platform
import urllib.request
import os.path as op
from distutils.dir_util import copy_tree
def error(str): def error(str):
@ -31,6 +35,13 @@ def vprint(str):
print(str) print(str)
is_windows = os.name == 'nt'
is_ci = 'CI' in os.environ and os.environ['CI'] == 'true'
if not is_ci and is_windows:
import colorama
colorama.init()
# Environment checks # Environment checks
if not sys.version_info >= (3, 6): if not sys.version_info >= (3, 6):
error('Requires Python 3.6+') error('Requires Python 3.6+')
@ -44,19 +55,6 @@ try:
except FileNotFoundError: except FileNotFoundError:
error('Please install JDK and make sure \'javac\' is available in PATH') error('Please install JDK and make sure \'javac\' is available in PATH')
import argparse
import multiprocessing
import zipfile
import datetime
import errno
import shutil
import lzma
import tempfile
import platform
import urllib.request
import os.path as op
from distutils.dir_util import copy_tree
cpu_count = multiprocessing.cpu_count() cpu_count = multiprocessing.cpu_count()
archs = ['armeabi-v7a', 'x86'] archs = ['armeabi-v7a', 'x86']
arch64 = ['arm64-v8a', 'x86_64'] arch64 = ['arm64-v8a', 'x86_64']
@ -71,6 +69,8 @@ gradlew = op.join('.', 'gradlew' + ('.bat' if is_windows else ''))
# Global vars # Global vars
config = {} config = {}
STDOUT = None STDOUT = None
build_tools = None
def mv(source, target): def mv(source, target):
try: try:
@ -198,31 +198,50 @@ def clean_elf():
execv(['g++', '-std=c++11', 'tools/termux-elf-cleaner/termux-elf-cleaner.cpp', execv(['g++', '-std=c++11', 'tools/termux-elf-cleaner/termux-elf-cleaner.cpp',
'-o', elf_cleaner]) '-o', elf_cleaner])
args = [elf_cleaner] args = [elf_cleaner]
args.extend(op.join('native', 'out', arch, 'magisk') for arch in archs + arch64) args.extend(op.join('native', 'out', arch, 'magisk')
for arch in archs + arch64)
execv(args) execv(args)
def sign_zip(unsigned, output, release): def find_build_tools():
if not release or 'keyStore' not in config: global build_tools
mv(unsigned, output) if build_tools:
return build_tools
build_tools_root = op.join(os.environ['ANDROID_SDK_ROOT'], 'build-tools')
ls = os.listdir(build_tools_root)
# Use the latest build tools available
ls.sort()
build_tools = op.join(build_tools_root, ls[-1])
return build_tools
def sign_zip(unsigned):
if 'keyStore' not in config:
return return
signer_name = 'zipsigner-4.0.jar' msg = '* Signing APK'
zipsigner = op.join('app', 'signing', 'build', 'libs', signer_name) apksigner = op.join(find_build_tools(), 'apksigner')
if not op.exists(zipsigner): execArgs = [apksigner, 'sign',
header('* Building ' + signer_name) '--ks', config['keyStore'],
proc = execv([gradlew, 'app:signing:shadowJar']) '--ks-pass', f'pass:{config["keyStorePass"]}',
'--ks-key-alias', config['keyAlias'],
'--key-pass', f'pass:{config["keyPass"]}',
'--v1-signer-name', 'CERT',
'--v4-signing-enabled', 'false']
if unsigned.endswith('.zip'):
msg = '* Signing zip'
execArgs.extend(['--min-sdk-version', '17',
'--v2-signing-enabled', 'false',
'--v3-signing-enabled', 'false'])
execArgs.append(unsigned)
header(msg)
proc = execv(execArgs)
if proc.returncode != 0: if proc.returncode != 0:
error(f'Build {signer_name} failed!') error('Signing failed!')
header('* Signing Zip')
proc = execv(['java', '-jar', zipsigner, config['keyStore'], config['keyStorePass'],
config['keyAlias'], config['keyPass'], unsigned, output])
if proc.returncode != 0:
error('Signing zip failed!')
def binary_dump(src, out, var_name): def binary_dump(src, out, var_name):
@ -398,10 +417,16 @@ def build_snet(args):
def zip_main(args): def zip_main(args):
header('* Packing Flashable Zip') header('* Packing Flashable Zip')
with tempfile.NamedTemporaryFile(delete=False) as f: if config['prettyName']:
unsigned = f.name name = f'Magisk-v{config["version"]}.zip'
elif args.release:
name = 'magisk-release.zip'
else:
name = 'magisk-debug.zip'
with zipfile.ZipFile(unsigned, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=False) as zipf: output = op.join(config['outdir'], name)
with zipfile.ZipFile(output, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=False) as zipf:
# update-binary # update-binary
target = op.join('META-INF', 'com', 'google', target = op.join('META-INF', 'com', 'google',
'android', 'update-binary') 'android', 'update-binary')
@ -454,20 +479,18 @@ def zip_main(args):
# End of zipping # End of zipping
output = op.join(config['outdir'], f'Magisk-v{config["version"]}.zip' if config['prettyName'] else sign_zip(output)
'magisk-release.zip' if args.release else 'magisk-debug.zip')
sign_zip(unsigned, output, args.release)
rm(unsigned)
header('Output: ' + output) header('Output: ' + output)
def zip_uninstaller(args): def zip_uninstaller(args):
header('* Packing Uninstaller Zip') header('* Packing Uninstaller Zip')
with tempfile.NamedTemporaryFile(delete=False) as f: datestr = datetime.datetime.now().strftime("%Y%m%d")
unsigned = f.name name = f'Magisk-uninstaller-{datestr}.zip' if config['prettyName'] else 'magisk-uninstaller.zip'
output = op.join(config['outdir'], name)
with zipfile.ZipFile(unsigned, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=False) as zipf: with zipfile.ZipFile(output, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=False) as zipf:
# update-binary # update-binary
target = op.join('META-INF', 'com', 'google', target = op.join('META-INF', 'com', 'google',
'android', 'update-binary') 'android', 'update-binary')
@ -500,11 +523,7 @@ def zip_uninstaller(args):
# End of zipping # End of zipping
datestr = datetime.datetime.now().strftime("%Y%m%d") sign_zip(output)
output = op.join(config['outdir'], f'Magisk-uninstaller-{datestr}.zip'
if config['prettyName'] else 'magisk-uninstaller.zip')
sign_zip(unsigned, output, args.release)
rm(unsigned)
header('Output: ' + output) header('Output: ' + output)
@ -581,6 +600,7 @@ def build_all(args):
parser = argparse.ArgumentParser(description='Magisk build script') parser = argparse.ArgumentParser(description='Magisk build script')
parser.set_defaults(func=lambda x: None)
parser.add_argument('-r', '--release', action='store_true', parser.add_argument('-r', '--release', action='store_true',
help='compile in release mode') help='compile in release mode')
parser.add_argument('-v', '--verbose', action='store_true', parser.add_argument('-v', '--verbose', action='store_true',