load("@rules_java//java:defs.bzl", "java_binary") load("@rules_cc//cc:defs.bzl", "cc_library") load("@build_bazel_rules_android//android:rules.bzl", "android_binary") load("@google_bazel_common//tools/maven:pom_file.bzl", "pom_file") # This file is based on https://github.com/aj-michael/aar_with_jni which is # subject to the following copyright and license: # # MIT License # # Copyright (c) 2019 Adam Michael # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. def android_artifacts(name, android_library, manifest, archive_name, native_deps = [], proguard_rules = "", visibility = []): """ NOTE: The bazel android_library's implicit aar output doesn't flatten its transitive dependencies. Additionally, when using the kotlin rules, the kt_android_library rule creates a few underlying libraries which makes the declared sources and dependencies a transitive dependency on the resulting android_library. The result of this is that the classes.jar in the resulting aar will be empty. In order to workaround this issue, this rule manually constructs the aar. This macro exposes two gen rules: 1. `{name}` which outputs the aar, pom, sources.jar, javadoc.jar. 2. `{name}_aar_only` which outputs the aar. :param name The name of the underlying gen rule. :param android_library The android library target. :native_deps The native dependency targets. :proguard_rules The proguard rules used for the aar. :visibility The visibility of the underlying gen rule. """ # Create the aar _classes_jar = _create_classes_jar(name, manifest, android_library) _jni_archive = _create_jni_library(name, native_deps) _aar_output = _create_aar(name, archive_name, _classes_jar, _jni_archive, proguard_rules, visibility) # Generate other needed files for a maven publish _sources_name, _javadocs_name = _create_sources_javadocs(name, android_library) _pom_name = _create_pom_xml(name, android_library, visibility) native.genrule( name = name + "_with_artifacts", srcs = [ _aar_output, _pom_name, _sources_name + "_deploy-src.jar", _javadocs_name, ], outs = [ archive_name + ".aar", archive_name + "-pom.xml", archive_name + "-sources.jar", archive_name + "-javadoc.jar", ], visibility = visibility, cmd = """ # Set source variables set -- $(SRCS) src_aar=$$1 src_pom_xml=$$2 src_sources_jar=$$3 src_javadocs=$$4 # Set output variables set -- $(OUTS) out_aar=$$1 out_pom_xml=$$2 out_sources_jar=$$3 out_javadocs=$$4 echo "Outputting pom.xml, sources.jar, and javadocs.jar..." cp $$src_aar $$out_aar cp $$src_pom_xml $$out_pom_xml cp $$src_sources_jar $$out_sources_jar cp $$src_javadocs $$out_javadocs echo "Finished!" """, ) def _create_aar(name, archive_name, classes_jar, jni_archive, proguard_rules, visibility): """ This macro rule manually creates an aar artifact. The underlying gen rule does the following: 1. Create the final aar manifest file. 2. Unzips the apk file generated by the `jni_archive_name` into a temporary directory. 3. Renames the `lib` directory to `jni` directory since the aar requires the so files to be in the `jni` directory. 4. Copy the android binary `jar` output from the `android_binary_name` as `classes.jar`. 5. Copy the proguard rules specified in the macro parameters. 6. Override the apk's aar with a generated one. 7. Zip everything in the temporary directory into the output. :param name Name of the aar generation rule. :param archive_name Name of the resulting aar archive. :param classes_jar The classes.jar file which contains all the kotlin/java classes. :param jni_archive The apk with the desired jni libraries. :param proguard_rules The proguard.txt file. :param visibility The bazel visibility for the underlying rule. """ _aar_output = name + "_local.aar" # This is to generate the envoy mobile aar AndroidManifest.xml _manifest_name = name + "_android_manifest" native.genrule( name = _manifest_name, outs = [_manifest_name + ".xml"], cmd = "cat > $(OUTS) < /dev/null if [[ -d lib ]]; then mv lib jni else echo "No jni directory found" fi cp $$original_directory/$$src_proguard_txt ./proguard.txt cp $$original_directory/$$src_manifest_xml AndroidManifest.xml zip -r tmp.aar * > /dev/null cp tmp.aar $$original_directory/$@ """, visibility = visibility, ) return _aar_output def _create_jni_library(name, native_deps = []): """ Creates an apk containing the jni so files. :param name The name of the top level macro. :param native_deps The list of native dependency targets. """ cc_lib_name = name + "_jni_interface_lib" jni_archive_name = name + "_jni" # Create a dummy manifest file for our android_binary native.genrule( name = name + "_binary_manifest_generator", outs = [name + "_generated_AndroidManifest.xml"], cmd = """cat > $(OUTS) < /dev/null zip -r classes.jar * > /dev/null popd cp $$classes_dir/classes.jar $@ """, ) return name + "_classes.jar" def _create_sources_javadocs(name, android_library): """ Creates the sources.jar and javadocs.jar for the provided android library. This rule generates a sources jar first using a proxy java_binary's result and then uses kotlin/dokka's CLI tool to generate javadocs from the sources.jar. :param name The name of the top level macro. :param android_library The android library which to extract the sources and javadocs. """ _sources_name = name + "_android_sources_jar" _javadocs_name = name + "_android_javadocs" # This implicitly outputs {name}_deploy-src.jar which is the sources jar java_binary( name = _sources_name, runtime_deps = [android_library], ) # This takes all the source files from the source jar and creates a javadoc.jar from it native.genrule( name = _javadocs_name, srcs = [_sources_name + "_deploy-src.jar"], outs = [_javadocs_name + ".jar"], message = "Generating javadocs...", cmd = """ original_directory=$$PWD sources_dir=$$(mktemp -d) unzip $(SRCS) -d $$sources_dir > /dev/null tmp_dir=$$(mktemp -d) java -jar $(location @kotlin_dokka//jar) \ $$sources_dir \ -format javadoc \ -noStdlibLink -noJdkLink \ -output $$tmp_dir > /dev/null cd $$tmp_dir zip -r $$original_directory/$@ . > /dev/null """, tools = ["@kotlin_dokka//jar"], ) return _sources_name, _javadocs_name def _create_pom_xml(name, android_library, visibility): """ Creates a pom xml associated with the android_library target. :param name The name of the top level macro. :param android_library The android library to generate a pom xml for. """ _pom_name = name + "_pom_xml" # This is for the pom xml. It has a public visibility since this can be accessed in the root BUILD file pom_file( name = _pom_name, targets = [android_library], visibility = visibility, template_file = "@envoy_mobile//bazel:pom_template.xml", ) return _pom_name def _manifest(package_name): """ Helper function to create an appropriate manifest with a provided package name. :pram package_name The package name used in the manifest file. """ return """ """.format(package_name)