| 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 |