Migrating an Android App from the TestFairy SDK
Beta release
The Sauce Mobile Beta SDK is in beta. The artifact names and the API are final; this documentation can still change. Share feedback with your Sauce Labs representative.
Follow these steps to move an Android app from the TestFairy SDK 1.x to the Sauce Mobile Beta SDK 2.3.0. Read Migrating from the TestFairy SDK first for what changes and why. For the full install reference of the new SDK, see Integrating the Android SDK.
The Maven coordinate changes. The Java package com.testfairy and the TestFairy API do not, so import com.testfairy.TestFairy; and your TestFairy.* calls keep compiling. Both Java and Kotlin apps are supported.
Remove com.testfairy:testfairy-android-sdk and com.testfairy:testfairy-android-ndk from every module before you add the Sauce Mobile Beta artifact. Both families contain the same com.testfairy classes, so a build that contains both fails with Duplicate class errors. Never run the TestFairy SDK 1.x beside Backtrace (Sauce Labs Error Reporting) either: both install crash handlers, and a process has one owner of its signal and exception handlers.
1. Remove the TestFairy SDK Artifacts
Remove every TestFairy SDK 1.x dependency from every module's build.gradle (or build.gradle.kts), including the NDK artifact. Check library modules too: a transitive copy pulled in by another module also fails the build.
// Remove these lines from every module.
implementation 'com.testfairy:testfairy-android-sdk:1.+@aar'
implementation 'com.testfairy:testfairy-android-ndk:1.+@aar'
If the project declared https://maven.testfairy.com only for the TestFairy SDK 1.x, you can keep it: the Sauce Mobile Beta artifact is served from it as well, and https://maven.saucelabs.com serves the same repository. If the declaration has a content { includeGroup 'com.testfairy' } filter, change the group to com.saucelabs.mobilebeta as shown in step 2, or Gradle will not look up the new artifact there.
Verify. The following command prints nothing from the com.testfairy group:
./gradlew :app:dependencies --configuration debugRuntimeClasspath | grep testfairy
Repeat it for every module that declared the dependency.
2. Add the Sauce Mobile Beta Artifact
The Sauce Mobile Beta SDK for Android is com.saucelabs.mobilebeta:sauce-mobile-beta-android, served from https://maven.saucelabs.com. It is not on Maven Central or jcenter. It supports API level 16 or later on its own, and API level 21 or later with Backtrace (see step 4).
Make sure the repository is declared in settings.gradle (or in the root build.gradle for older project layouts). The content filter is optional and limits the repository to the com.saucelabs.mobilebeta group:
- Groovy DSL
- Kotlin DSL
// settings.gradle
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven {
url 'https://maven.saucelabs.com'
content { includeGroup 'com.saucelabs.mobilebeta' }
}
}
}
// settings.gradle.kts
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven {
url = uri("https://maven.saucelabs.com")
content { includeGroup("com.saucelabs.mobilebeta") }
}
}
}
Then add the dependency to your app module. Pin the exact version. Do not use version wildcards such as 2.+: they can pull in a build you have not tested.
- Groovy DSL
- Kotlin DSL
dependencies {
implementation "com.saucelabs.mobilebeta:sauce-mobile-beta-android:2.3.0"
}
dependencies {
implementation("com.saucelabs.mobilebeta:sauce-mobile-beta-android:2.3.0")
}
Prefer debugImplementation or a beta flavor configuration such as betaImplementation, so that store builds do not ship the SDK while Backtrace stays under implementation. See Sauce Mobile Beta SDK in Production.
Your imports stay the same:
import com.testfairy.TestFairy;
Verify. Gradle sync succeeds and the dependency graph lists com.saucelabs.mobilebeta:sauce-mobile-beta-android:2.3.0:
./gradlew :app:dependencies --configuration debugRuntimeClasspath | grep mobilebeta
3. Update the Initialization
Replace begin with beginWithoutCrashHandler in the onCreate method of your Application subclass. It starts a session, never installs a crash handler, and forces the enableCrashReporter option to false even if you pass true through the options overload beginWithoutCrashHandler(context, appToken, options). Replace <sauce-mobile-beta-token> and <server-endpoint> with your values.
Both values are in Organization Settings > SDK Settings on your Mobile App Distribution dashboard, under the organization that owns the app. Only Account Owners and Org Admins can open that page. See Organization Settings.
- SDK App Token: the organization-wide token your app starts sessions with. Regenerating it invalidates the previous token for every build that still carries it.
- Server Endpoint: the URL the SDK sends session data to, in the form
https://<host>/services/. It is specific to your region or private instance, so copy it exactly. If it reads Not configured, contact Sauce Labs support before you ship a build.
Pass the endpoint to setServerEndpoint before beginWithoutCrashHandler. The SDK's built-in default server is no longer in service: an app that skips this call starts no sessions.
- Java
- Kotlin
import android.app.Application;
import com.testfairy.TestFairy;
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// Before:
// TestFairy.begin(this, "<app-token>");
// After. Initialize Backtrace before this line when it is part of the app.
TestFairy.setServerEndpoint("<server-endpoint>");
TestFairy.beginWithoutCrashHandler(this, "<sauce-mobile-beta-token>");
}
}
import android.app.Application
import com.testfairy.TestFairy
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
// Before:
// TestFairy.begin(this, "<app-token>")
// After. Initialize Backtrace before this line when it is part of the app.
TestFairy.setServerEndpoint("<server-endpoint>")
TestFairy.beginWithoutCrashHandler(this, "<sauce-mobile-beta-token>")
}
}
The Application class stays registered in AndroidManifest.xml as before. If you pass an options map, remove the enableCrashReporter key. The SDK forces it to false anyway.
Verify. Build and run a debug build. A new session for the build appears in your Sauce Labs Mobile App Distribution dashboard.
4. Delete the Crash Handler Calls and Set Up Backtrace
The crash entry points still exist in the API, but they do nothing in the Sauce Mobile Beta SDK. Delete these calls from your code:
// Delete these calls. They are no-ops in the Sauce Mobile Beta SDK.
TestFairy.enableCrashHandler();
TestFairy.disableCrashHandler();
TestFairy.installCrashHandler(context, "<app-token>"); // does not start a session
TestFairy.didLastSessionCrash(context); // always returns false
If your app used installCrashHandler on its own, as a crash handler without a session, that use case is now covered by Backtrace alone. Any code built on didLastSessionCrash, for example a "the app crashed last time" prompt, needs a Backtrace-based replacement or removal.
Crash reporting is provided by Backtrace. Add the Backtrace Android SDK by following Setting Up Backtrace for Android, and initialize it before beginWithoutCrashHandler so that it is the only crash owner. For NDK crashes, also follow Native Crash Integration, which takes over the role of the testfairy-android-ndk artifact you removed. New to Backtrace? Start with Getting Started.
Two requirements come with Backtrace:
- Use Backtrace Android SDK 3.7.14 or later. That release added
BacktraceClient.addAttribute, which the SDK calls on the client linked in step 6. 3.14.0 or later is recommended. On 3.7.13 or earlier, the SDK falls back to the client's attribute map andBacktraceDatabase.addAttribute. See Configuring Backtrace for Android. - Backtrace Android requires API level 21. The Sauce Mobile Beta SDK alone supports API level 16, so an app that ships both must set
minSdk 21.
Verify. The following command prints nothing:
grep -rn "installCrashHandler\|enableCrashHandler\|disableCrashHandler\|didLastSessionCrash" --include="*.java" --include="*.kt" app/src
5. Review ProGuard, R8, and Symbol Uploads
The Sauce Mobile Beta AAR bundles its consumer ProGuard rules, so Gradle applies them automatically when minification is enabled. You do not need to add rules for the SDK. If your proguard-rules.pro still contains the rules from the TestFairy SDK 1.x, keeping them is harmless:
-keep class com.testfairy.** { *; }
-dontwarn com.testfairy.**
-keepattributes Exceptions, Signature, LineNumberTable
-dontusemixedcaseclassnames
An app on the Sauce Mobile Beta SDK sends no crash reports to Sauce Labs Mobile App Distribution, so crash symbolication for it happens in Backtrace. Upload your ProGuard mapping files and native symbols to Backtrace: see ProGuard Deobfuscation for mapping files and Upload Native Symbols for NDK symbols.
Verify. A minified build runs, and a crash report in Backtrace shows your class and method names.
6. Let the SDK Correlate Sessions
The SDK matches a Backtrace crash report with the session recorded up to the crash. At every session start it generates a new sauce.correlation_id, attaches it to the session, and hands it to Backtrace together with sauce.mobile_beta.session_url, sauce.mobile_beta.session_started, sauce.sdk.coexistence_mode, sauce.release, and sauce.dist. The SDK writes them into the Backtrace client you link with setBacktraceClient before beginWithoutCrashHandler. The parameter is typed Object, so the SDK has no compile-time dependency on Backtrace:
- Java
- Kotlin
TestFairy.setBacktraceClient(backtrace);
TestFairy.setServerEndpoint("<server-endpoint>");
TestFairy.beginWithoutCrashHandler(this, "<sauce-mobile-beta-token>");
TestFairy.setBacktraceClient(backtrace)
TestFairy.setServerEndpoint("<server-endpoint>")
TestFairy.beginWithoutCrashHandler(this, "<sauce-mobile-beta-token>")
Remove any code that generates a UUID for sauce.correlation_id, sets the SDK-managed keys with setAttribute, or copies the session URL into Backtrace from a SessionStateListener. setAttribute ignores the reserved keys with a warning, and the SDK overwrites the Backtrace values at the next session start. Keep sauce.environment and mad.distribution_id as your own attributes on both SDKs. To read the current id, call TestFairy.getSessionCorrelationId().
The contract is defined once, in Using Sauce Mobile Beta with Backtrace, which has the initialization order and a complete Application example, and SDK-Managed Attributes.
Do not use the deprecated setCorrelationId or identify methods for the correlation id. They write the user-identity field that setUserId writes, and on Android only the first call per process takes effect. See Identifying Your Users.
Verify. A session's attributes in Sauce Labs Mobile App Distribution show sauce.correlation_id, and a Backtrace report from that session shows the same value. After stop() and a new beginWithoutCrashHandler, getSessionCorrelationId() returns a different value.
7. Validate Before Release
- Inspect the runtime dependency graph of every module.
./gradlew :app:dependencies --configuration debugRuntimeClasspath | grep testfairymust list nothing from thecom.testfairygroup. - A clean build succeeds. A
Duplicate classerror forcom.testfairyclasses means a TestFairy SDK 1.x artifact is still on the classpath, possibly as a transitive dependency of another module. Go back to step 1. - Run a debug build with both SDKs initialized and force one crash (and one native crash if you enabled the native integration). The process dies as a genuine crash. Relaunch the app: the crashes appear in Backtrace only, and the Sauce Mobile Beta SDK starts a new session.
- Submit feedback from the app and confirm that the session shows
sauce.correlation_idin its attributes, with the same value as a Backtrace report from that session. - Confirm that release variants do not package the Sauce Mobile Beta SDK while Backtrace stays. See Sauce Mobile Beta SDK in Production.
Troubleshooting
Could not find com.saucelabs.mobilebeta:sauce-mobile-beta-android:2.3.0 or a Could not GET error for a jcenter.bintray.com URL. The SDK is served from https://maven.saucelabs.com (https://maven.testfairy.com serves the same repository), not from jcenter or Maven Central. Add the repository as shown in step 2.
Duplicate class errors for com.testfairy classes. A TestFairy SDK 1.x artifact (com.testfairy:testfairy-android-sdk or com.testfairy:testfairy-android-ndk) is still on the classpath, possibly through another module. Run the dependency graph command from step 1 for every module and remove it.
minSdk conflict after adding Backtrace. Backtrace Android requires API level 21. Set minSdk 21 for the combined app.
The log says Backtrace is present but not linked. The app did not call setBacktraceClient before the first session start, so crash reports carry none of the SDK-managed attributes. Call TestFairy.setBacktraceClient(backtrace) before beginWithoutCrashHandler, as shown in Using Sauce Mobile Beta with Backtrace. On Backtrace Android SDK 3.7.13 or earlier, the SDK falls back to the client's attribute map and BacktraceDatabase.addAttribute; upgrade to 3.7.14 or later (3.14.0 or later is recommended).
A crash shows up nowhere. The Sauce Mobile Beta SDK does not report crashes. Make sure Backtrace is initialized before beginWithoutCrashHandler and that its submission URL is correct. See Setting Up Backtrace for Android.
didLastSessionCrash returns false after a crash. The SDK returns false by design. Query Backtrace for crash history.