From 9700e9cc92f1edfc7b09e7b200a3eeda731e408a Mon Sep 17 00:00:00 2001 From: Moe Hamade <69801237+moehamade@users.noreply.github.com> Date: Fri, 24 Jul 2026 19:46:23 +0300 Subject: [PATCH] fix: Allow sharing when the GitHub release lags the installed version Upstream bumps versionName in main before tagging the GitHub release, so there is a recurring window where the installed app is newer than the latest published universal APK. The hard version guard disabled the whole sharing feature during that window (including for reviewers building this branch at 1.7.5 while GitHub's latest is 1.7.4). An older release is still a genuine, signed, checksum-verified universal artifact, and Android already refuses downgrade installs on receivers, so: - checkForUpdate now logs (instead of erroring) when the latest release is older than the installed app and proceeds normally. - downloadUniversalApk no longer fails for an older-than-installed release. - A cached artifact stays shareable regardless of the installed version. The cached-artifact preference (never replace a newer cached APK with an older one) and all signature/checksum verification are unchanged. Co-Authored-By: Claude Fable 5 --- .../android/ui/ApkDownloadViewModel.kt | 4 ++- .../android/util/UniversalApkManager.kt | 35 ++++++------------- 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/com/bitchat/android/ui/ApkDownloadViewModel.kt b/app/src/main/java/com/bitchat/android/ui/ApkDownloadViewModel.kt index 73393a30..0b4e0005 100644 --- a/app/src/main/java/com/bitchat/android/ui/ApkDownloadViewModel.kt +++ b/app/src/main/java/com/bitchat/android/ui/ApkDownloadViewModel.kt @@ -309,8 +309,10 @@ class ApkDownloadViewModel(application: Application) : AndroidViewModel(applicat ) } is UniversalApkManager.UpdateStatus.Error -> { + // A cached artifact stays shareable even when the update + // check fails or the release lags the installed version. val info = apkManager.getCachedApkInfo() - if (info != null && apkManager.isCompatibleWithInstalledVersion(info.version)) { + if (info != null) { ApkPreparationStatus.Ready( version = info.version, sizeMB = (info.size / 1024 / 1024).toInt(), diff --git a/app/src/main/java/com/bitchat/android/util/UniversalApkManager.kt b/app/src/main/java/com/bitchat/android/util/UniversalApkManager.kt index b332c778..54cfc891 100644 --- a/app/src/main/java/com/bitchat/android/util/UniversalApkManager.kt +++ b/app/src/main/java/com/bitchat/android/util/UniversalApkManager.kt @@ -129,23 +129,21 @@ class UniversalApkManager(private val context: Context) { } val cachedInfo = getCachedApkInfo() - val cachedApkIsOlder = cachedInfo?.let { - isOlderThanInstalledVersion(it.version) - } == true val latestRelease = GitHubReleaseClient.fetchLatestRelease().getOrElse { error -> return@withContext UpdateStatus.Error( - if (cachedApkIsOlder) { - "Cached sharing APK ${cachedInfo?.version} is older than installed app " + - "${installedVersionName()}, and a newer GitHub release could not be checked." - } else { - error.message ?: "Failed to fetch latest release from GitHub" - } + error.message ?: "Failed to fetch latest release from GitHub" ) } + // The GitHub release may briefly lag behind the installed version + // (upstream bumps versionName in main before tagging the release). + // An older release is still a genuine, signed, universal artifact — + // recipients with a newer install can't be downgraded by Android + // anyway — so share it rather than disabling the feature. if (isOlderThanInstalledVersion(latestRelease.versionName)) { - return@withContext UpdateStatus.Error( - "GitHub universal APK ${latestRelease.versionName} is older than installed app " + - "${installedVersionName()}. Wait for the matching GitHub release." + Log.i( + TAG, + "GitHub universal APK ${latestRelease.versionName} is older than installed " + + "app ${installedVersionName()}; sharing it until the matching release ships" ) } @@ -208,15 +206,6 @@ class UniversalApkManager(private val context: Context) { val release = GitHubReleaseClient.fetchLatestRelease().getOrElse { error -> return@withContext Result.failure(error) } - if (isOlderThanInstalledVersion(release.versionName)) { - return@withContext Result.failure( - GitHubReleaseClient.ReleaseFetchException( - message = "GitHub universal APK ${release.versionName} is older than " + - "installed app ${installedVersionName()}", - retryable = false - ) - ) - } if (!GitHubReleaseClient.awaitSelectedNetworkRoute()) { return@withContext Result.failure( @@ -494,10 +483,6 @@ class UniversalApkManager(private val context: Context) { return GitHubReleaseClient.isNewerVersion(candidateVersion, installedVersionName()) } - fun isCompatibleWithInstalledVersion(candidateVersion: String): Boolean { - return !isOlderThanInstalledVersion(candidateVersion) - } - /** * Verify the downloaded APK against either the running app's signing lineage * or the pinned GitHub release certificate. The latter supports Play installs