| #!/usr/bin/env python |
| # Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file |
| # for details. All rights reserved. Use of this source code is governed by a |
| # BSD-style license that can be found in the LICENSE file. |
| |
| # Script for building sample apks using the sdk tools directly. |
| |
| import apk_utils |
| import fnmatch |
| import glob |
| import optparse |
| import os |
| import shutil |
| import subprocess |
| import sys |
| import utils |
| |
| ANDROID_JAR = 'third_party/android_jar/lib-v{api}/android.jar' |
| DEFAULT_AAPT = 'aapt' # Assume in path. |
| DEFAULT_D8 = os.path.join(utils.REPO_ROOT, 'tools', 'd8.py') |
| DEFAULT_JAVAC = 'javac' |
| SRC_LOCATION = 'src/com/android/tools/r8/sample/{app}/*.java' |
| DEFAULT_KEYSTORE = os.path.join(os.getenv('HOME'), '.android', 'debug.keystore') |
| |
| SAMPLE_APKS = [ |
| 'simple' |
| ] |
| |
| def parse_options(): |
| result = optparse.OptionParser() |
| result.add_option('--aapt', |
| help='aapt executable to use', |
| default=DEFAULT_AAPT) |
| result.add_option('--api', |
| help='Android api level', |
| default=21, |
| choices=[14, 15, 19, 21, 22, 23, 24, 25, 26]) |
| result.add_option('--keystore', |
| help='Keystore used for signing', |
| default=DEFAULT_KEYSTORE) |
| result.add_option('--app', |
| help='Which app to build', |
| default='simple', |
| choices=SAMPLE_APKS) |
| return result.parse_args() |
| |
| def run_aapt(aapt, args): |
| command = [aapt] |
| command.extend(args) |
| utils.PrintCmd(command) |
| subprocess.check_call(command) |
| |
| def get_build_dir(app): |
| return os.path.join(utils.BUILD, 'sampleApks', app) |
| |
| def get_gen_path(app): |
| gen_path = os.path.join(get_build_dir(app), 'gen') |
| utils.makedirs_if_needed(gen_path) |
| return gen_path |
| |
| def get_bin_path(app): |
| bin_path = os.path.join(get_build_dir(app), 'bin') |
| utils.makedirs_if_needed(bin_path) |
| return bin_path |
| |
| def get_android_jar(api): |
| return os.path.join(utils.REPO_ROOT, ANDROID_JAR.format(api=api)) |
| |
| def get_sample_dir(app): |
| return os.path.join(utils.REPO_ROOT, 'src', 'test', 'sampleApks', app) |
| |
| def get_src_path(app): |
| return os.path.join(get_sample_dir(app), 'src') |
| |
| def run_aapt_pack(aapt, api, app): |
| with utils.ChangedWorkingDirectory(get_sample_dir(app)): |
| args = ['package', |
| '-v', '-f', |
| '-I', get_android_jar(api), |
| '-M', 'AndroidManifest.xml', |
| '-A', 'assets', |
| '-S', 'res', |
| '-m', |
| '-J', get_gen_path(app), |
| '-F', os.path.join(get_bin_path(app), 'resources.ap_')] |
| run_aapt(aapt, args) |
| |
| def compile_with_javac(api, app): |
| with utils.ChangedWorkingDirectory(get_sample_dir(app)): |
| files = glob.glob(SRC_LOCATION.format(app=app)) |
| command = [DEFAULT_JAVAC, |
| '-classpath', get_android_jar(api), |
| '-sourcepath', '%s:%s' % (get_src_path(app), get_gen_path(app)), |
| '-d', get_bin_path(app)] |
| command.extend(files) |
| utils.PrintCmd(command) |
| subprocess.check_call(command) |
| |
| def dex(app, api): |
| files = [] |
| for root, dirnames, filenames in os.walk(get_bin_path(app)): |
| for filename in fnmatch.filter(filenames, '*.class'): |
| files.append(os.path.join(root, filename)) |
| command = [DEFAULT_D8, |
| '--output', get_bin_path(app), |
| '--classpath', get_android_jar(api), |
| '--min-api', str(api)] |
| command.extend(files) |
| utils.PrintCmd(command) |
| subprocess.check_call(command) |
| |
| def create_temp_apk(app): |
| temp_apk_path = os.path.join(get_bin_path(app), '%s.ap_' % app) |
| shutil.move(os.path.join(get_bin_path(app), 'resources.ap_'), |
| temp_apk_path) |
| return temp_apk_path |
| |
| def aapt_add_dex(aapt, app, temp_apk_path): |
| args = ['add', |
| '-k', temp_apk_path, |
| os.path.join(get_bin_path(app), 'classes.dex')] |
| run_aapt(aapt, args) |
| |
| def Main(): |
| (options, args) = parse_options() |
| run_aapt_pack(options.aapt, options.api, options.app) |
| compile_with_javac(options.api, options.app) |
| dex(options.app, options.api) |
| temp_apk_path = create_temp_apk(options.app) |
| aapt_add_dex(options.aapt, options.app, temp_apk_path) |
| apk_path = os.path.join(get_bin_path(options.app), '%s.apk' % options.app) |
| apk_utils.sign(temp_apk_path, apk_path, options.keystore) |
| print('Apk available at: %s' % apk_path) |
| |
| if __name__ == '__main__': |
| sys.exit(Main()) |