Repository: square/leakcanary
Issue: Failed to dump heap @HeapAnalyzerWorker NoSuchMethodError

### Description

[Description of the issue]
```
java.lang.NoSuchMethodError: No virtual method putByteArray(Ljava/lang/String;[B)Landroidx/work/Data$Builder; in class Landroidx/work/Data$Builder; or its super classes (declaration of 'androidx.work.Data$Builder' appears in /data/app/~~rvMD-eu-AHcTZlBHz6-m7Q==/com.xxx.xxxx-SGi5CaUQpM6RMmVM1Kf2pg==/base.apk)
 	at leakcanary.internal.HeapAnalyzerWorker$Companion.asWorkerInputData(HeapAnalyzerWorker.kt:33)
 	at leakcanary.internal.HeapAnalyzerWorker$Companion.asWorkerInputData$default(HeapAnalyzerWorker.kt:32)
 	at leakcanary.WorkManagerHeapAnalyzer.onEvent(WorkManagerHeapAnalyzer.kt:46)
 	at leakcanary.internal.InternalLeakCanary.sendEvent(InternalLeakCanary.kt:333)
 	at leakcanary.internal.HeapDumpTrigger.dumpHeap(HeapDumpTrigger.kt:191)
 	at leakcanary.internal.HeapDumpTrigger.access$dumpHeap(HeapDumpTrigger.kt:34)
 	at leakcanary.internal.HeapDumpTrigger$onDumpHeapReceived$1.run(HeapDumpTrigger.kt:265)
 	at android.os.Handler.handleCallback(Handler.java:938)
 	at android.os.Handler.dispatchMessage(Handler.java:99)
 	at android.os.Looper.loop(Looper.java:233)
 	at android.os.HandlerThread.run(HandlerThread.java:67)
```

### Steps to Reproduce

[Provide a sample project, a .hprof file or a failing test]

1. [First Step]
2. [Second Step]
3. [and so on...]

**Expected behavior:** [What you expect to happen]

### Version Information

* LeakCanary version:2.8.1
* Android OS version:11
* Gradle version:6.7

### Additional Information

Any additional information, configuration or data that might be necessary to reproduce the issue.


Changed files:
leakcanary-android-core/src/main/java/leakcanary/WorkManagerHeapAnalyzer.kt, leakcanary-android-core/src/main/java/leakcanary/LeakCanary.kt

diff --git a/leakcanary-android-core/src/main/java/leakcanary/LeakCanary.kt b/leakcanary-android-core/src/main/java/leakcanary/LeakCanary.kt
index 32e23d99c..6027cb934 100644
--- a/leakcanary-android-core/src/main/java/leakcanary/LeakCanary.kt
+++ b/leakcanary-android-core/src/main/java/leakcanary/LeakCanary.kt
@@ -203,7 +203,7 @@ object LeakCanary {
       when {
           RemoteWorkManagerHeapAnalyzer.remoteLeakCanaryServiceInClasspath ->
             RemoteWorkManagerHeapAnalyzer
-          WorkManagerHeapAnalyzer.workManagerInClasspath -> WorkManagerHeapAnalyzer
+          WorkManagerHeapAnalyzer.validWorkManagerInClasspath -> WorkManagerHeapAnalyzer
           else -> BackgroundThreadHeapAnalyzer
       }
     ),
diff --git a/leakcanary-android-core/src/main/java/leakcanary/WorkManagerHeapAnalyzer.kt b/leakcanary-android-core/src/main/java/leakcanary/WorkManagerHeapAnalyzer.kt
index d8762c92d..73a8503e9 100644
--- a/leakcanary-android-core/src/main/java/leakcanary/WorkManagerHeapAnalyzer.kt
+++ b/leakcanary-android-core/src/main/java/leakcanary/WorkManagerHeapAnalyzer.kt
@@ -15,10 +15,17 @@ import shark.SharkLog
  */
 object WorkManagerHeapAnalyzer : EventListener {
 
-  internal val workManagerInClasspath by lazy {
+  internal val validWorkManagerInClasspath by lazy {
     try {
       Class.forName("androidx.work.WorkManager")
-      true
+      // We need Data.Builder.putByteArray which was introduced in WorkManager 2.1.0.
+      // https://github.com/square/leakcanary/issues/2310
+      val dataBuilderClass = Class.forName("androidx.work.Data\\$Builder")
+      dataBuilderClass.declaredMethods.any { it.name == "putByteArray" }.apply {
+        if (!this) {
+          SharkLog.d { "Could not find androidx.work.Data\\$Builder.putByteArray, WorkManager should be at least 2.1.0." }
+        }
+      }
     } catch (ignored: Throwable) {
       false
     }