blob: 61e8141e6c3ad1f3962e2dbe9775bbf1d57445ad [file] [log] [blame]
# Copyright 2013 The Flutter Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import argparse
import os
import subprocess
import sys
import zipfile
def run_command_checked(command, env=None):
try:
env = env if env is not None else os.environ
subprocess.check_output(command, stderr=subprocess.STDOUT, text=True, env=env)
except subprocess.CalledProcessError as cpe:
print(cpe.output)
raise cpe
def is_mac():
return sys.platform == 'darwin'
def java_home():
script_path = os.path.dirname(os.path.realpath(__file__))
if is_mac():
return os.path.join(
script_path, '..', '..', '..', '..', 'third_party', 'java', 'openjdk', 'Contents', 'Home'
)
return os.path.join(script_path, '..', '..', 'third_party', 'java', 'openjdk')
def java_bin():
return os.path.join(java_home(), 'bin')
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--aapt2-bin', type=str, required=True, help='The path to the aapt2 binary.')
parser.add_argument(
'--zipalign-bin', type=str, required=True, help='The path to the zipalign binary.'
)
parser.add_argument(
'--apksigner-bin', type=str, required=True, help='The path to the apksigner binary.'
)
parser.add_argument(
'--android-manifest', type=str, required=True, help='The path to the AndroidManifest.xml.'
)
parser.add_argument('--android-jar', type=str, required=True, help='The path to android.jar.')
parser.add_argument('--output-path', type=str, required=True, help='The path to the output apk.')
parser.add_argument(
'--library', type=str, required=True, help='The path to the library to put in the apk.'
)
parser.add_argument(
'--keystore', type=str, required=True, help='The path to the debug keystore to sign the apk.'
)
parser.add_argument(
'--gen-dir', type=str, required=True, help='The directory for generated files.'
)
parser.add_argument(
'--android-abi', type=str, required=True, help='The android ABI of the library.'
)
args = parser.parse_args()
library_file = os.path.basename(args.library)
apk_name = os.path.basename(args.output_path)
unaligned_apk_path = os.path.join(args.gen_dir, '%s.unaligned' % apk_name)
unsigned_apk_path = os.path.join(args.gen_dir, '%s.unsigned' % apk_name)
apk_path = args.output_path
java_path = ':'.join([java_bin(), os.environ['PATH']])
env = dict(os.environ, PATH=java_path, JAVA_HOME=java_home())
# Create the skeleton of the APK using aapt2.
aapt2_command = [
args.aapt2_bin,
'link',
'-I',
args.android_jar,
'--manifest',
args.android_manifest,
'-o',
unaligned_apk_path,
]
run_command_checked(aapt2_command, env=env)
# Stuff the library in the APK which is just a regular ZIP file. Libraries are not compressed.
with zipfile.ZipFile(unaligned_apk_path, 'a', compression=zipfile.ZIP_STORED) as zipf:
zipf.write(args.library, 'lib/%s/%s' % (args.android_abi, library_file))
# Align the dylib to a page boundary.
zipalign_command = [
args.zipalign_bin,
'-p', # Page align the dylib
'-f', # overwrite output if exists
'4', # 32-bit alignment
unaligned_apk_path,
unsigned_apk_path,
]
run_command_checked(zipalign_command, env=env)
# Sign the APK.
apksigner_command = [
args.apksigner_bin, 'sign', '--ks', args.keystore, '--ks-pass', 'pass:android', '--out',
apk_path, unsigned_apk_path
]
run_command_checked(apksigner_command, env=env)
# Remove the intermediates so the out directory isn't full of large files.
os.remove(unaligned_apk_path)
os.remove(unsigned_apk_path)
return 0
if __name__ == '__main__':
sys.exit(main())