diff --git a/sentry-android-distribution/src/main/java/io/sentry/android/distribution/DistributionHttpClient.kt b/sentry-android-distribution/src/main/java/io/sentry/android/distribution/DistributionHttpClient.kt index 82c699a572..c4b2fcff8e 100644 --- a/sentry-android-distribution/src/main/java/io/sentry/android/distribution/DistributionHttpClient.kt +++ b/sentry-android-distribution/src/main/java/io/sentry/android/distribution/DistributionHttpClient.kt @@ -26,6 +26,7 @@ internal class DistributionHttpClient(private val options: SentryOptions) { val platform: String = "android", val versionCode: Long, val versionName: String, + val buildConfiguration: String, ) /** @@ -56,9 +57,12 @@ internal class DistributionHttpClient(private val options: SentryOptions) { append("&platform=${URLEncoder.encode(params.platform, "UTF-8")}") append("&build_number=${URLEncoder.encode(params.versionCode.toString(), "UTF-8")}") append("&build_version=${URLEncoder.encode(params.versionName, "UTF-8")}") + append("&build_configuration=${URLEncoder.encode(params.buildConfiguration, "UTF-8")}") } val url = URL(urlString) + options.logger.log(SentryLevel.DEBUG, "Distribution API URL: $urlString") + return try { makeRequest(url, authToken) } catch (e: IOException) { diff --git a/sentry-android-distribution/src/main/java/io/sentry/android/distribution/DistributionIntegration.kt b/sentry-android-distribution/src/main/java/io/sentry/android/distribution/DistributionIntegration.kt index 8509e4128a..b22154b87e 100644 --- a/sentry-android-distribution/src/main/java/io/sentry/android/distribution/DistributionIntegration.kt +++ b/sentry-android-distribution/src/main/java/io/sentry/android/distribution/DistributionIntegration.kt @@ -132,11 +132,16 @@ public class DistributionIntegration(context: Context) : Integration, IDistribut } val appId = context.applicationInfo.packageName + val buildConfiguration = + sentryOptions.distribution.buildConfiguration + ?: throw IllegalStateException("buildConfiguration must be set in distribution options") + DistributionHttpClient.UpdateCheckParams( appId = appId, platform = "android", versionCode = versionCode, versionName = versionName, + buildConfiguration = buildConfiguration, ) } catch (e: PackageManager.NameNotFoundException) { sentryOptions.logger.log(SentryLevel.ERROR, e, "Failed to get package info") diff --git a/sentry-android-distribution/src/main/java/io/sentry/android/distribution/UpdateResponseParser.kt b/sentry-android-distribution/src/main/java/io/sentry/android/distribution/UpdateResponseParser.kt index a1396cae46..e97e0a5ea4 100644 --- a/sentry-android-distribution/src/main/java/io/sentry/android/distribution/UpdateResponseParser.kt +++ b/sentry-android-distribution/src/main/java/io/sentry/android/distribution/UpdateResponseParser.kt @@ -32,11 +32,11 @@ internal class UpdateResponseParser(private val options: SentryOptions) { options.logger.log(SentryLevel.DEBUG, "Parsing distribution API response") - // Check if there's a new release available - val updateAvailable = json.optBoolean("updateAvailable", false) + // Check if there's an update object in the response + val updateJson = json.optJSONObject("update") - if (updateAvailable) { - val updateInfo = parseUpdateInfo(json) + if (updateJson != null) { + val updateInfo = parseUpdateInfo(updateJson) UpdateStatus.NewRelease(updateInfo) } else { UpdateStatus.UpToDate.getInstance() @@ -52,11 +52,11 @@ internal class UpdateResponseParser(private val options: SentryOptions) { private fun parseUpdateInfo(json: JSONObject): UpdateInfo { val id = json.optString("id", "") - val buildVersion = json.optString("buildVersion", "") - val buildNumber = json.optInt("buildNumber", 0) - val downloadUrl = json.optString("downloadUrl", "") - val appName = json.optString("appName", "") - val createdDate = json.optString("createdDate", "") + val buildVersion = json.optString("build_version", "") + val buildNumber = json.optInt("build_number", 0) + val downloadUrl = json.optString("download_url", "") + val appName = json.optString("app_name", "") + val createdDate = json.optString("created_date", "") // Validate required fields (optString returns "null" for null values) val missingFields = mutableListOf() diff --git a/sentry-android-distribution/src/test/java/io/sentry/android/distribution/DistributionHttpClientTest.kt b/sentry-android-distribution/src/test/java/io/sentry/android/distribution/DistributionHttpClientTest.kt index d5e8b7702e..eb5c0f6f26 100644 --- a/sentry-android-distribution/src/test/java/io/sentry/android/distribution/DistributionHttpClientTest.kt +++ b/sentry-android-distribution/src/test/java/io/sentry/android/distribution/DistributionHttpClientTest.kt @@ -37,6 +37,7 @@ class DistributionHttpClientTest { appId = "com.emergetools.hackernews", versionName = "1.0.0", versionCode = 5L, + buildConfiguration = "release", ) val response = httpClient.checkForUpdates(params) diff --git a/sentry-android-distribution/src/test/java/io/sentry/android/distribution/UpdateResponseParserTest.kt b/sentry-android-distribution/src/test/java/io/sentry/android/distribution/UpdateResponseParserTest.kt index 1cefdfa7ac..473339d3b6 100644 --- a/sentry-android-distribution/src/test/java/io/sentry/android/distribution/UpdateResponseParserTest.kt +++ b/sentry-android-distribution/src/test/java/io/sentry/android/distribution/UpdateResponseParserTest.kt @@ -26,13 +26,15 @@ class UpdateResponseParserTest { val responseBody = """ { - "updateAvailable": true, - "id": "update-123", - "buildVersion": "2.0.0", - "buildNumber": 42, - "downloadUrl": "https://example.com/download", - "appName": "Test App", - "createdDate": "2023-10-01T00:00:00Z" + "update": { + "id": "update-123", + "build_version": "2.0.0", + "build_number": 42, + "download_url": "https://example.com/download", + "app_name": "Test App", + "created_date": "2023-10-01T00:00:00Z" + }, + "current": null } """ .trimIndent() @@ -54,7 +56,15 @@ class UpdateResponseParserTest { val responseBody = """ { - "updateAvailable": false + "update": null, + "current": { + "id": "current-123", + "build_version": "1.0.0", + "build_number": 10, + "download_url": "https://example.com/download", + "app_name": "Test App", + "created_date": "2023-09-01T00:00:00Z" + } } """ .trimIndent() @@ -65,11 +75,18 @@ class UpdateResponseParserTest { } @Test - fun `parseResponse returns UpToDate when updateAvailable is missing`() { + fun `parseResponse returns UpToDate when update is missing`() { val responseBody = """ { - "someOtherField": "value" + "current": { + "id": "current-123", + "build_version": "1.0.0", + "build_number": 10, + "download_url": "https://example.com/download", + "app_name": "Test App", + "created_date": "2023-09-01T00:00:00Z" + } } """ .trimIndent() @@ -123,8 +140,9 @@ class UpdateResponseParserTest { val responseBody = """ { - "updateAvailable": true, - "buildVersion": "2.0.0" + "update": { + "build_version": "2.0.0" + } } """ .trimIndent() @@ -144,10 +162,14 @@ class UpdateResponseParserTest { val responseBody = """ { - "updateAvailable": true, - "id": "update-123", - "buildVersion": "2.0.0", - "downloadUrl": "https://example.com/download" + "update": { + "id": "update-123", + "build_version": "2.0.0", + "build_number": 0, + "download_url": "https://example.com/download", + "app_name": "", + "created_date": "" + } } """ .trimIndent() @@ -181,10 +203,14 @@ class UpdateResponseParserTest { val responseBody = """ { - "updateAvailable": true, - "id": null, - "buildVersion": "2.0.0", - "downloadUrl": "https://example.com/download" + "update": { + "id": null, + "build_version": "2.0.0", + "build_number": 10, + "download_url": "https://example.com/download", + "app_name": "Test App", + "created_date": "2023-10-01T00:00:00Z" + } } """ .trimIndent() @@ -204,9 +230,13 @@ class UpdateResponseParserTest { val responseBody = """ { - "updateAvailable": true, - "buildVersion": "2.0.0", - "downloadUrl": "https://example.com/download" + "update": { + "build_version": "2.0.0", + "build_number": 10, + "download_url": "https://example.com/download", + "app_name": "Test App", + "created_date": "2023-10-01T00:00:00Z" + } } """ .trimIndent() @@ -226,9 +256,13 @@ class UpdateResponseParserTest { val responseBody = """ { - "updateAvailable": true, - "id": "update-123", - "downloadUrl": "https://example.com/download" + "update": { + "id": "update-123", + "build_number": 10, + "download_url": "https://example.com/download", + "app_name": "Test App", + "created_date": "2023-10-01T00:00:00Z" + } } """ .trimIndent() @@ -248,9 +282,13 @@ class UpdateResponseParserTest { val responseBody = """ { - "updateAvailable": true, - "id": "update-123", - "buildVersion": "2.0.0" + "update": { + "id": "update-123", + "build_version": "2.0.0", + "build_number": 10, + "app_name": "Test App", + "created_date": "2023-10-01T00:00:00Z" + } } """ .trimIndent() @@ -270,8 +308,11 @@ class UpdateResponseParserTest { val responseBody = """ { - "updateAvailable": true, - "buildNumber": 42 + "update": { + "build_number": 42, + "app_name": "Test App", + "created_date": "2023-10-01T00:00:00Z" + } } """ .trimIndent() @@ -293,10 +334,14 @@ class UpdateResponseParserTest { val responseBody = """ { - "updateAvailable": true, - "id": "null", - "buildVersion": "2.0.0", - "downloadUrl": "https://example.com/download" + "update": { + "id": "null", + "build_version": "2.0.0", + "build_number": 10, + "download_url": "https://example.com/download", + "app_name": "Test App", + "created_date": "2023-10-01T00:00:00Z" + } } """ .trimIndent() diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index 4bfa96f120..23b75e9aa0 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -4354,6 +4354,7 @@ public final class io/sentry/UpdateInfo { public fun getCreatedDate ()Ljava/lang/String; public fun getDownloadUrl ()Ljava/lang/String; public fun getId ()Ljava/lang/String; + public fun toString ()Ljava/lang/String; } public abstract class io/sentry/UpdateStatus { @@ -4363,20 +4364,24 @@ public abstract class io/sentry/UpdateStatus { public final class io/sentry/UpdateStatus$NewRelease : io/sentry/UpdateStatus { public fun (Lio/sentry/UpdateInfo;)V public fun getInfo ()Lio/sentry/UpdateInfo; + public fun toString ()Ljava/lang/String; } public final class io/sentry/UpdateStatus$NoNetwork : io/sentry/UpdateStatus { public fun (Ljava/lang/String;)V public fun getMessage ()Ljava/lang/String; + public fun toString ()Ljava/lang/String; } public final class io/sentry/UpdateStatus$UpToDate : io/sentry/UpdateStatus { public static fun getInstance ()Lio/sentry/UpdateStatus$UpToDate; + public fun toString ()Ljava/lang/String; } public final class io/sentry/UpdateStatus$UpdateError : io/sentry/UpdateStatus { public fun (Ljava/lang/String;)V public fun getMessage ()Ljava/lang/String; + public fun toString ()Ljava/lang/String; } public final class io/sentry/UserFeedback : io/sentry/JsonSerializable, io/sentry/JsonUnknown { diff --git a/sentry/src/main/java/io/sentry/UpdateInfo.java b/sentry/src/main/java/io/sentry/UpdateInfo.java index 66a5452191..ec9ee3b66d 100644 --- a/sentry/src/main/java/io/sentry/UpdateInfo.java +++ b/sentry/src/main/java/io/sentry/UpdateInfo.java @@ -52,4 +52,27 @@ public int getBuildNumber() { public @Nullable String getCreatedDate() { return createdDate; } + + @Override + public String toString() { + return "UpdateInfo{" + + "id='" + + id + + '\'' + + ", buildVersion='" + + buildVersion + + '\'' + + ", buildNumber=" + + buildNumber + + ", downloadUrl='" + + downloadUrl + + '\'' + + ", appName='" + + appName + + '\'' + + ", createdDate='" + + createdDate + + '\'' + + '}'; + } } diff --git a/sentry/src/main/java/io/sentry/UpdateStatus.java b/sentry/src/main/java/io/sentry/UpdateStatus.java index c7c14ca68c..69293abf9a 100644 --- a/sentry/src/main/java/io/sentry/UpdateStatus.java +++ b/sentry/src/main/java/io/sentry/UpdateStatus.java @@ -16,6 +16,11 @@ private UpToDate() {} public static UpToDate getInstance() { return INSTANCE; } + + @Override + public String toString() { + return "UpdateStatus.UpToDate{}"; + } } /** A new release is available for download. */ @@ -29,6 +34,11 @@ public NewRelease(final @NotNull UpdateInfo info) { public @NotNull UpdateInfo getInfo() { return info; } + + @Override + public String toString() { + return "UpdateStatus.NewRelease{" + "info=" + info + '}'; + } } /** An error occurred during the update check. */ @@ -42,6 +52,11 @@ public UpdateError(final @NotNull String message) { public @NotNull String getMessage() { return message; } + + @Override + public String toString() { + return "UpdateStatus.UpdateError{" + "message='" + message + '\'' + '}'; + } } /** No network connection is available to check for updates. */ @@ -55,5 +70,10 @@ public NoNetwork(final @NotNull String message) { public @NotNull String getMessage() { return message; } + + @Override + public String toString() { + return "UpdateStatus.NoNetwork{" + "message='" + message + '\'' + '}'; + } } }