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.')
43 help='Make a resource package that can be loaded by a different'
44 'application at runtime to access the package\'s resources.')
45 parser
.add_option('--resource-zips',
46 help='zip files containing resources to be packaged')
47 parser
.add_option('--asset-dir',
48 help='directories containing assets to be packaged')
49 parser
.add_option('--no-compress', help='disables compression for the '
50 'given comma separated list of extensions')
52 parser
.add_option('--apk-path',
53 help='Path to output (partial) apk.')
55 (options
, args
) = parser
.parse_args()
58 parser
.error('No positional arguments should be given.')
60 # Check that required options have been provided.
61 required_options
= ('android_sdk', 'android_sdk_tools', 'configuration_name',
62 'android_manifest', 'version_code', 'version_name',
63 'resource_zips', 'asset_dir', 'apk_path')
65 build_utils
.CheckOptions(options
, parser
, required
=required_options
)
70 def MoveImagesToNonMdpiFolders(res_root
):
71 """Move images from drawable-*-mdpi-* folders to drawable-* folders.
73 Why? http://crbug.com/289843
75 for src_dir_name
in os
.listdir(res_root
):
76 src_components
= src_dir_name
.split('-')
77 if src_components
[0] != 'drawable' or 'mdpi' not in src_components
:
79 src_dir
= os
.path
.join(res_root
, src_dir_name
)
80 if not os
.path
.isdir(src_dir
):
82 dst_components
= [c
for c
in src_components
if c
!= 'mdpi']
83 assert dst_components
!= src_components
84 dst_dir_name
= '-'.join(dst_components
)
85 dst_dir
= os
.path
.join(res_root
, dst_dir_name
)
86 build_utils
.MakeDirectory(dst_dir
)
87 for src_file_name
in os
.listdir(src_dir
):
88 if not src_file_name
.endswith('.png'):
90 src_file
= os
.path
.join(src_dir
, src_file_name
)
91 dst_file
= os
.path
.join(dst_dir
, src_file_name
)
92 assert not os
.path
.lexists(dst_file
)
93 shutil
.move(src_file
, dst_file
)
96 def PackageArgsForExtractedZip(d
):
97 """Returns the aapt args for an extracted resources zip.
99 A resources zip either contains the resources for a single target or for
100 multiple targets. If it is multiple targets merged into one, the actual
101 resource directories will be contained in the subdirectories 0, 1, 2, ...
103 subdirs
= [os
.path
.join(d
, s
) for s
in os
.listdir(d
)]
104 subdirs
= [s
for s
in subdirs
if os
.path
.isdir(s
)]
105 is_multi
= '0' in [os
.path
.basename(s
) for s
in subdirs
]
107 res_dirs
= sorted(subdirs
, key
=lambda p
: int(os
.path
.basename(p
)))
112 MoveImagesToNonMdpiFolders(d
)
113 package_command
+= ['-S', d
]
114 return package_command
118 options
= ParseArgs()
119 android_jar
= os
.path
.join(options
.android_sdk
, 'android.jar')
120 aapt
= os
.path
.join(options
.android_sdk_tools
, 'aapt')
122 with build_utils
.TempDir() as temp_dir
:
123 package_command
= [aapt
,
125 '--version-code', options
.version_code
,
126 '--version-name', options
.version_name
,
127 '-M', options
.android_manifest
,
130 '--auto-add-overlay',
133 '-F', options
.apk_path
,
134 '--ignore-assets', build_utils
.AAPT_IGNORE_PATTERN
,
137 if options
.no_compress
:
138 for ext
in options
.no_compress
.split(','):
139 package_command
+= ['-0', ext
]
140 if options
.shared_resources
:
141 package_command
.append('--shared-lib')
143 if os
.path
.exists(options
.asset_dir
):
144 package_command
+= ['-A', options
.asset_dir
]
146 dep_zips
= build_utils
.ParseGypList(options
.resource_zips
)
148 subdir
= os
.path
.join(temp_dir
, os
.path
.basename(z
))
149 if os
.path
.exists(subdir
):
150 raise Exception('Resource zip name conflict: ' + os
.path
.basename(z
))
151 build_utils
.ExtractAll(z
, path
=subdir
)
152 package_command
+= PackageArgsForExtractedZip(subdir
)
154 if 'Debug' in options
.configuration_name
:
155 package_command
+= ['--debug-mode']
157 build_utils
.CheckOutput(
158 package_command
, print_stdout
=False, print_stderr
=False)
161 build_utils
.WriteDepfile(
163 build_utils
.GetPythonDependencies())
166 if __name__
== '__main__':