Rico Wind | 0ed24cc | 2018-03-23 07:16:35 +0100 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | # Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file |
| 3 | # for details. All rights reserved. Use of this source code is governed by a |
| 4 | # BSD-style license that can be found in the LICENSE file. |
| 5 | |
| 6 | # Script for building sample apks using the sdk tools directly. |
| 7 | |
| 8 | import apk_utils |
| 9 | import fnmatch |
| 10 | import glob |
| 11 | import optparse |
| 12 | import os |
| 13 | import shutil |
| 14 | import subprocess |
| 15 | import sys |
| 16 | import utils |
| 17 | |
| 18 | ANDROID_JAR = 'third_party/android_jar/lib-v{api}/android.jar' |
| 19 | DEFAULT_AAPT = 'aapt' # Assume in path. |
| 20 | DEFAULT_D8 = os.path.join(utils.REPO_ROOT, 'tools', 'd8.py') |
| 21 | DEFAULT_JAVAC = 'javac' |
| 22 | SRC_LOCATION = 'src/com/android/tools/r8/sample/{app}/*.java' |
| 23 | DEFAULT_KEYSTORE = os.path.join(os.getenv('HOME'), '.android', 'debug.keystore') |
| 24 | |
| 25 | SAMPLE_APKS = [ |
| 26 | 'simple' |
| 27 | ] |
| 28 | |
| 29 | def parse_options(): |
| 30 | result = optparse.OptionParser() |
| 31 | result.add_option('--aapt', |
| 32 | help='aapt executable to use', |
| 33 | default=DEFAULT_AAPT) |
| 34 | result.add_option('--api', |
| 35 | help='Android api level', |
| 36 | default=21, |
| 37 | choices=[14, 15, 19, 21, 22, 23, 24, 25, 26]) |
| 38 | result.add_option('--keystore', |
| 39 | help='Keystore used for signing', |
| 40 | default=DEFAULT_KEYSTORE) |
| 41 | result.add_option('--app', |
| 42 | help='Which app to build', |
| 43 | default='simple', |
| 44 | choices=SAMPLE_APKS) |
| 45 | return result.parse_args() |
| 46 | |
| 47 | def run_aapt(aapt, args): |
| 48 | command = [aapt] |
| 49 | command.extend(args) |
| 50 | utils.PrintCmd(command) |
| 51 | subprocess.check_call(command) |
| 52 | |
| 53 | def get_build_dir(app): |
| 54 | return os.path.join(utils.BUILD, 'sampleApks', app) |
| 55 | |
| 56 | def get_gen_path(app): |
| 57 | gen_path = os.path.join(get_build_dir(app), 'gen') |
| 58 | utils.makedirs_if_needed(gen_path) |
| 59 | return gen_path |
| 60 | |
| 61 | def get_bin_path(app): |
| 62 | bin_path = os.path.join(get_build_dir(app), 'bin') |
| 63 | utils.makedirs_if_needed(bin_path) |
| 64 | return bin_path |
| 65 | |
| 66 | def get_android_jar(api): |
| 67 | return os.path.join(utils.REPO_ROOT, ANDROID_JAR.format(api=api)) |
| 68 | |
| 69 | def get_sample_dir(app): |
| 70 | return os.path.join(utils.REPO_ROOT, 'src', 'test', 'sampleApks', app) |
| 71 | |
| 72 | def get_src_path(app): |
| 73 | return os.path.join(get_sample_dir(app), 'src') |
| 74 | |
| 75 | def run_aapt_pack(aapt, api, app): |
| 76 | with utils.ChangedWorkingDirectory(get_sample_dir(app)): |
| 77 | args = ['package', |
| 78 | '-v', '-f', |
| 79 | '-I', get_android_jar(api), |
| 80 | '-M', 'AndroidManifest.xml', |
| 81 | '-A', 'assets', |
| 82 | '-S', 'res', |
| 83 | '-m', |
| 84 | '-J', get_gen_path(app), |
Søren Gjesse | 12c5209 | 2018-04-05 14:22:29 +0200 | [diff] [blame^] | 85 | '-F', os.path.join(get_bin_path(app), 'resources.ap_'), |
| 86 | '-G', os.path.join(get_build_dir(app), 'proguard_options')] |
Rico Wind | 0ed24cc | 2018-03-23 07:16:35 +0100 | [diff] [blame] | 87 | run_aapt(aapt, args) |
| 88 | |
| 89 | def compile_with_javac(api, app): |
| 90 | with utils.ChangedWorkingDirectory(get_sample_dir(app)): |
| 91 | files = glob.glob(SRC_LOCATION.format(app=app)) |
| 92 | command = [DEFAULT_JAVAC, |
| 93 | '-classpath', get_android_jar(api), |
| 94 | '-sourcepath', '%s:%s' % (get_src_path(app), get_gen_path(app)), |
| 95 | '-d', get_bin_path(app)] |
| 96 | command.extend(files) |
| 97 | utils.PrintCmd(command) |
| 98 | subprocess.check_call(command) |
| 99 | |
| 100 | def dex(app, api): |
| 101 | files = [] |
| 102 | for root, dirnames, filenames in os.walk(get_bin_path(app)): |
| 103 | for filename in fnmatch.filter(filenames, '*.class'): |
| 104 | files.append(os.path.join(root, filename)) |
| 105 | command = [DEFAULT_D8, |
| 106 | '--output', get_bin_path(app), |
| 107 | '--classpath', get_android_jar(api), |
| 108 | '--min-api', str(api)] |
| 109 | command.extend(files) |
| 110 | utils.PrintCmd(command) |
| 111 | subprocess.check_call(command) |
| 112 | |
| 113 | def create_temp_apk(app): |
| 114 | temp_apk_path = os.path.join(get_bin_path(app), '%s.ap_' % app) |
| 115 | shutil.move(os.path.join(get_bin_path(app), 'resources.ap_'), |
| 116 | temp_apk_path) |
| 117 | return temp_apk_path |
| 118 | |
| 119 | def aapt_add_dex(aapt, app, temp_apk_path): |
| 120 | args = ['add', |
| 121 | '-k', temp_apk_path, |
| 122 | os.path.join(get_bin_path(app), 'classes.dex')] |
| 123 | run_aapt(aapt, args) |
| 124 | |
| 125 | def Main(): |
| 126 | (options, args) = parse_options() |
| 127 | run_aapt_pack(options.aapt, options.api, options.app) |
| 128 | compile_with_javac(options.api, options.app) |
| 129 | dex(options.app, options.api) |
| 130 | temp_apk_path = create_temp_apk(options.app) |
| 131 | aapt_add_dex(options.aapt, options.app, temp_apk_path) |
| 132 | apk_path = os.path.join(get_bin_path(options.app), '%s.apk' % options.app) |
| 133 | apk_utils.sign(temp_apk_path, apk_path, options.keystore) |
| 134 | print('Apk available at: %s' % apk_path) |
| 135 | |
| 136 | if __name__ == '__main__': |
| 137 | sys.exit(Main()) |