Setup (Android)
Get started using Reaper in Android in under 10 minutes
Reaper for Android is currently in Beta
Reach out to [email protected] or fill out this form for access
Reaper is an SDK that uses production data to detect dead code. See the emerge-android repo for source code.
Quick setup (~10 minutes)
Install the SDK
First, if you haven't already, you must install our Gradle plugin by following our setup guide. The Gradle plugin is used to instrument your application code.
Second, add an implementation dependency for the Reaper SDK:
Latest versions:
// app-module build.gradle.kts
dependencies {
implementation("com.emergetools.reaper:reaper:<latest_version>")
}
Configure the SDK
The SDK automatically sends user sessions to Emerge's backend, allowing Emerge to determine used & unused code.
To send sessions we need to configure two settings within the reaper
block: enabledVariants
and publishableApiKey
. Additionally, Emerge needs the apiToken
to be set for uploading the AAB with Reaper to Emerge.
apiToken
is a token used by the Emerge Gradle plugin for uploading the outputted AAB with Reaper to Emerge. This uploaded AAB is used by Emerge to find all possible classes in the app. You can create a new API token here.enabledVariants
is a List property that controls whether the plugin instruments the bytecode during compilation. for the specified variantspublishableApiKey
is a token included with Reaper reports uploaded from the field to Emerge. The key can be found here.
// app-module build.gradle.kts
plugins {
id("com.emergetools.android")
}
emerge {
// Emerge uses the EMERGE_API_TOKEN env variable by default if you don't set a value explicitly.
apiToken.set(System.getenv("EMERGE_API_TOKEN"))
// ...
reaper {
enabledVariants.set("release")
publishableApiKey.set("<PUBLISHABLE API KEY>")
}
}
Setup verification
Emerge offers a task, ./gradlew :<app>:emergeReaperPreflight<variant>
to verify Reaper is set up properly for each variant of your application.
āŗ ./gradlew :app:emergeReaperPreflightRelease
BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed
> Task :app:emergeReaperPreflightRelease
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Reaper preflight was successful (3/3) ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā ā ā
Reaper enabled for variant: release
ā ā ā
reaper.publishableApiKey set
āā ā
Reaper runtime SDK added
Any errors in the Reaper configuration will be raised here with instructions for how to address them.
Build and upload the release AAB
Reaper is intended to run on Release builds
Emerge recommends only enabling Reaper on non-debug variants.
Even if just for testing, Emerge does not recommend leveraging debug builds with reaper, as it can lead to inaccurate results due to lack of minification and other optimizations that occur only in release builds.
Emerge requires a release AAB with Reaper to be uploaded, as Emerge analyzes the app to determine all classes available.
This is done automatically by the default AGP ./gradlew :<app>:bundle<variant>
Gradle task. Emerge hooks the bundle
tasks for any variants specified with enabledVariants
and uploads the AAB automatically to Emerge.
Emerge will then parse the uploaded AAB and find all possible classes in the app, which will later be marked as used/unused when user reports are uploaded.
Viewing Reaper data
All versions of your app with Reaper included can be viewed in the uploads page, under the "Reaper" tab: https://www.emergetools.com/uploads?tab=reaper.
Clicking on a version will take you to a detailed breakdown of class usage information for that app version.
Once Reaper is in your app, as your users use the application, reports will be sent and analyzed by Emerge to aggregate class usage information.
Note: After setting up/uploading for the first time, it's expected for an app to have all classes marked as unused and no session counts. Once you release your app with Reaper integrated and sessions begin to be uploaded, Emerge will reflect unused classes and session counts in the UI.
Publish the built AAB
The ./gradlew :<app>:bundle<variant>
will generate the AAB for the specific variant specified in the standard output directory (<app>/build/outputs/bundle/<variant>/app-<variant>.aab
) with Reaper set up.
Emerge recommends publishing the built AAB to Google Play and any other publications as the final release build artifact.
That's it!
Once published, the Emerge SDK. will begin uploading real code usage reports to Emerge.
Read on for more information on how Reaper works and how to interpret results.
How does it work?
Reaper works by instrumenting your app's code using Emerge's gradle plugin. The plugin adds "breadcrumb" logging, which records hashed information about code as it's used.
The Reaper SDK will aggregate this information into a background report. Once users leave your app, the Reaper SDK will upload the report to Emerge. Emerge will then connect the hashed class usage information on our backend with the detected classes in your app, which is then used to determine which code is used and unused.
Emerge will then reflect which code is unused in the Reaper UI. Emerge recommends waiting some time for a critical amount of sessions to be received before taking action on deleting unused code.
Performance impact
Emerge has heavily tested Reaper on apps like Hacker News and Now in Android. The overall performance impact of adding/using reaper is negligible. Reaper adds ~2 instructions to the init method of a class.
Nonetheless, Emerge would encourage adding Reaper into a beta/internal release track before rolling out to production and validating using Emerge performance testing or any other performance metrics your team currently leverages.
Size impact
The overall size impact of Reaper is a function of the number of classes in the app. The SDK itself adds ~12kb of download size to an app. Additionally, Reaper relies on class instrumentation, which will add a few instructions and an 8-byte hash string to each class.
For apps like apps like Hacker News and Now in Android, we've seen a ~5% increase in download size from adding Reaper.
SDK initialization
Automatic initialization
Reaper relies on the Androidx startup library to auto-initialize the Reaper SDK as part of your app's startup.
Disable automatic initialization
To disable automatic initialization add the following snippet to your app's AndroidManifest.xml
:
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data android:name="com.emergetools.reaper.ReaperInitializer"
tools:node="remove" />
</provider>
You may need to add a direct dependency on theandroidx.startup:startup-runtime
library if the app does not already have such a dependency.
// app-module build.gradle.kts
dependencies {
implementation("androidx.startup:startup-runtime:<latest_version>")
}
Follow the Manual initialization steps below to ensure that Reaper is initialized.
Manual initialization
To manually initialize Reaper call Reaper.init(context)
. For example:
import com.emergetools.reaper.Reaper
class MyApp : Application() {
override fun onCreate() {
Reaper.init(this)
}
}
import com.emergetools.reaper.Reaper;
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
Reaper.init(this);
}
}
A common case when manual initialization is required is when androidx.startup.InitializationProvider
has been globally disabled by the following snippet being included in the AndroidManifest.xml
:
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="remove">
<meta-data
android:name="androidx.work.WorkManagerInitializer"
android:value="androidx.startup"
tools:node="remove" />
</provider>
Common Errors
Missing classes detected while running R8
Missing classes detected while running R8
Example error message
ERROR: Missing classes detected while running R8. Please add the missing classes or apply additional keep rules that are generated in missing_rules.txt.
ERROR: R8: Missing class com.emergetools.reaper.ReaperInternal (referenced from: void \_COROUTINE.ArtificialStackFrames.<init>() and 5715 other contexts)
Cause This occurs when the Gradle plugin instruments the code but the SDK is not added as a implementation dependency.
Fix Add the following code to the application build.gradle.kts
file:
// app-module build.gradle.kts
dependencies {
implementation("com.emergetools.reaper:reaper:<latest_version>")
}
Updated 12 days ago