Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
199 changes: 140 additions & 59 deletions tools/crashlytics/defs.bzl
Original file line number Diff line number Diff line change
@@ -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 = """<?xml version="1.0" encoding="utf-8" standalone="no"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<string tools:ignore="UnusedResources,TypographyDashes" name="com.google.firebase.crashlytics.mapping_file_id" translatable="false">{build_id}</string>
</resources>"""

_CRASHLYTICS_KEEP_CONTENT = """<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="@string/com_google_firebase_crashlytics_mapping_file_id" />"""

_CRASHLYTICS_MANIFEST_TEMPLATE = """<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="{package_name}">
</manifest>
"""

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 = \
"""<?xml version=\\"1.0\\" encoding=\\"utf-8\\" standalone=\\"no\\"?>
<resources xmlns:tools=\\"http://schemas.android.com/tools\\">
<string tools:ignore=\\"UnusedResources,TypographyDashes\\" name=\\"com.google.firebase.crashlytics.mapping_file_id\\" translatable=\\"false\\">{build_id}</string>
</resources>"""
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 = \
"""<?xml version=\\"1.0\\" encoding=\\"utf-8\\"?>
<resources xmlns:tools=\\"http://schemas.android.com/tools\\"
tools:keep=\\"@string/com_google_firebase_crashlytics_mapping_file_id\\" />"""
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 = \
"""<?xml version=\\"1.0\\" encoding=\\"utf-8\\"?>
<manifest xmlns:android=\\"http://schemas.android.com/apk/res/android\\"
package=\\"{package_name}\\">
</manifest>
"""
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
)
77 changes: 44 additions & 33 deletions tools/googleservices/defs.bzl
Original file line number Diff line number Diff line change
@@ -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.
""",
)