Skip to content

Commit b60f232

Browse files
runningcodeclaude
andcommitted
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 <noreply@anthropic.com>
1 parent 17a0955 commit b60f232

File tree

8 files changed

+289
-1
lines changed

8 files changed

+289
-1
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,89 @@
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;)Lio/sentry/android/distribution/UpdateStatus;
4+
public final fun checkForUpdateCompletableFuture (Landroid/content/Context;)Ljava/util/concurrent/CompletableFuture;
5+
public final fun downloadUpdate (Landroid/content/Context;Lio/sentry/android/distribution/UpdateInfo;)V
6+
public final fun init (Landroid/content/Context;Lio/sentry/android/distribution/DistributionOptions;)V
7+
public final fun isEnabled ()Z
8+
}
9+
10+
public final class io/sentry/android/distribution/DistributionContentProvider : android/content/ContentProvider {
211
public fun <init> ()V
12+
public fun delete (Landroid/net/Uri;Ljava/lang/String;[Ljava/lang/String;)I
13+
public fun getType (Landroid/net/Uri;)Ljava/lang/String;
14+
public fun insert (Landroid/net/Uri;Landroid/content/ContentValues;)Landroid/net/Uri;
15+
public fun onCreate ()Z
16+
public fun query (Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;
17+
public fun update (Landroid/net/Uri;Landroid/content/ContentValues;Ljava/lang/String;[Ljava/lang/String;)I
18+
}
19+
20+
public final class io/sentry/android/distribution/DistributionOptions {
21+
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
22+
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
23+
public final fun component1 ()Ljava/lang/String;
24+
public final fun component2 ()Ljava/lang/String;
25+
public final fun component3 ()Ljava/lang/String;
26+
public final fun component4 ()Ljava/lang/String;
27+
public final fun component5 ()Ljava/lang/String;
28+
public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lio/sentry/android/distribution/DistributionOptions;
29+
public static synthetic fun copy$default (Lio/sentry/android/distribution/DistributionOptions;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/sentry/android/distribution/DistributionOptions;
30+
public fun equals (Ljava/lang/Object;)Z
31+
public final fun getBuildConfiguration ()Ljava/lang/String;
32+
public final fun getOrgAuthToken ()Ljava/lang/String;
33+
public final fun getOrganizationSlug ()Ljava/lang/String;
34+
public final fun getProjectSlug ()Ljava/lang/String;
35+
public final fun getSentryBaseUrl ()Ljava/lang/String;
36+
public fun hashCode ()I
37+
public fun toString ()Ljava/lang/String;
38+
}
39+
40+
public final class io/sentry/android/distribution/UpdateInfo {
41+
public fun <init> (Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
42+
public final fun component1 ()Ljava/lang/String;
43+
public final fun component2 ()Ljava/lang/String;
44+
public final fun component3 ()I
45+
public final fun component4 ()Ljava/lang/String;
46+
public final fun component5 ()Ljava/lang/String;
47+
public final fun component6 ()Ljava/lang/String;
48+
public final fun copy (Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lio/sentry/android/distribution/UpdateInfo;
49+
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;
50+
public fun equals (Ljava/lang/Object;)Z
51+
public final fun getAppName ()Ljava/lang/String;
52+
public final fun getBuildNumber ()I
53+
public final fun getBuildVersion ()Ljava/lang/String;
54+
public final fun getCreatedDate ()Ljava/lang/String;
55+
public final fun getDownloadUrl ()Ljava/lang/String;
56+
public final fun getId ()Ljava/lang/String;
57+
public fun hashCode ()I
58+
public fun toString ()Ljava/lang/String;
59+
}
60+
61+
public abstract class io/sentry/android/distribution/UpdateStatus {
62+
}
63+
64+
public final class io/sentry/android/distribution/UpdateStatus$Error : io/sentry/android/distribution/UpdateStatus {
65+
public fun <init> (Ljava/lang/String;)V
66+
public final fun component1 ()Ljava/lang/String;
67+
public final fun copy (Ljava/lang/String;)Lio/sentry/android/distribution/UpdateStatus$Error;
68+
public static synthetic fun copy$default (Lio/sentry/android/distribution/UpdateStatus$Error;Ljava/lang/String;ILjava/lang/Object;)Lio/sentry/android/distribution/UpdateStatus$Error;
69+
public fun equals (Ljava/lang/Object;)Z
70+
public final fun getMessage ()Ljava/lang/String;
71+
public fun hashCode ()I
72+
public fun toString ()Ljava/lang/String;
73+
}
74+
75+
public final class io/sentry/android/distribution/UpdateStatus$NewRelease : io/sentry/android/distribution/UpdateStatus {
76+
public fun <init> (Lio/sentry/android/distribution/UpdateInfo;)V
77+
public final fun component1 ()Lio/sentry/android/distribution/UpdateInfo;
78+
public final fun copy (Lio/sentry/android/distribution/UpdateInfo;)Lio/sentry/android/distribution/UpdateStatus$NewRelease;
79+
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;
80+
public fun equals (Ljava/lang/Object;)Z
81+
public final fun getInfo ()Lio/sentry/android/distribution/UpdateInfo;
82+
public fun hashCode ()I
83+
public fun toString ()Ljava/lang/String;
84+
}
85+
86+
public final class io/sentry/android/distribution/UpdateStatus$UpToDate : io/sentry/android/distribution/UpdateStatus {
87+
public static final field INSTANCE Lio/sentry/android/distribution/UpdateStatus$UpToDate;
388
}
489

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
3+
<uses-permission android:name="android.permission.INTERNET" />
4+
5+
<application>
6+
<provider
7+
android:name="io.sentry.android.distribution.DistributionContentProvider"
8+
android:authorities="${applicationId}.sentry-distribution-provider"
9+
android:exported="false"
10+
android:initOrder="100" />
11+
</application>
12+
</manifest>
Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,70 @@
11
package io.sentry.android.distribution
22

3-
public class Distribution {}
3+
import android.content.Context
4+
import android.content.Intent
5+
import android.net.Uri
6+
import io.sentry.android.distribution.internal.DistributionInternal
7+
import java.util.concurrent.CompletableFuture
8+
9+
/**
10+
* The public Android SDK for Sentry Build Distribution.
11+
*
12+
* Provides functionality to check for app updates and download new versions from Sentry's preprod
13+
* artifacts system.
14+
*/
15+
public object Distribution {
16+
/**
17+
* Initialize build distribution with the provided options. This should be called once per
18+
* process, typically in Application.onCreate().
19+
*
20+
* @param context Android context
21+
* @param options Configuration options for build distribution
22+
*/
23+
public fun init(context: Context, options: DistributionOptions) {
24+
DistributionInternal.init(context, options)
25+
}
26+
27+
/**
28+
* Check if build distribution is enabled and properly configured.
29+
*
30+
* @return true if build distribution is enabled
31+
*/
32+
public fun isEnabled(): Boolean {
33+
return DistributionInternal.isEnabled()
34+
}
35+
36+
/**
37+
* Check for available updates synchronously (blocking call). This method will block the calling
38+
* thread while making the network request. Consider using checkForUpdateCompletableFuture for
39+
* non-blocking behavior.
40+
*
41+
* @param context Android context
42+
* @return UpdateStatus indicating if an update is available, up to date, or error
43+
*/
44+
public fun checkForUpdate(context: Context): UpdateStatus {
45+
return DistributionInternal.checkForUpdate(context)
46+
}
47+
48+
/**
49+
* Check for available updates using CompletableFuture for Java compatibility.
50+
*
51+
* @param context Android context
52+
* @return CompletableFuture with UpdateStatus result
53+
*/
54+
public fun checkForUpdateCompletableFuture(context: Context): CompletableFuture<UpdateStatus> {
55+
return DistributionInternal.checkForUpdateCompletableFuture(context)
56+
}
57+
58+
/**
59+
* Download and install the provided update by opening the download URL in the default browser or
60+
* appropriate application.
61+
*
62+
* @param context Android context
63+
* @param info Information about the update to download
64+
*/
65+
public fun downloadUpdate(context: Context, info: UpdateInfo) {
66+
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(info.downloadUrl))
67+
browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
68+
context.startActivity(browserIntent)
69+
}
70+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package io.sentry.android.distribution
2+
3+
import android.content.ContentProvider
4+
import android.content.ContentValues
5+
import android.database.Cursor
6+
import android.net.Uri
7+
8+
/**
9+
* ContentProvider that automatically initializes the Sentry Distribution SDK.
10+
*
11+
* This provider is automatically instantiated by the Android system when the app starts, ensuring
12+
* the Distribution SDK is available without requiring manual initialization in
13+
* Application.onCreate().
14+
*/
15+
public class DistributionContentProvider : ContentProvider() {
16+
override fun onCreate(): Boolean {
17+
// TODO: Automatic initialization will be implemented in future PR
18+
return true
19+
}
20+
21+
// Required ContentProvider methods (not used for initialization)
22+
override fun query(
23+
uri: Uri,
24+
projection: Array<String>?,
25+
selection: String?,
26+
selectionArgs: Array<String>?,
27+
sortOrder: String?,
28+
): Cursor? = null
29+
30+
override fun getType(uri: Uri): String? = null
31+
32+
override fun insert(uri: Uri, values: ContentValues?): Uri? = null
33+
34+
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int = 0
35+
36+
override fun update(
37+
uri: Uri,
38+
values: ContentValues?,
39+
selection: String?,
40+
selectionArgs: Array<String>?,
41+
): Int = 0
42+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package io.sentry.android.distribution
2+
3+
/**
4+
* Configuration options for Sentry Build Distribution.
5+
*
6+
* @param orgAuthToken Organization authentication token for API access
7+
* @param organizationSlug Sentry organization slug
8+
* @param projectSlug Sentry project slug
9+
* @param sentryBaseUrl Base URL for Sentry API (defaults to https://sentry.io)
10+
* @param buildConfiguration Optional build configuration name for filtering
11+
*/
12+
public data class DistributionOptions(
13+
val orgAuthToken: String,
14+
val organizationSlug: String,
15+
val projectSlug: String,
16+
val sentryBaseUrl: String = "https://sentry.io",
17+
val buildConfiguration: String? = null,
18+
)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package io.sentry.android.distribution
2+
3+
/**
4+
* Information about an available app update.
5+
*
6+
* @param id Unique identifier for this build artifact
7+
* @param buildVersion Version string (e.g., "1.2.0")
8+
* @param buildNumber Build number for this version
9+
* @param downloadUrl URL where the update can be downloaded
10+
* @param appName Application name
11+
* @param createdDate ISO timestamp when this build was created
12+
*/
13+
public data class UpdateInfo(
14+
val id: String,
15+
val buildVersion: String,
16+
val buildNumber: Int,
17+
val downloadUrl: String,
18+
val appName: String,
19+
val createdDate: String,
20+
)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package io.sentry.android.distribution
2+
3+
/** Represents the result of checking for app updates. */
4+
public sealed class UpdateStatus {
5+
/** Current app version is up to date, no update available. */
6+
public object UpToDate : UpdateStatus()
7+
8+
/** A new release is available for download. */
9+
public data class NewRelease(val info: UpdateInfo) : UpdateStatus()
10+
11+
/** An error occurred during the update check. */
12+
public data class Error(val message: String) : UpdateStatus()
13+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package io.sentry.android.distribution.internal
2+
3+
import android.content.Context
4+
import io.sentry.android.distribution.DistributionOptions
5+
import io.sentry.android.distribution.UpdateStatus
6+
import java.util.concurrent.CompletableFuture
7+
8+
/** Internal implementation for build distribution functionality. */
9+
internal object DistributionInternal {
10+
private var isInitialized = false
11+
12+
@Synchronized
13+
fun init(context: Context, distributionOptions: DistributionOptions) {
14+
// TODO: Implementation will be added in future PR
15+
isInitialized = true
16+
}
17+
18+
fun isEnabled(): Boolean {
19+
return isInitialized
20+
}
21+
22+
fun checkForUpdate(context: Context): UpdateStatus {
23+
return UpdateStatus.Error("Implementation coming in future PR")
24+
}
25+
26+
fun checkForUpdateCompletableFuture(context: Context): CompletableFuture<UpdateStatus> {
27+
val future = CompletableFuture<UpdateStatus>()
28+
future.complete(UpdateStatus.Error("Implementation coming in future PR"))
29+
return future
30+
}
31+
}

0 commit comments

Comments
 (0)