Android Gradle plugin

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.

  • Upload JVM mappings (ProGuard, DexGuard, or R8), NDK shared object mappings, and source maps (for React Native).
  • Report information when you deploy your app to enable linking to code in your source control provider from the releases dashboard, timeline annotations, and stack traces.
  • Extract the BugSnag NDK .so library and header files for linking against when using our NDK API in your apps.

If you are building your Android project from Unity, our integration documentation is here.

Installation

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.

DexGuard

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.

Basic configuration

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
}

NDK symbol files

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)

Manual upload

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

Endpoint configuration

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.

NDK API linkage

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.

Additional configuration

Advanced mapping upload configuration

Retrying the file upload

To enable retrying the file upload, set the retryCount property:

bugsnag {
    retryCount = 5
}
bugsnag {
    retryCount = 5
}

Altering the HTTP request timeout

To alter the timeout of HTTP requests, set the requestTimeoutMs property:

bugsnag {
    requestTimeoutMs = 5000L
}
bugsnag {
    requestTimeoutMs = 5000L
}

By default, requests timeout after 60000 milliseconds.

Project root

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"
}

Shared object paths

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 paths

The 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"
    )
}

Fail On Upload Error

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
}

Overwrite mapping file

To overwrite when there is an existing mapping file, you can set the overwrite property as follows:

bugsnag {
    overwrite = true
}
bugsnag {
    overwrite = true
}

Custom node_modules directory

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")
}

Enable NDK linkage

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.

Advanced build reporting configuration

Builder

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

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"
    }
}

Metadata

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
}

Configuring a HTTP Proxy

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.

Manifest placeholders

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>

FAQ

BugSnag Android Gradle Plugin throws a NoSuchMethodError

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.