| # pylint: disable=g-direct-third-party-import | |
| # Copyright 2015 The Bazel Authors. All rights reserved. | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| """Stubifies an AndroidManifest.xml. | |
| Does the following things: | |
| - Replaces the Application class in an Android manifest with a stub one | |
| - Resolve string and integer resources to their default values | |
| usage: %s [input manifest] [output manifest] [file for old application class] | |
| Writes the old application class into the file designated by the third argument. | |
| """ | |
| import sys | |
| from xml.etree import ElementTree | |
| from third_party.py import gflags | |
| gflags.DEFINE_string("main_manifest", None, "The main manifest of the app") | |
| gflags.DEFINE_string("split_manifest", None, "The output manifest") | |
| gflags.DEFINE_string("override_package", None, | |
| "The Android package. Override the one specified in the " | |
| "input manifest") | |
| gflags.DEFINE_string("split", None, "The name of the split") | |
| gflags.DEFINE_boolean("hascode", False, "Whether this split .apk has dexes") | |
| FLAGS = gflags.FLAGS | |
| MANIFEST_TEMPLATE = """<?xml version="1.0" encoding="utf-8"?> | |
| <manifest | |
| xmlns:android="http://schemas.android.com/apk/res/android" | |
| %(version_code_attribute)s | |
| %(version_name_attribute)s | |
| package="%(package)s" | |
| split="%(split)s"> | |
| <application android:hasCode="%(hascode)s"> | |
| </application> | |
| </manifest> | |
| """ | |
| def BuildSplitManifest(main_manifest, override_package, split, hascode): | |
| """Builds a split manifest based on the manifest of the main APK. | |
| Args: | |
| main_manifest: the XML manifest of the main APK as a string | |
| override_package: if not None, override the package in the main manifest | |
| split: the name of the split as a string | |
| hascode: if this split APK will contain .dex files | |
| Returns: | |
| The XML split manifest as a string | |
| Raises: | |
| Exception if something goes wrong. | |
| """ | |
| manifest = ElementTree.fromstring(main_manifest) | |
| android_namespace_prefix = "{http://schemas.android.com/apk/res/android}" | |
| if override_package: | |
| package = override_package | |
| else: | |
| package = manifest.get("package") | |
| version_code = manifest.get(android_namespace_prefix + "versionCode") | |
| version_name = manifest.get(android_namespace_prefix + "versionName") | |
| return MANIFEST_TEMPLATE % { | |
| "version_code_attribute": | |
| 'android:versionCode="%s"' % version_code if version_code else "", | |
| "version_name_attribute": | |
| 'android:versionName="%s"' % version_name if version_name else "", | |
| "package": package, | |
| "split": split, | |
| "hascode": str(hascode).lower() | |
| } | |
| def main(): | |
| split_manifest = BuildSplitManifest( | |
| open(FLAGS.main_manifest, "rb").read(), FLAGS.override_package, | |
| FLAGS.split, FLAGS.hascode) | |
| with open(FLAGS.split_manifest, "wb") as output_xml: | |
| output_xml.write(split_manifest) | |
| if __name__ == "__main__": | |
| FLAGS(sys.argv) | |
| main() |