diff --git a/tools/crashlytics/defs.bzl b/tools/crashlytics/defs.bzl
index 482acb6..1ac1e1b 100644
--- a/tools/crashlytics/defs.bzl
+++ b/tools/crashlytics/defs.bzl
@@ -1,73 +1,154 @@
+load("//tools/googleservices:defs.bzl", "google_services_xml")
load("@rules_android//android:rules.bzl", "android_library")
-def crashlytics_android_library(name, package_name, build_id, resource_files):
- _CRASHLYTICS_PROP_TEMPLATE = \
- """build_id={build_id}
+_CRASHLYTICS_PROP_TEMPLATE = """build_id={build_id}
package_name={package_name}"""
- crashlytics_properties_file = "_%s_crashlytics/assets/crashlytics-build.properties" % name
- crashlytics_properties_file_content = _CRASHLYTICS_PROP_TEMPLATE.format(
+
+_CRASHLYTICS_RES_TEMPLATE = """
+
+ {build_id}
+"""
+
+_CRASHLYTICS_KEEP_CONTENT = """
+"""
+
+_CRASHLYTICS_MANIFEST_TEMPLATE = """
+
+
+"""
+
+def _crashlytics_android_impl(ctx):
+ package_name = ctx.attr.package_name
+ # Expand make variables in build_id
+ build_id = ctx.expand_make_variables("build_id", ctx.attr.build_id, {})
+
+ properties_file = ctx.outputs.properties
+ res_values_file = ctx.outputs.res_values
+ res_keep_file = ctx.outputs.res_keep
+ manifest_file = ctx.outputs.manifest
+
+ # Generate crashlytics-build.properties
+ properties_content = _CRASHLYTICS_PROP_TEMPLATE.format(
build_id = build_id,
package_name = package_name,
)
-
- native.genrule(
- name = "%s_crashlytics_setup_properties" % name,
- outs = [crashlytics_properties_file],
- tools = ["@tools_android//tools/crashlytics"],
- cmd = "$(location @tools_android//tools/crashlytics) \"%s\" $@" % crashlytics_properties_file_content,
+ ctx.actions.write(
+ output = properties_file,
+ content = properties_content,
+ is_executable = False,
)
- # Generate the unique identifier for Fabric backend to identify builds.
- # https://docs.fabric.io/android/crashlytics/build-tools.html#optimize-builds-when-you-re-not-proguarding-or-using-beta-by-crashlytics
- _CRASHLYTICS_RES_TEMPLATE = \
- """
-
- {build_id}
-"""
- crashlytics_res_values_file = "_%s_crashlytics/res/values/com_crashlytics_build_id.xml" % name
- crashlytics_res_values_file_content = _CRASHLYTICS_RES_TEMPLATE.format(build_id = build_id)
-
- native.genrule(
- name = "%s_crashlytics_setup_res" % name,
- outs = [crashlytics_res_values_file],
- tools = ["@tools_android//tools/crashlytics"],
- cmd = "$(location @tools_android//tools/crashlytics) \"%s\" $@" % crashlytics_res_values_file_content,
+ # Generate build ID resource XML
+ res_values_content = _CRASHLYTICS_RES_TEMPLATE.format(build_id = build_id)
+ ctx.actions.write(
+ output = res_values_file,
+ content = res_values_content,
+ is_executable = False,
)
- _CRASHLYTICS_KEEP_CONTENT = \
- """
-"""
- crashlytics_res_keep_file = "_%s_crashlytics/res/raw/%s_crashlytics.keep.xml" % (name, package_name)
-
- native.genrule(
- name = "%s_crashlytics_setup_res_keep" % name,
- outs = [crashlytics_res_keep_file],
- tools = ["@tools_android//tools/crashlytics"],
- cmd = "$(location @tools_android//tools/crashlytics) \"%s\" $@" % _CRASHLYTICS_KEEP_CONTENT,
+ # Generate keep XML
+ ctx.actions.write(
+ output = res_keep_file,
+ content = _CRASHLYTICS_KEEP_CONTENT,
+ is_executable = False,
)
- _CRASHLYTICS_MANIFEST_TEMPLATE = \
-"""
-
-
-"""
- crashlytics_manifest_file = "_%s_crashlytics/CrashlyticsManifest.xml" % name
- crashlytics_manifest_file_content = _CRASHLYTICS_MANIFEST_TEMPLATE.format(package_name = package_name)
-
- native.genrule(
- name = "%s_crashlytics_setup_manifest" % name,
- outs = [crashlytics_manifest_file],
- tools = ["@tools_android//tools/crashlytics"],
- cmd = "$(location @tools_android//tools/crashlytics) \"%s\" $@" % crashlytics_manifest_file_content,
+ # Generate manifest
+ manifest_content = _CRASHLYTICS_MANIFEST_TEMPLATE.format(package_name = package_name)
+ ctx.actions.write(
+ output = manifest_file,
+ content = manifest_content,
+ is_executable = False,
)
- android_library(
- name = name,
- assets = [crashlytics_properties_file],
- assets_dir = "_%s_crashlytics/assets" % name,
- custom_package = package_name,
- manifest = crashlytics_manifest_file,
- resource_files = [crashlytics_res_values_file, crashlytics_res_keep_file] + resource_files,
- )
+ # Collect all resource files
+ all_resource_files = [res_values_file, res_keep_file] + ctx.files.resource_files
+
+ return [
+ DefaultInfo(files = depset([
+ properties_file,
+ manifest_file,
+ ] + all_resource_files)),
+ OutputGroupInfo(
+ assets = depset([properties_file]),
+ manifest = depset([manifest_file]),
+ resources = depset(all_resource_files),
+ ),
+ ]
+
+crashlytics_android = rule(
+ implementation = _crashlytics_android_impl,
+ attrs = {
+ "package_name": attr.string(
+ mandatory = True,
+ doc = "The package name (or application ID) of the Android app.",
+ ),
+ "build_id": attr.string(
+ mandatory = True,
+ doc = "The build ID for Crashlytics. Supports make variable expansion like $(crashlyticsBuildID).",
+ ),
+ "resource_files": attr.label_list(
+ allow_files = True,
+ doc = "Additional resource files to include.",
+ ),
+ "_generator": attr.label(
+ default = "@tools_android//tools/crashlytics",
+ executable = True,
+ cfg = "exec",
+ ),
+ },
+ outputs = {
+ "properties": "%{name}_crashlytics/assets/crashlytics-build.properties",
+ "res_values": "%{name}_crashlytics/res/values/com_crashlytics_build_id.xml",
+ "res_keep": "%{name}_crashlytics/res/raw/%{name}_crashlytics_keep.xml",
+ "manifest": "%{name}_crashlytics/CrashlyticsManifest.xml",
+ },
+ doc = """Generates Crashlytics configuration files.
+
+ Generates the unique identifier for Fabric backend to identify builds.
+ See: https://docs.fabric.io/android/crashlytics/build-tools.html
+ """,
+)
+
+def crashlytics_android_library(name, package_name, build_id, google_services_json, **kwargs):
+ """Creates an Android library with Crashlytics and Google Services configuration.
+
+ Args:
+ name: Name of the android_library target.
+ package_name: The package name (or application ID) of the Android app.
+ Supports select() statements.
+ build_id: The build ID for Crashlytics.
+ google_services_json: The google-services.json file.
+ **kwargs: Additional arguments to pass to android_library.
+ """
+ gsx_name = name + "_google_services_xml"
+ gen_name = name + "_gen"
+
+ google_services_xml(
+ name = gsx_name,
+ package_name = package_name,
+ google_services_json = google_services_json,
+ )
+
+ crashlytics_android(
+ name = gen_name,
+ package_name = package_name,
+ build_id = build_id,
+ resource_files = [":%s" % gsx_name],
+ )
+
+ android_library(
+ name = name,
+ assets = [":%s_crashlytics/assets/crashlytics-build.properties" % gen_name],
+ assets_dir = "%s_crashlytics/assets" % gen_name,
+ custom_package = package_name,
+ manifest = ":%s_crashlytics/CrashlyticsManifest.xml" % gen_name,
+ resource_files = [
+ ":%s_crashlytics/res/values/com_crashlytics_build_id.xml" % gen_name,
+ ":%s_crashlytics/res/raw/%s_crashlytics_keep.xml" % (gen_name, gen_name),
+ ":%s" % gsx_name,
+ ],
+ **kwargs
+ )
diff --git a/tools/googleservices/defs.bzl b/tools/googleservices/defs.bzl
index df96456..c5d071a 100644
--- a/tools/googleservices/defs.bzl
+++ b/tools/googleservices/defs.bzl
@@ -1,39 +1,50 @@
-"""Macros to support Google services, e.g. Firebase Cloud Messaging."""
+"""Rules to support Google services, e.g. Firebase Cloud Messaging."""
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
load("@bazel_tools//tools/build_defs/repo:jvm.bzl", "jvm_maven_import_external")
+def _google_services_xml_impl(ctx):
+ package_name = ctx.attr.package_name
+ google_services_json = ctx.file.google_services_json
-def google_services_xml(package_name, google_services_json):
- """Creates Android resource XML for Google services.
-
- The XML is based on a google-services.json file.
-
- This macro assumes that the Android tools repository is named "tools_android"
- in the top-level project's WORKSPACE file.
-
- Args:
- package_name: The package name (or application ID) of the Android app.
- google_services_json: The google-services.json file.
-
- Returns:
- A list of the generated resource files which can be used with
- android_binary.resource_files or android_library.resource_files.
- """
- # Adding the package name and google-services.json file to the outs and name
- # of the rule is necessary in case there are multiple calls to
- # google_services_xml() with different package names or different json files.
- outs = ["google_services_xml/%s/%s/res/values/values.xml" %
- (package_name, google_services_json.replace("/", "_"))]
- name = "gen_google_services_xml_%s_%s" % (
- package_name.replace(".", "_"),
- google_services_json.replace(".", "_").replace("/", "_"))
- if not native.existing_rule(name):
- native.genrule(
- name = name,
- srcs = [google_services_json],
- outs = outs,
- tools = ["@tools_android//third_party/googleservices:GenerateGoogleServicesXml"],
- cmd = "$(location @tools_android//third_party/googleservices:GenerateGoogleServicesXml) %s $< $@" % package_name,
+ output = ctx.actions.declare_file(
+ "google_services_xml/%s/%s/res/values/values.xml" % (
+ package_name,
+ google_services_json.path.replace("/", "_")))
+
+ ctx.actions.run(
+ outputs = [output],
+ inputs = [google_services_json],
+ executable = ctx.executable._generator,
+ arguments = [package_name, google_services_json.path, output.path],
+ mnemonic = "GenerateGoogleServicesXml",
)
- return outs
+
+ return [DefaultInfo(files = depset([output]))]
+
+google_services_xml = rule(
+ implementation = _google_services_xml_impl,
+ attrs = {
+ "package_name": attr.string(
+ mandatory = True,
+ doc = "The package name (or application ID) of the Android app.",
+ ),
+ "google_services_json": attr.label(
+ mandatory = True,
+ allow_single_file = [".json"],
+ doc = "The google-services.json file.",
+ ),
+ "_generator": attr.label(
+ default = "@tools_android//third_party/googleservices:GenerateGoogleServicesXml",
+ executable = True,
+ cfg = "exec",
+ ),
+ },
+ doc = """Creates Android resource XML for Google services.
+
+ The XML is based on a google-services.json file.
+
+ This rule assumes that the Android tools repository is named "tools_android"
+ in the top-level project's WORKSPACE file.
+ """,
+)