Upload ProGuard, DexGuard, and R8 mappings, NDK symbol files and report builds to BugSnag using our Gradle plugin. (For AGP versions 5-8.)
Our Android Gradle plugin can be used to upload ProGuard, DexGuard, and R8 mappings, NDK symbol files, React Native source maps, and report builds to BugSnag.
The Android Gradle plugin will soon be deprecated in favor of a thinner Gradle wrapper of the BugSnag CLI. We recommend using either the new plugin or the CLI directly when integrating BugSnag into your builds.
If you are building your Android project from Unity, our integration documentation is here.
Add the following dependency to <project_dir>/build.gradle
or build.gradle.kts
:
buildscript {
dependencies {
// ...
classpath "com.bugsnag:bugsnag-android-gradle-plugin:8.+"
}
}
buildscript {
dependencies {
// ...
classpath("com.bugsnag:bugsnag-android-gradle-plugin:8.+")
}
}
Since v7.x of bugsnag-android-gradle-plugin
, our major version number matches the version of Android Gradle plugin that it supports. If you are using version 3.4.x - 4.x in your project, use version 5.+
of our plugin.
Apply the plugin in your module’s build file, at <project_dir>/<module_name>/build.gradle
or build.gradle.kts
:
apply plugin: "com.android.application"
apply plugin: "com.bugsnag.android.gradle"
apply(plugin = "com.android.application")
apply(plugin = "com.bugsnag.android.gradle")
By default the BugSnag plugin is disabled for debug build variants (specifically, any build variant with “debug” in the name). To improve your project’s build performance you should disable the plugin for any project-specific build variants that do not require deobfuscated stack traces in BugSnag. This can be achieved by providing your own variant filter in your module’s build.gradle
or build.gradle.kts
file:
bugsnag {
variantFilter { variant ->
// disables plugin for all variants of the 'staging' productFlavor
def name = variant.name.toLowerCase()
if (name.contains("staging") || name.contains("debug")) {
enabled = false
}
}
}
bugsnag {
variantFilter {
// disables plugin for all variants of the 'staging' productFlavor
val name = it.name.toLowerCase()
if (name.contains("staging") || name.contains("debug")) {
it.enabled = false
}
}
}
Finally, ensure your API key is present in the <application>
section of your AndroidManifest.xml
:
<application ...>
<meta-data android:name="com.bugsnag.android.API_KEY"
android:value="your-api-key-here"/>
</application>
You can find your API key in Project Settings from your BugSnag dashboard.
If you are using DexGuard you must add the following to your project’s keep rules:
-keepresourcexmlelements AndroidManifest.xml
This prevents DexGuard from obfuscating a meta-data element that BugSnag uses to identify the correct mapping file for each artefact.
By default the plugin automatically uploads ProGuard, DexGuard, R8, NDK, and Unity library mapping files for each build variant. BugSnag also reports build metadata such as version and source control information that is used to link to source code from the dashboard.
The plugin only supports uploading mapping files from application modules.
You can disable automatic upload via the bugsnag
extension:
bugsnag {
uploadJvmMappings = false // disables upload of ProGuard/DexGuard/R8 mapping files
uploadNdkMappings = false // disables upload of NDK mapping files
uploadNdkUnityLibraryMappings = false // disables upload of Unity library mapping files
reportBuilds = false // disables upload of build metadata
}
bugsnag {
uploadJvmMappings = false // disables upload of ProGuard/DexGuard/R8 mapping files
uploadNdkMappings = false // disables upload of NDK mapping files
uploadNdkUnityLibraryMappings = false // disables upload of Unity library mapping files
reportBuilds = false // disables upload of build metadata
}
Automatic upload of JS sourcemaps for React Native projects can also be enabled via the bugsnag
extension:
bugsnag {
uploadReactNativeMappings = true // enables upload of React Native source maps
}
bugsnag {
uploadReactNativeMappings = true // enables upload of React Native source maps
}
BugSnag has introduced a new symbolication mechanism for NDK symbols. This new mechanism fixes a number of bugs and we recommend switching to it. Also, if your build uses NDK r23 or higher then you can only use the new mechanism, due to changes in the toolchain.
To opt-in to the new mechanism, use the following configuration:
bugsnag {
useLegacyNdkSymbolUpload = false
}
bugsnag {
useLegacyNdkSymbolUpload = false
}
If switching an existing project to the new mechanism, some stack frames may symbolicate differently than they did with the old mechanism, resulting in new error groups. This should only affect stack frames that the old mechanism was unable to symbolicate.
To use the new mechanism you will need:
a compatible version of the BugSnag library in your app:
to be using the BugSnag upload endpoints or a recent version of On-premise (v3.2211.0+ single machine or v5.2211.0+ of clustered)
to build using v7.x of the Android Gradle plugin and BugSnag Android Gradle plugin v7.4.0+ (see above)
It is possible to disable automatic upload if you wish to perform custom logic before uploading mapping files, such as running pre-release checks on an APK. In this scenario you can invoke upload tasks manually:
./gradlew uploadBugsnag${variantOutputName}Mapping # uploads JVM mapping files for a build variant
./gradlew uploadBugsnagNdk${variantOutputName}Mapping # uploads NDK mapping files for a build variant
./gradlew uploadBugsnag${variantOutputName}SourceMaps # uploads React Native source maps for a build variant
./gradlew bugsnagRelease${variantOutputName}Mapping # uploads build metadata for a build variant
For example, the following command would upload the release JVM mapping file for the x86
split of the javaExample
productFlavor in the example
module:
./gradlew :example:uploadBugsnagJavaExample-x86-releaseMapping
If you are using BugSnag On-premise you should alter the Upload API and Build API endpoints.
bugsnag {
endpoint = "https://upload.bugsnag.example.com" // configures the Upload API endpoint
releasesEndpoint = "https://bugsnag-build.example.com" // configures the Build API endpoint
}
bugsnag {
endpoint = "https://upload.bugsnag.example.com" // configures the Upload API endpoint
releasesEndpoint = "https://bugsnag-build.example.com" // configures the Build API endpoint
}
For further options see advanced configuration.
If you use BugSnag functions in your native (NDK) code, e.g. bugsnag_leave_breadcrumb
or bugsnag_notify
, you will need to have the BugSnag NDK library and header files available to your native build system to link against.
With v6 of the BugSnag Android SDK, this is provided using Prefab (see our Native API configuration guide for instructions). However for users of older SDKs, you will need to extract the libbugsnag-ndk.so
and header files from our NDK package. This is done automatically if you have our Android Gradle plugin installed.
To enable retrying the file upload, set the retryCount
property:
bugsnag {
retryCount = 5
}
bugsnag {
retryCount = 5
}
To alter the timeout of HTTP requests, set the requestTimeoutMs
property:
bugsnag {
requestTimeoutMs = 5000L
}
bugsnag {
requestTimeoutMs = 5000L
}
By default, requests timeout after 60000 milliseconds.
In NDK stacktraces the project’s root directory is used to highlight in-project stack frames and improves grouping. If you want code outside of your project root to be considered in-project, set the projectRoot
property:
bugsnag {
projectRoot = "/Users/joebloggs/my-app"
}
bugsnag {
projectRoot = "/Users/joebloggs/my-app"
}
The plugin will automatically upload mapping files for shared objects in the default Android build directory. If you have additional shared object files in non-standard build directories, mapping files can be uploaded by adding them to the sharedObjectPaths
property:
def paths = [
new File("app/build/jni/libs"),
new File("app/build/someOtherFolder")
]
bugsnag {
sharedObjectPaths = paths
}
val paths = listOf(
File("app/build/jni/libs"),
File("app/build/someOtherFolder")
)
bugsnag {
sharedObjectPaths = paths
}
objdump
pathsThe objdump
command is used to generate symbol mappings for NDK when the legacy upload behavior is enabled.
In recent versions of the NDK (v23.0.7599858+) this command has been removed and so the BugSnag upload endpoint now accepts .so
files stripped of executable code using the objcopy
NDK command as well. We recommend you use this new mechanism when possible — see Basic Configuration for details for opting-in to it.
If objdump
is used, by default the plugin will automatically calculate the paths of the executable and no additional configuration is needed. If necessary, the path can be overridden on a per ABI basis:
bugsnag {
objdumpPaths = [
"armeabi": "/custom-location/ndk-bundle/armeabi-objdump",
"armeabi-v7a": "/custom-location/ndk-bundle/armeabi-v7a-objdump",
"arm64-v8a": "/custom-location/ndk-bundle/arm64-v8a-objdump",
"x86": "/custom-location/ndk-bundle/x86-objdump",
"x86_64": "/custom-location/ndk-bundle/x86_64-objdump",
]
}
bugsnag {
objdumpPaths = mapOf(
"armeabi" to "/custom-location/ndk-bundle/armeabi-objdump",
"armeabi-v7a" to "/custom-location/ndk-bundle/armeabi-v7a-objdump",
"arm64-v8a" to "/custom-location/ndk-bundle/arm64-v8a-objdump",
"x86" to "/custom-location/ndk-bundle/x86-objdump",
"x86_64" to "/custom-location/ndk-bundle/x86_64-objdump"
)
}
failOnUploadError
stops the build when a mapping file fails to upload to BugSnag successfully. By default, this value is set to true. If you wish to disable this behaviour, you should set the flag to false:
bugsnag {
failOnUploadError = false
}
bugsnag {
failOnUploadError = false
}
To overwrite when there is an existing mapping file, you can set the overwrite
property as follows:
bugsnag {
overwrite = true
}
bugsnag {
overwrite = true
}
If you upload React Native source maps and your node_modules
are installed in a non-default directory, you should set the nodeModulesDir
property as follows:
bugsnag {
// for a path relative to this `build.gradle` file
nodeModulesDir = file("../../../path/to/node_modules")
// or, for an absolute path
nodeModulesDir = new File("/absolute/custom/path/node_modules")
}
bugsnag {
// for a path relative to this `build.gradle.kts` file
nodeModulesDir = file("../../../path/to/node_modules")
// or, for an absolute path
nodeModulesDir = File("/absolute/custom/path/node_modules")
}
During a build, the bugsnag-plugin-android-ndk
plugin package is extracted to allow projects that use it to link against the native libraries. This can be disabled if your project does not have native code that uses our NDK plugin:
bugsnag {
enableNdkLinkage = false
}
bugsnag {
enableNdkLinkage = false
}
Due to changes in AGP v8 and limitations in the latest API, this task will break configuration caching if enabled. Therefore if you don’t use the bugsnag-plugin-android-ndk
plugin, or have an alternative means of linking against it in your build, you can disable it to avoid the “Configuration was resolved at configuration time” warnings that result.
Set the name of the person or entity who built the app (defaults to whoami
):
bugsnag {
builderName = "Joe Bloggs"
}
bugsnag {
builderName = "Joe Bloggs"
}
Source control values are automatically detected if Git is installed. If you want to override them you can set the following values:
Config | Type | Description |
---|---|---|
provider |
String |
The source control provider. This will be automatically detected from the repository URL where possible. If your provider is on-premise it can be set to one of ‘github-enterprise’, ‘bitbucket-server’ or ‘gitlab-onpremise’ |
repository |
String |
The repository URL. |
revision |
String |
The commit hash of the code used to generate this build. |
bugsnag {
sourceControl {
provider = "github-enterprise"
repository = "https://github.com/org/repo"
revision = "abcdef1"
}
}
bugsnag {
sourceControl {
provider = "github-enterprise"
repository = "https://github.com/org/repo"
revision = "abcdef1"
}
}
Set any metadata associated with the build that is useful to see against releases in BugSnag. By default, Java, Gradle, and other data are captured, using the following keys:
"os_arch"
"os_name"
"os_version"
"java_version"
"gradle_version"
"git_version"
Additional metadata can be added via the metadata property:
bugsnag {
def map = new HashMap()
map.put("MyKey", "MyValue")
metadata = map
}
bugsnag {
val map = hashMapOf()
map["MyKey"] = "MyValue"
metadata = map
}
This will be added in addition to the default data. If you wish to override a default value, you can add a different value for its key in the Map:
bugsnag {
def map = new HashMap()
map.put("java_version", "[REDACTED]")
metadata = map
}
bugsnag {
val map = hashMapOf()
map["java_version"] = "[REDACTED]"
metadata = map
}
To use a proxy you should configure the JVM’s networking properties in the gradle.properties
file of your project:
systemProp.http.proxyHost=www.example.com
systemProp.http.proxyPort=8080
systemProp.http.proxyUser=my-user
systemProp.http.proxyPassword=my-password
systemProp.http.nonProxyHosts=*.example.com
After configuring this the plugin will route all its traffic through the proxy.
The plugin can be set up to use different configuration values for different build variants, by using manifest placeholders in your app’s build.gradle
or build.gradle.kts
script.
android {
defaultConfig {
manifestPlaceholders = [
bugsnagApiKey: "your-api-key-here"
]
}
productFlavors {
pro {
manifestPlaceholders = [
// override defaultConfig values here
bugsnagApiKey: "your-api-key-here"
]
}
}
}
android {
defaultConfig {
manifestPlaceholders = mapOf(
"bugsnagApiKey" to "your-api-key-here"
)
}
productFlavors {
create("pro") {
manifestPlaceholders = mapOf(
// override defaultConfig values here
"bugsnagApiKey" to "your-api-key-here"
)
}
}
}
You will also need to update the meta-data element at the bottom of your app manifest file (AndroidManifest.xml
) accordingly:
<application>
<meta-data android:name="com.bugsnag.android.API_KEY" android:value="${bugsnagApiKey}"/>
</application>
Some users have reported that the BugSnag Android Gradle Plugin can throw a NoSuchMethodError
:
Execution failed for task ':app:processBugsnagReleaseManifest'.
> okio.Okio.sink$default(Ljava/io/File;ZILjava/lang/Object;)Lokio/Sink;
This occurs when your project adds another gradle plugin to your buildscript classpath that itself has a dependency on a different version of the Okio library.
To resolve this issue (and any similar version mismatches), you should follow Gradle’s guide on altering the versions of transitive dependencies.