🏗️ Build and Test JellyTau / Run Tests (push) Successful in 25m52s
🏗️ Build and Test JellyTau / Supply Chain (push) Successful in 46s
📱 Test APK / Build test APK (push) Failing after 1m14s
Publish Documentation / Build & publish docs to gitea-pages (push) Successful in 7m54s
Traceability Validation / Check Requirement Traces (push) Successful in 18s
🏗️ Build and Test JellyTau / Android Compile Check (push) Successful in 6m26s
The test-APK workflow was dispatch-only, so merging to master produced no APK at all -- there was nothing to hand a tester without pressing a button first, which is not what a "latest build" means. Pushes to master now refresh a `latest` pre-release in place. Both the tag and the asset name are stable, so the download URL never changes and a link given to a tester once keeps serving the current build. Release assets are public; Actions artifacts need an account, which is what made them useless for this. It stays the side-by-side variant: R8-minified like a real release, so it still exercises the minification that has broken Android builds here before, but signed with the debug keystore under the `.debug` applicationId. A bad master commit therefore cannot replace anyone's working install, and the production signing key stays in the tag-driven release workflow. Event handling is resolved in one step rather than read raw at each use. A push carries no dispatch inputs -- every `github.event.inputs.*` is empty on that event -- so the variant and ABI need real defaults, and the publish decision differs by event. Doing it once means the build, collect and publish steps cannot disagree about what the run is. Known gap, documented rather than hidden: this builds in parallel with build-and-test.yml, so `latest` can carry a commit whose tests later fail. Cross-workflow dependencies are not reliably available here and duplicating the test job would double an already hour-long queue on a single-slot runner.
156 lines
6.9 KiB
Markdown
156 lines
6.9 KiB
Markdown
# ⚠️ IMPORTANT: Android Build File Locations
|
|
|
|
## Critical Information for Future Development
|
|
|
|
**DO NOT EDIT FILES IN `src-tauri/gen/android/` DIRECTLY!**
|
|
|
|
### File Structure
|
|
|
|
This project has **TWO** sets of Android source files:
|
|
|
|
1. **`src-tauri/android/`** - **SOURCE FILES** (edit these!)
|
|
- This is the template directory
|
|
- Changes here need to be copied to the generated directory
|
|
|
|
2. **`src-tauri/gen/android/`** - **GENERATED BUILD DIRECTORY** (do not edit directly!)
|
|
- This is where Gradle actually builds the APK
|
|
- Files here may be overwritten during builds
|
|
|
|
### How to Make Changes to Android Code
|
|
|
|
When you need to modify Android/Kotlin files:
|
|
|
|
1. **Edit the files in `src-tauri/android/src/main/java/`**
|
|
2. **Build using the provided script (which auto-syncs files)**
|
|
```bash
|
|
./scripts/build-android.sh
|
|
```
|
|
|
|
The build script automatically runs `./scripts/sync-android-sources.sh` which copies:
|
|
- `src-tauri/android/src/main/java/com/dtourolle/jellytau/player/` → generated directory
|
|
- `src-tauri/android/src/main/java/com/dtourolle/jellytau/security/` → generated directory
|
|
|
|
3. **Manual sync (if needed)**
|
|
```bash
|
|
./scripts/sync-android-sources.sh
|
|
```
|
|
|
|
### Why This Matters
|
|
|
|
- If you only edit `src-tauri/gen/android/`, your changes will be lost
|
|
- If you only edit `src-tauri/android/`, your changes won't be in the build
|
|
- **You must edit both** (or edit source and copy to generated)
|
|
|
|
### Debug and release install side by side
|
|
|
|
The **debug** build type sets `applicationIdSuffix = ".debug"` in
|
|
`app/build.gradle.kts`, so a debug build is a genuinely separate Android app:
|
|
|
|
| build | applicationId | launcher name | versionName | signed with |
|
|
|---|---|---|---|---|
|
|
| `release` | `com.dtourolle.jellytau` | jellytau | `0.5.5` | real key (`.env`) |
|
|
| `release --debug` | `com.dtourolle.jellytau.debug` | JellyTau Debug | `0.5.5-debug-release` | debug keystore |
|
|
| `debug` | `com.dtourolle.jellytau.debug` | JellyTau Debug | `0.5.5-debug` | debug keystore |
|
|
|
|
`release --debug` is the **side-by-side release**: fully R8-minified, exactly
|
|
what ships, but packaged into the debug slot and signed with the local debug
|
|
keystore. It exists because R8 has broken release APKs here before (stripping
|
|
JNI-loaded player/security classes), and reproducing that previously meant
|
|
building with the real key and clobbering your working install. It shares the
|
|
applicationId *and* signature with the plain debug build, so the two replace
|
|
each other cleanly; only the versionName suffix tells you which is installed.
|
|
|
|
```bash
|
|
./scripts/build-and-deploy.sh release --device --debug # build + install it
|
|
```
|
|
|
|
The flag is plumbed through as `JT_SIDE_BY_SIDE=1`, read by `build.gradle.kts`.
|
|
CI never sets it, so distributable release builds are untouched.
|
|
|
|
That means:
|
|
|
|
- **No uninstall step.** Debug builds are signed with the local auto-generated
|
|
`~/.android/debug.keystore`, release builds with the real key. Two different
|
|
keys on the *same* package is `INSTALL_FAILED_UPDATE_INCOMPATIBLE`; two
|
|
different packages is just two apps.
|
|
- Each has **its own data directory** — separate settings, credentials,
|
|
downloads and offline cache. A debug experiment cannot corrupt the state of
|
|
the build you actually use. This is not optional and cannot be shared:
|
|
Android gives each applicationId its own UID and enforces the boundary in the
|
|
kernel. (`sharedUserId` is deprecated since API 29 and cannot be added to an
|
|
already-installed app anyway.) You log in again in the debug app, once.
|
|
- Only the *application* id changes. Kotlin classes stay in the `namespace`
|
|
package `com.dtourolle.jellytau`, so the JNI class lookups in
|
|
`src-tauri/src/player/android/mod.rs`, the manifest `<service>` entry and the
|
|
R8 keep rules in `proguard-jellytau.pro` are all unaffected. The FileProvider
|
|
authority is `${applicationId}.fileprovider`, so it follows the suffix
|
|
automatically.
|
|
- The launcher labels come from the `appLabel` / `activityLabel`
|
|
manifestPlaceholders (`AndroidManifest.xml` uses `${appLabel}`), *not* from
|
|
`resValue`, which would collide with Tauri's generated `strings.xml`.
|
|
|
|
Follow the right log stream with `./scripts/logcat.sh [debug|release]`
|
|
(defaults to debug).
|
|
|
|
### Getting a test APK out of CI
|
|
|
|
`.gitea/workflows/build-test-apk.yml` produces installable APKs that are **not
|
|
releases**. Two ways in:
|
|
|
|
| Trigger | Result |
|
|
|---------|--------|
|
|
| **push to `master`** | Refreshes the rolling **`latest`** pre-release automatically |
|
|
| **`workflow_dispatch`** | Builds any branch on demand; optionally publishes it as `test-<branch>` |
|
|
|
|
#### The rolling `latest` build
|
|
|
|
Every push to `master` (bar doc-only ones) rebuilds and replaces the APK on the
|
|
`latest` pre-release. Both the tag and the asset name are stable, so the
|
|
download URL never changes:
|
|
|
|
```
|
|
https://gitea.tourolle.paris/dtourolle/jellytau/releases/download/latest/jellytau-latest.apk
|
|
```
|
|
|
|
Send that link to a tester once and it keeps serving the current build. No
|
|
account needed — release assets are public, unlike Actions artifacts.
|
|
|
|
#### What you get, and why it is safe
|
|
|
|
Both variants install into the `com.dtourolle.jellytau.debug` slot:
|
|
|
|
| Variant | What it is | When |
|
|
|---------|-----------|------|
|
|
| `side-by-side-release` (default, and what `latest` always is) | R8-minified, exactly what ships, signed with the **debug** keystore | Almost always — a plain debug build cannot catch R8 stripping JNI-loaded classes, which has broken release APKs here before |
|
|
| `debug` | Unminified | When you need readable stack traces |
|
|
|
|
Three properties make an automatic build on every master push safe:
|
|
|
|
- **It cannot replace a real install.** The applicationId is suffixed `.debug`,
|
|
so it sits beside the store build with its own data. A broken master commit
|
|
can never take out somebody's working app.
|
|
- **The production signing key is not involved.** That stays in the tag-driven
|
|
`build-release.yml`. This workflow needs no secrets beyond the API token.
|
|
- **The tag is `latest`/`test-*`, never `v*`.** Only `v*` triggers
|
|
`build-release.yml`. And the desktop updater reads a static `latest.json` from
|
|
the `updater` branch rather than the release list, so nothing here is offered
|
|
to existing users.
|
|
|
|
**Known gap:** the APK builds in parallel with `build-and-test.yml`, not after
|
|
it, so `latest` can carry a commit whose tests later fail. Cross-workflow
|
|
dependencies are not reliably available here, and duplicating the test job would
|
|
double an already hour-long queue on a single-slot runner. Check the commit's
|
|
CI status before handing the link to somebody.
|
|
|
|
Runs are serialised and `cancel-in-progress` is on, so a burst of pushes to
|
|
master collapses into one build rather than one per commit.
|
|
|
|
### Key Files
|
|
|
|
Player-related Kotlin files:
|
|
- `player/JellyTauPlayer.kt` - Main player implementation
|
|
- `player/JellyTauPlaybackService.kt` - MediaSession service for lockscreen controls
|
|
- `security/SecureStorage.kt` - Android Keystore integration for secure credential storage
|
|
|
|
Always check BOTH locations exist and match after making changes!
|