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 and kill session through HTTP API
- open one live terminal viewer through `/ws/terminal` - open one live terminal viewer through `/ws/terminal`
- native `/ws/events` listener for session invalidation and hook notifications - 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 - native Tools page for health, server status, timeline, preferences, hook
events, image file/URL upload, image preview info, and native image preview events, image file/URL upload, image preview info, and native image preview
display 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 https://github.com/neatstudio/tmux-browser-android/releases/latest/download/latest.json
``` ```
Those GitHub links are the primary public install/update channel. Gitea releases Gitea is the app's default install/update channel because phones may not be able
are mirrored as a second public source. This Gitea instance does not support the to reach GitHub reliably. GitHub remains an optional public source. This Gitea
GitHub-style `/releases/latest/download/...` URL, so the app uses the Gitea instance does not support the GitHub-style `/releases/latest/download/...` URL,
Release API as the stable Gitea update entrypoint. 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 Plain branch builds only create Actions artifacts; they are useful for CI
verification, but releases are the stable download/update channel. 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 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. 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 ```text
https://github.com/neatstudio/tmux-browser-android/releases/latest/download/latest.json 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 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` Gitea during the same update check. Choose the source in the app's `Update`
page, or use a custom manifest/API URL. 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: Gitea tag-specific assets are also public, for example:
```text ```text

View File

@ -9,6 +9,8 @@ val repoSlug = providers.gradleProperty("repoSlug")
val defaultServerUrl = providers.gradleProperty("defaultServerUrl") val defaultServerUrl = providers.gradleProperty("defaultServerUrl")
.orElse("http://100.89.0.116:3000") .orElse("http://100.89.0.116:3000")
val defaultUpdateUrl = providers.gradleProperty("defaultUpdateUrl") 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") .orElse("https://github.com/${repoSlug.get()}/releases/latest/download/latest.json")
val defaultGiteaUpdateUrl = providers.gradleProperty("defaultGiteaUpdateUrl") val defaultGiteaUpdateUrl = providers.gradleProperty("defaultGiteaUpdateUrl")
.orElse("https://gitea.neatcn.com/api/v1/repos/tmux/tmux-browser-android/releases/latest") .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_SERVER_URL", "\"${defaultServerUrl.get()}\"")
buildConfigField("String", "DEFAULT_UPDATE_URL", "\"${defaultUpdateUrl.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_GITEA_UPDATE_URL", "\"${defaultGiteaUpdateUrl.get()}\"")
buildConfigField("String", "DEFAULT_APK_URL", "\"${defaultApkUrl.get()}\"") buildConfigField("String", "DEFAULT_APK_URL", "\"${defaultApkUrl.get()}\"")
buildConfigField("String", "DEFAULT_RELEASE_PAGE_URL", "\"${defaultReleasePageUrl.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 int MAX_TERMINAL_CHARS = 40_000;
private static final long TERMINAL_RENDER_INTERVAL_MS = 80L; 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_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 DEFAULT_TAILSCALE_URL = "http://100.89.0.116:3000";
private static final String PAGE_SESSIONS = "Sessions"; private static final String PAGE_SESSIONS = "Sessions";
private static final String PAGE_PROJECTS = "Projects"; private static final String PAGE_PROJECTS = "Projects";
@ -116,6 +117,7 @@ public final class MainActivity extends Activity {
.putBoolean("tailscale_defaults_applied_v1", true) .putBoolean("tailscale_defaults_applied_v1", true)
.apply(); .apply();
} }
migrateDefaultUpdateSourceToGitea();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setStatusBarColor(Color.rgb(17, 20, 24)); getWindow().setStatusBarColor(Color.rgb(17, 20, 24));
getWindow().setNavigationBarColor(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(prefs.getString("update_url", BuildConfig.DEFAULT_UPDATE_URL))
.append('\n'); .append('\n');
text.append("Available sources:\n"); text.append("Available sources:\n");
text.append("GitHub: ").append(BuildConfig.DEFAULT_UPDATE_URL).append('\n'); text.append("Gitea default: ").append(BuildConfig.DEFAULT_GITEA_UPDATE_URL).append('\n');
text.append("Gitea: ").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('\n');
text.append(permissionSummary()); text.append(permissionSummary());
@ -1476,17 +1478,17 @@ public final class MainActivity extends Activity {
private void showUpdateSourcePicker() { private void showUpdateSourcePicker() {
String[] items = { String[] items = {
"GitHub: " + BuildConfig.DEFAULT_UPDATE_URL, "Gitea default: " + BuildConfig.DEFAULT_GITEA_UPDATE_URL,
"Gitea: " + BuildConfig.DEFAULT_GITEA_UPDATE_URL, "GitHub optional: " + BuildConfig.DEFAULT_GITHUB_UPDATE_URL,
"Custom URL" "Custom URL"
}; };
new AlertDialog.Builder(this) new AlertDialog.Builder(this)
.setTitle("Update source") .setTitle("Update source")
.setItems(items, (dialog, which) -> { .setItems(items, (dialog, which) -> {
if (which == 0) { if (which == 0) {
setUpdateUrl(BuildConfig.DEFAULT_UPDATE_URL);
} else if (which == 1) {
setUpdateUrl(BuildConfig.DEFAULT_GITEA_UPDATE_URL); setUpdateUrl(BuildConfig.DEFAULT_GITEA_UPDATE_URL);
} else if (which == 1) {
setUpdateUrl(BuildConfig.DEFAULT_GITHUB_UPDATE_URL);
} else { } else {
promptText("Custom update manifest", "https://.../latest.json", prefs.getString("update_url", BuildConfig.DEFAULT_UPDATE_URL), this::setUpdateUrl); 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() { private void probeServerProfiles() {
progressBar.setVisibility(View.VISIBLE); progressBar.setVisibility(View.VISIBLE);
setStatus("Probing Tailscale APIs..."); setStatus("Probing Tailscale APIs...");

View File

@ -87,7 +87,7 @@ Implemented now:
preview display preview display
- GitHub Actions APK build - GitHub Actions APK build
- release manifest `latest.json` - 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 update check
- one-download-per-version APK cache, SHA-256 verification, and installer - one-download-per-version APK cache, SHA-256 verification, and installer
handoff 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. 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. 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 Gitea is the default public source because phones may not reach GitHub reliably.
the app does not fall back across both providers during a normal check. This GitHub is available as an optional public source, but the app does not fall back
keeps update behavior predictable on mobile networks and avoids duplicate across both providers during a normal check. This keeps update behavior
provider checks. predictable on mobile networks and avoids duplicate provider checks.
Downloaded APKs are cached by `versionCode`. If a cached APK exists and its 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 SHA-256 matches the manifest, the app reuses it instead of downloading the same