diff --git a/README.md b/README.md index 2ecbbfc..ba2c0a3 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,8 @@ APIs directly: and kill session through HTTP API - open one live terminal viewer through `/ws/terminal` - native `/ws/events` listener for session invalidation and hook notifications -- selectable GitHub or Gitea update manifest source +- selectable Gitea or GitHub update source, defaulting to Gitea for mobile + reachability - native Tools page for health, server status, timeline, preferences, hook events, image file/URL upload, image preview info, and native image preview display @@ -93,10 +94,10 @@ https://github.com/neatstudio/tmux-browser-android/releases/latest/download/tmux https://github.com/neatstudio/tmux-browser-android/releases/latest/download/latest.json ``` -Those GitHub links are the primary public install/update channel. Gitea releases -are mirrored as a second public source. This Gitea instance does not support the -GitHub-style `/releases/latest/download/...` URL, so the app uses the Gitea -Release API as the stable Gitea update entrypoint. +Gitea is the app's default install/update channel because phones may not be able +to reach GitHub reliably. GitHub remains an optional public source. This Gitea +instance does not support the GitHub-style `/releases/latest/download/...` URL, +so the app uses the Gitea Release API as the stable Gitea update entrypoint. Plain branch builds only create Actions artifacts; they are useful for CI verification, but releases are the stable download/update channel. @@ -146,28 +147,24 @@ release manifest automatically, downloads the newer APK, verifies its SHA-256, then opens Android's package installer. The user still has to approve the install, and Android 8+ may require allowing this app to install unknown apps. -The default update manifest is: +The default update source is the Gitea Release API: + +```text +https://gitea.neatcn.com/api/v1/repos/tmux/tmux-browser-android/releases/latest +``` + +The default source resolves `latest.json` and `tmux-android.apk` from Gitea +release assets, so APK downloads do not require GitHub. The optional GitHub +manifest is: ```text https://github.com/neatstudio/tmux-browser-android/releases/latest/download/latest.json ``` -The public manual APK download is: - -```text -https://github.com/neatstudio/tmux-browser-android/releases/latest/download/tmux-android.apk -``` - The app checks only the selected update source. It does not probe GitHub and Gitea during the same update check. Choose the source in the app's `Update` page, or use a custom manifest/API URL. -The built-in Gitea API endpoint is: - -```text -https://gitea.neatcn.com/api/v1/repos/tmux/tmux-browser-android/releases/latest -``` - Gitea tag-specific assets are also public, for example: ```text diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f97c576..8673dd9 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -9,6 +9,8 @@ val repoSlug = providers.gradleProperty("repoSlug") val defaultServerUrl = providers.gradleProperty("defaultServerUrl") .orElse("http://100.89.0.116:3000") val defaultUpdateUrl = providers.gradleProperty("defaultUpdateUrl") + .orElse("https://gitea.neatcn.com/api/v1/repos/tmux/tmux-browser-android/releases/latest") +val defaultGithubUpdateUrl = providers.gradleProperty("defaultGithubUpdateUrl") .orElse("https://github.com/${repoSlug.get()}/releases/latest/download/latest.json") val defaultGiteaUpdateUrl = providers.gradleProperty("defaultGiteaUpdateUrl") .orElse("https://gitea.neatcn.com/api/v1/repos/tmux/tmux-browser-android/releases/latest") @@ -36,6 +38,7 @@ android { buildConfigField("String", "DEFAULT_SERVER_URL", "\"${defaultServerUrl.get()}\"") buildConfigField("String", "DEFAULT_UPDATE_URL", "\"${defaultUpdateUrl.get()}\"") + buildConfigField("String", "DEFAULT_GITHUB_UPDATE_URL", "\"${defaultGithubUpdateUrl.get()}\"") buildConfigField("String", "DEFAULT_GITEA_UPDATE_URL", "\"${defaultGiteaUpdateUrl.get()}\"") buildConfigField("String", "DEFAULT_APK_URL", "\"${defaultApkUrl.get()}\"") buildConfigField("String", "DEFAULT_RELEASE_PAGE_URL", "\"${defaultReleasePageUrl.get()}\"") diff --git a/app/src/main/java/com/neatstudio/tmuxandroid/MainActivity.java b/app/src/main/java/com/neatstudio/tmuxandroid/MainActivity.java index 64cf862..53e7b0d 100644 --- a/app/src/main/java/com/neatstudio/tmuxandroid/MainActivity.java +++ b/app/src/main/java/com/neatstudio/tmuxandroid/MainActivity.java @@ -60,6 +60,7 @@ public final class MainActivity extends Activity { private static final int MAX_TERMINAL_CHARS = 40_000; private static final long TERMINAL_RENDER_INTERVAL_MS = 80L; private static final String OLD_LOCAL_DEFAULT_URL = "http://127.0.0.1:3000"; + private static final String OLD_GITHUB_DEFAULT_UPDATE_URL = "https://github.com/neatstudio/tmux-browser-android/releases/latest/download/latest.json"; private static final String DEFAULT_TAILSCALE_URL = "http://100.89.0.116:3000"; private static final String PAGE_SESSIONS = "Sessions"; private static final String PAGE_PROJECTS = "Projects"; @@ -116,6 +117,7 @@ public final class MainActivity extends Activity { .putBoolean("tailscale_defaults_applied_v1", true) .apply(); } + migrateDefaultUpdateSourceToGitea(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { getWindow().setStatusBarColor(Color.rgb(17, 20, 24)); getWindow().setNavigationBarColor(Color.rgb(17, 20, 24)); @@ -1438,8 +1440,8 @@ public final class MainActivity extends Activity { .append(prefs.getString("update_url", BuildConfig.DEFAULT_UPDATE_URL)) .append('\n'); text.append("Available sources:\n"); - text.append("GitHub: ").append(BuildConfig.DEFAULT_UPDATE_URL).append('\n'); - text.append("Gitea: ").append(BuildConfig.DEFAULT_GITEA_UPDATE_URL).append('\n'); + text.append("Gitea default: ").append(BuildConfig.DEFAULT_GITEA_UPDATE_URL).append('\n'); + text.append("GitHub optional: ").append(BuildConfig.DEFAULT_GITHUB_UPDATE_URL).append('\n'); text.append('\n'); text.append(permissionSummary()); @@ -1476,17 +1478,17 @@ public final class MainActivity extends Activity { private void showUpdateSourcePicker() { String[] items = { - "GitHub: " + BuildConfig.DEFAULT_UPDATE_URL, - "Gitea: " + BuildConfig.DEFAULT_GITEA_UPDATE_URL, + "Gitea default: " + BuildConfig.DEFAULT_GITEA_UPDATE_URL, + "GitHub optional: " + BuildConfig.DEFAULT_GITHUB_UPDATE_URL, "Custom URL" }; new AlertDialog.Builder(this) .setTitle("Update source") .setItems(items, (dialog, which) -> { if (which == 0) { - setUpdateUrl(BuildConfig.DEFAULT_UPDATE_URL); - } else if (which == 1) { setUpdateUrl(BuildConfig.DEFAULT_GITEA_UPDATE_URL); + } else if (which == 1) { + setUpdateUrl(BuildConfig.DEFAULT_GITHUB_UPDATE_URL); } else { promptText("Custom update manifest", "https://.../latest.json", prefs.getString("update_url", BuildConfig.DEFAULT_UPDATE_URL), this::setUpdateUrl); } @@ -1504,6 +1506,15 @@ public final class MainActivity extends Activity { } } + private void migrateDefaultUpdateSourceToGitea() { + String current = prefs.getString("update_url", ""); + if (current == null || current.trim().isEmpty() || OLD_GITHUB_DEFAULT_UPDATE_URL.equals(current.trim())) { + prefs.edit() + .putString("update_url", BuildConfig.DEFAULT_GITEA_UPDATE_URL) + .apply(); + } + } + private void probeServerProfiles() { progressBar.setVisibility(View.VISIBLE); setStatus("Probing Tailscale APIs..."); diff --git a/docs/android-client-notes.md b/docs/android-client-notes.md index c706055..3b11d99 100644 --- a/docs/android-client-notes.md +++ b/docs/android-client-notes.md @@ -87,7 +87,7 @@ Implemented now: preview display - GitHub Actions APK build - release manifest `latest.json` -- selected-source update checks; GitHub and Gitea are not probed in the same +- selected-source update checks; Gitea and GitHub are not probed in the same update check - one-download-per-version APK cache, SHA-256 verification, and installer handoff @@ -102,10 +102,10 @@ open Android's package installer, but the user must approve the install. On Android 8+, the user may also need to allow this app to install unknown apps. The app checks exactly one update source per run: the selected manifest/API URL. -GitHub is the default public source. Gitea is available as a public mirror, but -the app does not fall back across both providers during a normal check. This -keeps update behavior predictable on mobile networks and avoids duplicate -provider checks. +Gitea is the default public source because phones may not reach GitHub reliably. +GitHub is available as an optional public source, but the app does not fall back +across both providers during a normal check. This keeps update behavior +predictable on mobile networks and avoids duplicate provider checks. Downloaded APKs are cached by `versionCode`. If a cached APK exists and its SHA-256 matches the manifest, the app reuses it instead of downloading the same