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
5 # found in the LICENSE file.
7 # pylint: disable=C0301
8 """Package resources into an apk.
10 See https://android.googlesource.com/platform/tools/base/+/master/legacy/ant-tasks/src/main/java/com/android/ant/AaptExecTask.java
12 https://android.googlesource.com/platform/sdk/+/master/files/ant/build.xml
14 # pylint: enable=C0301
20 from util import build_utils
23 """Parses command line options.
26 An options object as from optparse.OptionsParser.parse_args()
28 parser = optparse.OptionParser()
29 build_utils.AddDepfileOption(parser)
30 parser.add_option('--android-sdk', help='path to the Android SDK folder')
31 parser.add_option('--android-sdk-tools',
32 help='path to the Android SDK build tools folder')
34 parser.add_option('--configuration-name',
35 help='Gyp\'s configuration name (Debug or Release).')
37 parser.add_option('--android-manifest', help='AndroidManifest.xml path')
38 parser.add_option('--version-code', help='Version code for apk.')
39 parser.add_option('--version-name', help='Version name for apk.')
40 parser.add_option('--resource-zips',
41 help='zip files containing resources to be packaged')
42 parser.add_option('--asset-dir',
43 help='directories containing assets to be packaged')
44 parser.add_option('--no-compress', help='disables compression for the '
45 'given comma separated list of extensions')
47 parser.add_option('--apk-path',
48 help='Path to output (partial) apk.')
50 (options, args) = parser.parse_args()
53 parser.error('No positional arguments should be given.')
55 # Check that required options have been provided.
56 required_options = ('android_sdk', 'android_sdk_tools', 'configuration_name',
57 'android_manifest', 'version_code', 'version_name',
58 'resource_zips', 'asset_dir', 'apk_path')
60 build_utils.CheckOptions(options, parser, required=required_options)
65 def MoveImagesToNonMdpiFolders(res_root):
66 """Move images from drawable-*-mdpi-* folders to drawable-* folders.
68 Why? http://crbug.com/289843
70 for src_dir_name in os.listdir(res_root):
71 src_components = src_dir_name.split('-')
72 if src_components[0] != 'drawable' or 'mdpi' not in src_components:
74 src_dir = os.path.join(res_root, src_dir_name)
75 if not os.path.isdir(src_dir):
77 dst_components = [c for c in src_components if c != 'mdpi']
78 assert dst_components != src_components
79 dst_dir_name = '-'.join(dst_components)
80 dst_dir = os.path.join(res_root, dst_dir_name)
81 build_utils.MakeDirectory(dst_dir)
82 for src_file_name in os.listdir(src_dir):
83 if not src_file_name.endswith('.png'):
85 src_file = os.path.join(src_dir, src_file_name)
86 dst_file = os.path.join(dst_dir, src_file_name)
87 assert not os.path.lexists(dst_file)
88 shutil.move(src_file, dst_file)
91 def PackageArgsForExtractedZip(d):
92 """Returns the aapt args for an extracted resources zip.
94 A resources zip either contains the resources for a single target or for
95 multiple targets. If it is multiple targets merged into one, the actual
96 resource directories will be contained in the subdirectories 0, 1, 2, ...
99 subdirs = [os.path.join(d, s) for s in os.listdir(d)]
100 subdirs = sorted([s for s in subdirs if os.path.isdir(s)])
101 if subdirs and os.path.basename(subdirs[0]) == '0':
107 MoveImagesToNonMdpiFolders(d)
108 package_command += ['-S', d]
109 return package_command
113 options = ParseArgs()
114 android_jar = os.path.join(options.android_sdk, 'android.jar')
115 aapt = os.path.join(options.android_sdk_tools, 'aapt')
117 with build_utils.TempDir() as temp_dir:
118 package_command = [aapt,
120 '--version-code', options.version_code,
121 '--version-name', options.version_name,
122 '-M', options.android_manifest,
125 '--auto-add-overlay',
128 '-F', options.apk_path,
131 if options.no_compress:
132 for ext in options.no_compress.split(','):
133 package_command += ['-0', ext]
135 if os.path.exists(options.asset_dir):
136 package_command += ['-A', options.asset_dir]
138 dep_zips = build_utils.ParseGypList(options.resource_zips)
140 subdir = os.path.join(temp_dir, os.path.basename(z))
141 if os.path.exists(subdir):
142 raise Exception('Resource zip name conflict: ' + os.path.basename(z))
143 build_utils.ExtractAll(z, path=subdir)
144 package_command += PackageArgsForExtractedZip(subdir)
146 if 'Debug' in options.configuration_name:
147 package_command += ['--debug-mode']
149 build_utils.CheckOutput(
150 package_command, print_stdout=False, print_stderr=False)
153 build_utils.WriteDepfile(
155 build_utils.GetPythonDependencies())
158 if __name__ == '__main__':