Default updates to Gitea
All checks were successful
Gitea Smoke / smoke (push) Successful in 0s
Gitea Android APK / build (push) Successful in 11m48s

This commit is contained in:
Codex 2026-07-07 01:37:18 +00:00
parent dd056c8027
commit 72913c5571
4 changed files with 40 additions and 29 deletions

View File

@ -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

View File

@ -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()}\"")

View File

@ -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...");

View File

@ -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