From 1f13be3226d8fddcf50da00cbe14c7534ae27b54 Mon Sep 17 00:00:00 2001 From: Hector Date: Wed, 9 Oct 2024 16:54:07 +0100 Subject: [PATCH] Build distribution add initial API --- .../distribution/src/main/AndroidManifest.xml | 4 ++ .../emergetools/distribution/Distribution.kt | 44 +++++++++--- .../internal/DistributionInternal.kt | 71 ++++++++++++++++--- 3 files changed, 99 insertions(+), 20 deletions(-) diff --git a/distribution/distribution/src/main/AndroidManifest.xml b/distribution/distribution/src/main/AndroidManifest.xml index db0eb73b..84e039d7 100644 --- a/distribution/distribution/src/main/AndroidManifest.xml +++ b/distribution/distribution/src/main/AndroidManifest.xml @@ -9,6 +9,10 @@ + + tryDecode(s: String): T? { return try { Json.decodeFromString(s) @@ -46,6 +64,11 @@ private fun decodeResult(body: String?): UpdateStatus { return UpdateStatus.Error("Empty response from server") } + val success = tryDecode(body) + if (success !== null) { + return UpdateStatus.NewRelease(success.updateInfo) + } + val message = tryDecode(body) if (message !== null) { return UpdateStatus.Error(message.message) @@ -54,7 +77,12 @@ private fun decodeResult(body: String?): UpdateStatus { return UpdateStatus.Error("Unexpected response $body") } -private class State(val handler: Handler, private var okHttpClient: OkHttpClient?) { +private class State( + val handler: Handler, + val tag: String, + val apiKey: String?, + private var okHttpClient: OkHttpClient? +) { @Synchronized fun getOkHttpClient(): OkHttpClient { @@ -71,7 +99,6 @@ object DistributionInternal { private var state: State? = null @Synchronized - @Suppress("unused") fun init(context: Context, options: DistributionOptions) { if (state != null) { Log.e(TAG, "Distribution already initialized, ignoring Distribution.init().") @@ -85,7 +112,17 @@ object DistributionInternal { } val handler = Handler(looper) - state = State(handler, options.okHttpClient) + + // apiKey may be null if + val metaData = context.packageManager.getApplicationInfo( + context.packageName, + PackageManager.GET_META_DATA + ).metaData + val apiKey = getApiKey(metaData) + + val tag = options.tag ?: "release" + + state = State(handler, tag, apiKey, options.okHttpClient) } private fun getState(): State? { @@ -96,29 +133,41 @@ object DistributionInternal { return theState } - suspend fun checkForUpdate(context: Context, apiKey: String?): UpdateStatus { + suspend fun checkForUpdate(context: Context): UpdateStatus { try { val state = getState() if (state == null) { Log.e(TAG, "Build distribution not initialized") return UpdateStatus.Error("Build distribution not initialized") } - if (apiKey == null) { - Log.e(TAG, "No API key available") - return UpdateStatus.Error("No API key available") - } - return doCheckForUpdate(context, state, apiKey) + return doCheckForUpdate(context, state) } catch (e: Exception) { Log.e(TAG, "Error: $e") return UpdateStatus.Error("Error: $e") } } + + @Suppress("unused") + fun isEnabled(context: Context): Boolean { + try { + val state = getState() + return state?.apiKey != null + } catch (e: Exception) { + Log.e(TAG, "Error: $e") + return false + } + } } @OptIn(ExperimentalCoroutinesApi::class) -private suspend fun doCheckForUpdate(context: Context, state: State, apiKey: String): UpdateStatus { +private suspend fun doCheckForUpdate(context: Context, state: State): UpdateStatus { // Despite the name context.packageName is the actually the application id. val applicationId = context.packageName + val apiKey = state.apiKey + if (apiKey == null) { + Log.e(TAG, "No API key available") + return UpdateStatus.Error("No API key available") + } val url = HttpUrl.Builder().apply { scheme("https") @@ -126,7 +175,7 @@ private suspend fun doCheckForUpdate(context: Context, state: State, apiKey: Str addPathSegment("distribution") addPathSegment("checkForUpdates") addQueryParameter("apiKey", apiKey) - addQueryParameter("binaryIdentifier", "polar bears") + addQueryParameter("tag", state.tag) addQueryParameter("appId", applicationId) addQueryParameter("platform", "android") }.build()