OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # | 2 # |
3 # Copyright 2014 The Chromium Authors. All rights reserved. | 3 # Copyright 2014 The Chromium Authors. All rights reserved. |
4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 | 6 |
7 # pylint: disable=C0301 | 7 # pylint: disable=C0301 |
8 """Package resources into an apk. | 8 """Package resources into an apk. |
9 | 9 |
10 See https://android.googlesource.com/platform/tools/base/+/master/legacy/ant-tas
ks/src/main/java/com/android/ant/AaptExecTask.java | 10 See https://android.googlesource.com/platform/tools/base/+/master/legacy/ant-tas
ks/src/main/java/com/android/ant/AaptExecTask.java |
11 and | 11 and |
12 https://android.googlesource.com/platform/sdk/+/master/files/ant/build.xml | 12 https://android.googlesource.com/platform/sdk/+/master/files/ant/build.xml |
13 """ | 13 """ |
14 # pylint: enable=C0301 | 14 # pylint: enable=C0301 |
15 | 15 |
16 import optparse | 16 import optparse |
17 import os | 17 import os |
18 import shutil | 18 import shutil |
| 19 import zipfile |
19 | 20 |
20 from util import build_utils | 21 from util import build_utils |
21 | 22 |
| 23 |
| 24 # List is generated from the chrome_apk.apk_intermediates.ap_ via: |
| 25 # unzip -l $FILE_AP_ | cut -c31- | grep res/draw | cut -d'/' -f 2 | sort \ |
| 26 # | uniq | grep -- -tvdpi- | cut -c10- |
| 27 # and then manually sorted. |
| 28 # Note that we can't just do a cross-product of dimentions because the filenames |
| 29 # become too big and aapt fails to create the files. |
| 30 # This leaves all default drawables (mdpi) in the main apk. Android gets upset |
| 31 # though if any drawables are missing from the default drawables/ directory. |
| 32 DENSITY_SPLITS = { |
| 33 'hdpi': ( |
| 34 'hdpi-v4', # Order matters for output file names. |
| 35 'ldrtl-hdpi-v4', |
| 36 'sw600dp-hdpi-v13', |
| 37 'ldrtl-hdpi-v17', |
| 38 'ldrtl-sw600dp-hdpi-v17', |
| 39 'hdpi-v21', |
| 40 ), |
| 41 'xhdpi': ( |
| 42 'xhdpi-v4', |
| 43 'ldrtl-xhdpi-v4', |
| 44 'sw600dp-xhdpi-v13', |
| 45 'ldrtl-xhdpi-v17', |
| 46 'ldrtl-sw600dp-xhdpi-v17', |
| 47 'xhdpi-v21', |
| 48 ), |
| 49 'xxhdpi': ( |
| 50 'xxhdpi-v4', |
| 51 'ldrtl-xxhdpi-v4', |
| 52 'sw600dp-xxhdpi-v13', |
| 53 'ldrtl-xxhdpi-v17', |
| 54 'ldrtl-sw600dp-xxhdpi-v17', |
| 55 'xxhdpi-v21', |
| 56 ), |
| 57 'tvdpi': ( |
| 58 'tvdpi-v4', |
| 59 'sw600dp-tvdpi-v13', |
| 60 'ldrtl-sw600dp-tvdpi-v17', |
| 61 ), |
| 62 } |
| 63 |
| 64 |
22 def ParseArgs(): | 65 def ParseArgs(): |
23 """Parses command line options. | 66 """Parses command line options. |
24 | 67 |
25 Returns: | 68 Returns: |
26 An options object as from optparse.OptionsParser.parse_args() | 69 An options object as from optparse.OptionsParser.parse_args() |
27 """ | 70 """ |
28 parser = optparse.OptionParser() | 71 parser = optparse.OptionParser() |
29 build_utils.AddDepfileOption(parser) | 72 build_utils.AddDepfileOption(parser) |
30 parser.add_option('--android-sdk', help='path to the Android SDK folder') | 73 parser.add_option('--android-sdk', help='path to the Android SDK folder') |
31 parser.add_option('--android-sdk-tools', | 74 parser.add_option('--android-sdk-tools', |
32 help='path to the Android SDK build tools folder') | 75 help='path to the Android SDK build tools folder') |
33 | 76 |
34 parser.add_option('--configuration-name', | 77 parser.add_option('--configuration-name', |
35 help='Gyp\'s configuration name (Debug or Release).') | 78 help='Gyp\'s configuration name (Debug or Release).') |
36 | 79 |
37 parser.add_option('--android-manifest', help='AndroidManifest.xml path') | 80 parser.add_option('--android-manifest', help='AndroidManifest.xml path') |
38 parser.add_option('--version-code', help='Version code for apk.') | 81 parser.add_option('--version-code', help='Version code for apk.') |
39 parser.add_option('--version-name', help='Version name for apk.') | 82 parser.add_option('--version-name', help='Version name for apk.') |
40 parser.add_option( | 83 parser.add_option( |
41 '--shared-resources', | 84 '--shared-resources', |
42 action='store_true', | 85 action='store_true', |
43 help='Make a resource package that can be loaded by a different' | 86 help='Make a resource package that can be loaded by a different' |
44 'application at runtime to access the package\'s resources.') | 87 'application at runtime to access the package\'s resources.') |
45 parser.add_option('--resource-zips', | 88 parser.add_option('--resource-zips', |
46 help='zip files containing resources to be packaged') | 89 help='zip files containing resources to be packaged') |
47 parser.add_option('--asset-dir', | 90 parser.add_option('--asset-dir', |
48 help='directories containing assets to be packaged') | 91 help='directories containing assets to be packaged') |
49 parser.add_option('--no-compress', help='disables compression for the ' | 92 parser.add_option('--no-compress', help='disables compression for the ' |
50 'given comma separated list of extensions') | 93 'given comma separated list of extensions') |
| 94 parser.add_option( |
| 95 '--create-density-splits', |
| 96 action='store_true', |
| 97 help='Enables density splits') |
51 | 98 |
52 parser.add_option('--apk-path', | 99 parser.add_option('--apk-path', |
53 help='Path to output (partial) apk.') | 100 help='Path to output (partial) apk.') |
54 | 101 |
55 (options, args) = parser.parse_args() | 102 (options, args) = parser.parse_args() |
56 | 103 |
57 if args: | 104 if args: |
58 parser.error('No positional arguments should be given.') | 105 parser.error('No positional arguments should be given.') |
59 | 106 |
60 # Check that required options have been provided. | 107 # Check that required options have been provided. |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
107 res_dirs = sorted(subdirs, key=lambda p : int(os.path.basename(p))) | 154 res_dirs = sorted(subdirs, key=lambda p : int(os.path.basename(p))) |
108 else: | 155 else: |
109 res_dirs = [d] | 156 res_dirs = [d] |
110 package_command = [] | 157 package_command = [] |
111 for d in res_dirs: | 158 for d in res_dirs: |
112 MoveImagesToNonMdpiFolders(d) | 159 MoveImagesToNonMdpiFolders(d) |
113 package_command += ['-S', d] | 160 package_command += ['-S', d] |
114 return package_command | 161 return package_command |
115 | 162 |
116 | 163 |
| 164 def RenameDensitySplits(apk_path): |
| 165 """Renames all density splits to have shorter / predictable names.""" |
| 166 for density, config in DENSITY_SPLITS.iteritems(): |
| 167 src_path = '%s_%s' % (apk_path, '_'.join(config)) |
| 168 dst_path = '%s-%s' % (apk_path, density) |
| 169 if os.path.exists(dst_path): |
| 170 os.unlink(dst_path) |
| 171 os.rename(src_path, dst_path) |
| 172 |
| 173 |
| 174 def CheckDensityMissedConfigs(apk_path): |
| 175 """Raises an exception if apk_path contains any density-specifc files.""" |
| 176 triggers = ['-%s' % density for density in DENSITY_SPLITS] |
| 177 with zipfile.ZipFile(apk_path) as main_apk_zip: |
| 178 for name in main_apk_zip.namelist(): |
| 179 for trigger in triggers: |
| 180 if trigger in name and not 'mipmap-' in name: |
| 181 raise Exception(('Found density in main apk that should have been ' + |
| 182 'put into a split: %s\nYou need to update ' + |
| 183 'package_resources.py to include this new ' + |
| 184 'config.') % name) |
| 185 |
| 186 |
117 def main(): | 187 def main(): |
118 options = ParseArgs() | 188 options = ParseArgs() |
119 android_jar = os.path.join(options.android_sdk, 'android.jar') | 189 android_jar = os.path.join(options.android_sdk, 'android.jar') |
120 aapt = os.path.join(options.android_sdk_tools, 'aapt') | 190 aapt = os.path.join(options.android_sdk_tools, 'aapt') |
121 | 191 |
122 with build_utils.TempDir() as temp_dir: | 192 with build_utils.TempDir() as temp_dir: |
123 package_command = [aapt, | 193 package_command = [aapt, |
124 'package', | 194 'package', |
125 '--version-code', options.version_code, | 195 '--version-code', options.version_code, |
126 '--version-name', options.version_name, | 196 '--version-name', options.version_name, |
127 '-M', options.android_manifest, | 197 '-M', options.android_manifest, |
128 '--no-crunch', | 198 '--no-crunch', |
129 '-f', | 199 '-f', |
130 '--auto-add-overlay', | 200 '--auto-add-overlay', |
131 | |
132 '-I', android_jar, | 201 '-I', android_jar, |
133 '-F', options.apk_path, | 202 '-F', options.apk_path, |
134 '--ignore-assets', build_utils.AAPT_IGNORE_PATTERN, | 203 '--ignore-assets', build_utils.AAPT_IGNORE_PATTERN, |
135 ] | 204 ] |
136 | 205 |
137 if options.no_compress: | 206 if options.no_compress: |
138 for ext in options.no_compress.split(','): | 207 for ext in options.no_compress.split(','): |
139 package_command += ['-0', ext] | 208 package_command += ['-0', ext] |
140 if options.shared_resources: | 209 if options.shared_resources: |
141 package_command.append('--shared-lib') | 210 package_command.append('--shared-lib') |
142 | 211 |
143 if options.asset_dir and os.path.exists(options.asset_dir): | 212 if options.asset_dir and os.path.exists(options.asset_dir): |
144 package_command += ['-A', options.asset_dir] | 213 package_command += ['-A', options.asset_dir] |
145 | 214 |
146 if options.resource_zips: | 215 if options.resource_zips: |
147 dep_zips = build_utils.ParseGypList(options.resource_zips) | 216 dep_zips = build_utils.ParseGypList(options.resource_zips) |
148 for z in dep_zips: | 217 for z in dep_zips: |
149 subdir = os.path.join(temp_dir, os.path.basename(z)) | 218 subdir = os.path.join(temp_dir, os.path.basename(z)) |
150 if os.path.exists(subdir): | 219 if os.path.exists(subdir): |
151 raise Exception('Resource zip name conflict: ' + os.path.basename(z)) | 220 raise Exception('Resource zip name conflict: ' + os.path.basename(z)) |
152 build_utils.ExtractAll(z, path=subdir) | 221 build_utils.ExtractAll(z, path=subdir) |
153 package_command += PackageArgsForExtractedZip(subdir) | 222 package_command += PackageArgsForExtractedZip(subdir) |
154 | 223 |
| 224 if options.create_density_splits: |
| 225 for config in DENSITY_SPLITS.itervalues(): |
| 226 package_command.extend(('--split', ','.join(config))) |
| 227 |
155 if 'Debug' in options.configuration_name: | 228 if 'Debug' in options.configuration_name: |
156 package_command += ['--debug-mode'] | 229 package_command += ['--debug-mode'] |
157 | 230 |
158 build_utils.CheckOutput( | 231 build_utils.CheckOutput( |
159 package_command, print_stdout=False, print_stderr=False) | 232 package_command, print_stdout=False, print_stderr=False) |
160 | 233 |
| 234 if options.create_density_splits: |
| 235 CheckDensityMissedConfigs(options.apk_path) |
| 236 RenameDensitySplits(options.apk_path) |
| 237 |
161 if options.depfile: | 238 if options.depfile: |
162 build_utils.WriteDepfile( | 239 build_utils.WriteDepfile( |
163 options.depfile, | 240 options.depfile, |
164 build_utils.GetPythonDependencies()) | 241 build_utils.GetPythonDependencies()) |
165 | 242 |
166 | 243 |
167 if __name__ == '__main__': | 244 if __name__ == '__main__': |
168 main() | 245 main() |
OLD | NEW |