Skip to content

Commit 1c69dc8

Browse files
runningcodeclaudegetsentry-bot
authored
feat(android-distribution): Add module foundation with compilation stubs (#4712)
* feat(android-distribution): Add module foundation with compilation stubs This PR establishes the foundational structure for the sentry-android-distribution module with compilation stubs that enable parallel development of individual components. ### Changes - Android module configuration with necessary dependencies - AndroidManifest.xml with ContentProvider for auto-initialization - Distribution object with init(), isEnabled(), checkForUpdate() methods - DistributionOptions data class for configuration - UpdateStatus sealed class for result types - UpdateInfo data class for update details - Internal stub implementations that compile successfully ### Implementation Strategy - All methods return placeholder errors ("Implementation coming in future PR") - Follows zero-dependency design (only depends on sentry module) - Enables parallel development of binary identifier, HTTP client, API models, and core logic 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * feat(android-distribution): Address PR feedback - Fix ActivityNotFoundException in downloadUpdate method - Update AndroidManifest provider to use shorter naming convention - Add EmptySecureContentProvider for security - Convert DistributionOptions from data class to regular class - Add initOrder comment explaining initialization sequence 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * Format code * feat(android-distribution): Improve API design based on review feedback - Add lambda-based init pattern matching SentryAndroid.init - Rename checkForUpdate to checkForUpdateBlocking for clarity - Replace CompletableFuture with simple callback approach - Convert DistributionOptions to mutable builder pattern - Add example for buildConfiguration parameter 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * feat(android-distribution): Add automatic integration and top-level API - Add automatic distribution module detection in SentryAndroid.java - Create DistributionIntegration for seamless auto-enablement when module present - Add Sentry.distribution() top-level API using reflection for build-time safety - Remove ContentProvider approach in favor of Integration pattern - Update Distribution API to use callback-based async methods - Fix ActivityNotFoundException handling in downloadUpdate method Follows existing patterns from replay/timber/fragment integrations for consistency. Module works automatically when included, provides compile errors when not. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * Format code * refactor: Remove unnecessary sentry-android-core dependency and use direct instantiation - Remove sentry-android-core dependency from distribution module (only needs sentry module) - Add distribution as compileOnly dependency in sentry-android-core - Use direct DistributionIntegration instantiation instead of reflection - Eliminates circular dependency and follows same pattern as other integrations The distribution module only needs Integration/IScopes/SentryOptions from core sentry, not anything from sentry-android-core, making the architecture cleaner. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * style: Apply spotless formatting 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * docs: Remove PR submission plan No longer needed since this is a single PR implementation. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * Fix failing CI tests by adding missing isDistributionAvailable parameter Added the missing isDistributionAvailable parameter (set to false) to installDefaultIntegrations method calls in test files to fix compilation errors. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * Add distribution() method to API signature file Update sentry.api to include the new distribution() method signature to fix apiCheck failure. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * Fix R8 minification failure with consumer ProGuard rule for DistributionIntegration Added consumer ProGuard rule in sentry-android-core to handle missing DistributionIntegration class when the distribution module is not included. This follows the same pattern used for other optional integrations like Replay and Timber. * Update API dump for distribution module 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> --------- Co-authored-by: Claude <[email protected]> Co-authored-by: Sentry Github Bot <[email protected]>
1 parent 23d6b12 commit 1c69dc8

File tree

19 files changed

+305
-3
lines changed

19 files changed

+305
-3
lines changed

sentry-android-core/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ dependencies {
7777
compileOnly(projects.sentryAndroidTimber)
7878
compileOnly(projects.sentryAndroidReplay)
7979
compileOnly(projects.sentryCompose)
80+
compileOnly(projects.sentryAndroidDistribution)
8081

8182
// lifecycle processor, session tracking
8283
implementation(libs.androidx.lifecycle.common.java8)

sentry-android-core/proguard-rules.pro

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,8 @@
7878
-dontwarn io.sentry.android.replay.DefaultReplayBreadcrumbConverter
7979
-keepnames class io.sentry.android.replay.ReplayIntegration
8080
##---------------End: proguard configuration for sentry-android-replay ----------
81+
82+
##---------------Begin: proguard configuration for sentry-android-distribution ----------
83+
-dontwarn io.sentry.android.distribution.internal.DistributionIntegration
84+
-keepnames class io.sentry.android.distribution.internal.DistributionIntegration
85+
##---------------End: proguard configuration for sentry-android-distribution ----------

sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import io.sentry.android.core.internal.util.AndroidThreadChecker;
3333
import io.sentry.android.core.internal.util.SentryFrameMetricsCollector;
3434
import io.sentry.android.core.performance.AppStartMetrics;
35+
import io.sentry.android.distribution.internal.DistributionIntegration;
3536
import io.sentry.android.fragment.FragmentLifecycleIntegration;
3637
import io.sentry.android.replay.DefaultReplayBreadcrumbConverter;
3738
import io.sentry.android.replay.ReplayIntegration;
@@ -321,7 +322,8 @@ static void installDefaultIntegrations(
321322
final @NotNull ActivityFramesTracker activityFramesTracker,
322323
final boolean isFragmentAvailable,
323324
final boolean isTimberAvailable,
324-
final boolean isReplayAvailable) {
325+
final boolean isReplayAvailable,
326+
final boolean isDistributionAvailable) {
325327

326328
// Integration MUST NOT cache option values in ctor, as they will be configured later by the
327329
// user
@@ -391,6 +393,9 @@ static void installDefaultIntegrations(
391393
options.addIntegration(replay);
392394
options.setReplayController(replay);
393395
}
396+
if (isDistributionAvailable) {
397+
options.addIntegration(new DistributionIntegration());
398+
}
394399
options
395400
.getFeedbackOptions()
396401
.setDialogHandler(new SentryAndroidOptions.AndroidUserFeedbackIDialogHandler());

sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroid.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ public final class SentryAndroid {
4141
static final String SENTRY_REPLAY_INTEGRATION_CLASS_NAME =
4242
"io.sentry.android.replay.ReplayIntegration";
4343

44+
static final String SENTRY_DISTRIBUTION_INTEGRATION_CLASS_NAME =
45+
"io.sentry.android.distribution.internal.DistributionIntegration";
46+
4447
private static final String TIMBER_CLASS_NAME = "timber.log.Timber";
4548
private static final String FRAGMENT_CLASS_NAME =
4649
"androidx.fragment.app.FragmentManager$FragmentLifecycleCallbacks";
@@ -111,6 +114,8 @@ public static void init(
111114
&& classLoader.isClassAvailable(SENTRY_TIMBER_INTEGRATION_CLASS_NAME, options));
112115
final boolean isReplayAvailable =
113116
classLoader.isClassAvailable(SENTRY_REPLAY_INTEGRATION_CLASS_NAME, options);
117+
final boolean isDistributionAvailable =
118+
classLoader.isClassAvailable(SENTRY_DISTRIBUTION_INTEGRATION_CLASS_NAME, options);
114119

115120
final BuildInfoProvider buildInfoProvider = new BuildInfoProvider(logger);
116121
final io.sentry.util.LoadClass loadClass = new io.sentry.util.LoadClass();
@@ -131,7 +136,8 @@ public static void init(
131136
activityFramesTracker,
132137
isFragmentAvailable,
133138
isTimberAvailable,
134-
isReplayAvailable);
139+
isReplayAvailable,
140+
isDistributionAvailable);
135141

136142
try {
137143
configuration.configure(options);

sentry-android-core/src/test/java/io/sentry/android/core/AndroidContinuousProfilerTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ class AndroidContinuousProfilerTest {
124124
false,
125125
false,
126126
false,
127+
false,
127128
)
128129

129130
AndroidOptionsInitializer.initializeIntegrationsAndProcessors(

sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ class AndroidOptionsInitializerTest {
105105
false,
106106
false,
107107
false,
108+
false,
108109
)
109110

110111
sentryOptions.configureOptions()
@@ -149,6 +150,7 @@ class AndroidOptionsInitializerTest {
149150
isFragmentAvailable,
150151
isTimberAvailable,
151152
isReplayAvailable,
153+
false,
152154
)
153155

154156
AndroidOptionsInitializer.initializeIntegrationsAndProcessors(
@@ -820,6 +822,7 @@ class AndroidOptionsInitializerTest {
820822
false,
821823
false,
822824
false,
825+
false,
823826
)
824827
verify(mockOptions, never()).outboxPath
825828
verify(mockOptions, never()).cacheDirPath

sentry-android-core/src/test/java/io/sentry/android/core/AndroidProfilerTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ class AndroidProfilerTest {
127127
false,
128128
false,
129129
false,
130+
false,
130131
)
131132

132133
AndroidOptionsInitializer.initializeIntegrationsAndProcessors(

sentry-android-core/src/test/java/io/sentry/android/core/AndroidTransactionProfilerTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ class AndroidTransactionProfilerTest {
143143
false,
144144
false,
145145
false,
146+
false,
146147
)
147148

148149
AndroidOptionsInitializer.initializeIntegrationsAndProcessors(

sentry-android-core/src/test/java/io/sentry/android/core/SentryInitProviderTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ class SentryInitProviderTest {
160160
false,
161161
false,
162162
false,
163+
false,
163164
)
164165

165166
AndroidOptionsInitializer.initializeIntegrationsAndProcessors(
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,79 @@
11
public final class io/sentry/android/distribution/Distribution {
2+
public static final field INSTANCE Lio/sentry/android/distribution/Distribution;
3+
public final fun checkForUpdate (Landroid/content/Context;Lkotlin/jvm/functions/Function1;)V
4+
public final fun checkForUpdateBlocking (Landroid/content/Context;)Lio/sentry/android/distribution/UpdateStatus;
5+
public final fun downloadUpdate (Landroid/content/Context;Lio/sentry/android/distribution/UpdateInfo;)V
6+
public final fun init (Landroid/content/Context;)V
7+
public final fun init (Landroid/content/Context;Lkotlin/jvm/functions/Function1;)V
8+
public final fun isEnabled ()Z
9+
}
10+
11+
public final class io/sentry/android/distribution/DistributionOptions {
12+
public fun <init> ()V
13+
public final fun getBuildConfiguration ()Ljava/lang/String;
14+
public final fun getOrgAuthToken ()Ljava/lang/String;
15+
public final fun getOrganizationSlug ()Ljava/lang/String;
16+
public final fun getProjectSlug ()Ljava/lang/String;
17+
public final fun getSentryBaseUrl ()Ljava/lang/String;
18+
public final fun setBuildConfiguration (Ljava/lang/String;)V
19+
public final fun setOrgAuthToken (Ljava/lang/String;)V
20+
public final fun setOrganizationSlug (Ljava/lang/String;)V
21+
public final fun setProjectSlug (Ljava/lang/String;)V
22+
public final fun setSentryBaseUrl (Ljava/lang/String;)V
23+
}
24+
25+
public final class io/sentry/android/distribution/UpdateInfo {
26+
public fun <init> (Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
27+
public final fun component1 ()Ljava/lang/String;
28+
public final fun component2 ()Ljava/lang/String;
29+
public final fun component3 ()I
30+
public final fun component4 ()Ljava/lang/String;
31+
public final fun component5 ()Ljava/lang/String;
32+
public final fun component6 ()Ljava/lang/String;
33+
public final fun copy (Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lio/sentry/android/distribution/UpdateInfo;
34+
public static synthetic fun copy$default (Lio/sentry/android/distribution/UpdateInfo;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/sentry/android/distribution/UpdateInfo;
35+
public fun equals (Ljava/lang/Object;)Z
36+
public final fun getAppName ()Ljava/lang/String;
37+
public final fun getBuildNumber ()I
38+
public final fun getBuildVersion ()Ljava/lang/String;
39+
public final fun getCreatedDate ()Ljava/lang/String;
40+
public final fun getDownloadUrl ()Ljava/lang/String;
41+
public final fun getId ()Ljava/lang/String;
42+
public fun hashCode ()I
43+
public fun toString ()Ljava/lang/String;
44+
}
45+
46+
public abstract class io/sentry/android/distribution/UpdateStatus {
47+
}
48+
49+
public final class io/sentry/android/distribution/UpdateStatus$Error : io/sentry/android/distribution/UpdateStatus {
50+
public fun <init> (Ljava/lang/String;)V
51+
public final fun component1 ()Ljava/lang/String;
52+
public final fun copy (Ljava/lang/String;)Lio/sentry/android/distribution/UpdateStatus$Error;
53+
public static synthetic fun copy$default (Lio/sentry/android/distribution/UpdateStatus$Error;Ljava/lang/String;ILjava/lang/Object;)Lio/sentry/android/distribution/UpdateStatus$Error;
54+
public fun equals (Ljava/lang/Object;)Z
55+
public final fun getMessage ()Ljava/lang/String;
56+
public fun hashCode ()I
57+
public fun toString ()Ljava/lang/String;
58+
}
59+
60+
public final class io/sentry/android/distribution/UpdateStatus$NewRelease : io/sentry/android/distribution/UpdateStatus {
61+
public fun <init> (Lio/sentry/android/distribution/UpdateInfo;)V
62+
public final fun component1 ()Lio/sentry/android/distribution/UpdateInfo;
63+
public final fun copy (Lio/sentry/android/distribution/UpdateInfo;)Lio/sentry/android/distribution/UpdateStatus$NewRelease;
64+
public static synthetic fun copy$default (Lio/sentry/android/distribution/UpdateStatus$NewRelease;Lio/sentry/android/distribution/UpdateInfo;ILjava/lang/Object;)Lio/sentry/android/distribution/UpdateStatus$NewRelease;
65+
public fun equals (Ljava/lang/Object;)Z
66+
public final fun getInfo ()Lio/sentry/android/distribution/UpdateInfo;
67+
public fun hashCode ()I
68+
public fun toString ()Ljava/lang/String;
69+
}
70+
71+
public final class io/sentry/android/distribution/UpdateStatus$UpToDate : io/sentry/android/distribution/UpdateStatus {
72+
public static final field INSTANCE Lio/sentry/android/distribution/UpdateStatus$UpToDate;
73+
}
74+
75+
public final class io/sentry/android/distribution/internal/DistributionIntegration : io/sentry/Integration {
276
public fun <init> ()V
77+
public fun register (Lio/sentry/IScopes;Lio/sentry/SentryOptions;)V
378
}
479

0 commit comments

Comments
 (0)