3 Commits
Author SHA1 Message Date
florian df7bb5e181 Added Android Permissions
Build Android Apk / android (release) Successful in 11m5s
Build Linux Application / linux (release) Successful in 4m57s
Publish Docker Image / docker (release) Successful in 13m50s
2026-09-07 15:23:52 +02:00
florian e8598a2e43 Set the Repository Owner to LocPac 2026-09-07 15:05:24 +02:00
florian ea5e5592a8 Fixed a Build Issue
Build Android Apk / android (release) Successful in 11m6s
Build Linux Application / linux (release) Successful in 4m41s
Publish Docker Image / docker (release) Successful in 13m46s
2026-09-07 12:49:02 +02:00
5 changed files with 36 additions and 10 deletions
+9 -5
View File
@@ -91,7 +91,10 @@ jobs:
KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }} KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
run: | run: |
set -euo pipefail # The act-runner executes `run` with sh (dash), not bash, so this
# script has to stay posix - `set -o pipefail` for example dies
# with "Illegal option -o pipefail" before anything else runs.
set -eu
# Failing here is on purpose: a silently debug signed apk would be # Failing here is on purpose: a silently debug signed apk would be
# installable once and never updatable afterwards. # installable once and never updatable afterwards.
@@ -120,7 +123,7 @@ jobs:
# must never go backwards. # must never go backwards.
- name: Build the apk - name: Build the apk
run: | run: |
set -euo pipefail set -eu
version="${{ github.ref_name }}" version="${{ github.ref_name }}"
version="${version#v}" version="${version#v}"
@@ -158,7 +161,7 @@ jobs:
# access in a secret and use that instead. # access in a secret and use that instead.
TOKEN: ${{ github.token }} TOKEN: ${{ github.token }}
run: | run: |
set -euo pipefail set -eu
api="${{ github.server_url }}/api/v1/repos/${{ github.repository }}" api="${{ github.server_url }}/api/v1/repos/${{ github.repository }}"
asset="ac_web-${{ github.ref_name }}.apk" asset="ac_web-${{ github.ref_name }}.apk"
@@ -167,8 +170,9 @@ jobs:
# for a manual re-run of the job. # for a manual re-run of the job.
releaseId="${{ github.event.release.id }}" releaseId="${{ github.event.release.id }}"
if [ -z "$releaseId" ] || [ "$releaseId" = "null" ]; then if [ -z "$releaseId" ] || [ "$releaseId" = "null" ]; then
releaseId=$(curl -fsSL -H "Authorization: token $TOKEN" \ release=$(curl -fsSL -H "Authorization: token $TOKEN" \
"$api/releases/tags/${{ github.ref_name }}" | jq -r '.id') "$api/releases/tags/${{ github.ref_name }}")
releaseId=$(printf '%s' "$release" | jq -r '.id')
fi fi
curl -fsSL -X POST \ curl -fsSL -X POST \
+7 -3
View File
@@ -82,7 +82,10 @@ jobs:
# access in a secret and use that instead. # access in a secret and use that instead.
TOKEN: ${{ github.token }} TOKEN: ${{ github.token }}
run: | run: |
set -euo pipefail # The act-runner executes `run` with sh (dash), not bash, so this
# script has to stay posix - `set -o pipefail` for example dies
# with "Illegal option -o pipefail" before anything else runs.
set -eu
api="${{ github.server_url }}/api/v1/repos/${{ github.repository }}" api="${{ github.server_url }}/api/v1/repos/${{ github.repository }}"
asset="ac_web-linux-x64-${{ github.ref_name }}.tar.gz" asset="ac_web-linux-x64-${{ github.ref_name }}.tar.gz"
@@ -91,8 +94,9 @@ jobs:
# for a manual re-run of the job. # for a manual re-run of the job.
releaseId="${{ github.event.release.id }}" releaseId="${{ github.event.release.id }}"
if [ -z "$releaseId" ] || [ "$releaseId" = "null" ]; then if [ -z "$releaseId" ] || [ "$releaseId" = "null" ]; then
releaseId=$(curl -fsSL -H "Authorization: token $TOKEN" \ release=$(curl -fsSL -H "Authorization: token $TOKEN" \
"$api/releases/tags/${{ github.ref_name }}" | jq -r '.id') "$api/releases/tags/${{ github.ref_name }}")
releaseId=$(printf '%s' "$release" | jq -r '.id')
fi fi
curl -fsSL -X POST \ curl -fsSL -X POST \
+1 -1
View File
@@ -35,7 +35,7 @@ jobs:
uses: https://github.com/docker/login-action@v3 uses: https://github.com/docker/login-action@v3
with: with:
registry: ${{ env.REGISTRY }} registry: ${{ env.REGISTRY }}
username: ${{ github.repository_owner }} username: LocPac
# A personal access token, created in the repo settings as BUILDTOKEN. # A personal access token, created in the repo settings as BUILDTOKEN.
password: ${{ secrets.BUILDTOKEN }} password: ${{ secrets.BUILDTOKEN }}
+6
View File
@@ -47,6 +47,7 @@ Notes that are easy to get wrong:
- **The act-runner of the gitea instance only supports actions up to `node20`.** Anything newer fails with `The runs.using key in action.yml must be one of: [...], got node24`, which is why the Flutter sdk is unpacked from the official archive instead of through `subosito/flutter-action` (that one caches through `actions/cache@v5`). Check the `runs.using` of an action before adding it. - **The act-runner of the gitea instance only supports actions up to `node20`.** Anything newer fails with `The runs.using key in action.yml must be one of: [...], got node24`, which is why the Flutter sdk is unpacked from the official archive instead of through `subosito/flutter-action` (that one caches through `actions/cache@v5`). Check the `runs.using` of an action before adding it.
- The Flutter version is pinned in three places (`FLUTTER_VERSION` in both build workflows, `ARG FLUTTER_VERSION` in `ac_web/Dockerfile`) and must be kept in sync. - The Flutter version is pinned in three places (`FLUTTER_VERSION` in both build workflows, `ARG FLUTTER_VERSION` in `ac_web/Dockerfile`) and must be kept in sync.
- Steps run with `working-directory: ac_web`, but `upload-artifact` paths are relative to the repository root. - Steps run with `working-directory: ac_web`, but `upload-artifact` paths are relative to the repository root.
- **The act-runner executes `run:` with sh (dash), not bash.** A script with `set -o pipefail` fails immediately with `Illegal option -o pipefail`, so the scripts stay posix (`set -eu`, no `[[ ]]`, no arrays) and pipelines are split where the exit code of the *first* command matters.
- **`actions/upload-artifact` must stay at `@v3`.** `@v4` bundles `@actions/artifact` v2, which aborts with `GHESNotSupportedError` whenever `GITHUB_SERVER_URL` is not `github.com` -- on this instance it is the gitea host, so the check fires before any request and cannot be worked around on the server side. `@v3` uses the older artifact api gitea implements. - **`actions/upload-artifact` must stay at `@v3`.** `@v4` bundles `@actions/artifact` v2, which aborts with `GHESNotSupportedError` whenever `GITHUB_SERVER_URL` is not `github.com` -- on this instance it is the gitea host, so the check fires before any request and cannot be worked around on the server side. `@v3` uses the older artifact api gitea implements.
- The workflows are read from the tag the release points at, so they have to be committed **before** the release is created. - The workflows are read from the tag the release points at, so they have to be committed **before** the release is created.
- Artifacts and the built files carry the tag name (`github.ref_name`); the docker image is pushed as the tag, as `latest` and as the short sha. - Artifacts and the built files carry the tag name (`github.ref_name`); the docker image is pushed as the tag, as `latest` and as the short sha.
@@ -67,6 +68,11 @@ Notes that are easy to get wrong:
The backend host/port is configured once in `lib/main.dart` via `AcApi.configure(const ApiConfig(host: 'localhost', port: 5118))`. Plain http is intentional — the API is only reached inside a trusted network. There is no environment/config file; changing the backend address means editing `main.dart`. The backend host/port is configured once in `lib/main.dart` via `AcApi.configure(const ApiConfig(host: 'localhost', port: 5118))`. Plain http is intentional — the API is only reached inside a trusted network. There is no environment/config file; changing the backend address means editing `main.dart`.
On android two things in `android/app/src/main/AndroidManifest.xml` have to stay in place for that to work, and both only bite the **release** apk:
- `<uses-permission android:name="android.permission.INTERNET"/>` — flutter ships this permission only in `src/debug` and `src/profile`, which a release build does not merge. Without it every request fails with `SocketException: Connection failed (OS Error: Operation not permitted)`, because the app may not open a socket at all.
- `android:usesCleartextTraffic="true"` on `<application>` — android blocks plain http since api 28 (the app targets 36). Without it requests fail with `CLEARTEXT communication to <host> not permitted`. Remove the attribute once the backend speaks https.
## Architecture ## Architecture
### API layer (`lib/Api/`) ### API layer (`lib/Api/`)
@@ -1,8 +1,20 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Only `src/debug` and `src/profile` carry this permission by default,
because the flutter tool needs it for hot reload. A release build
merges this manifest alone, so without the line here every request of
the release apk fails with "Operation not permitted" (EPERM) - the app
is not allowed to open a socket at all. -->
<uses-permission android:name="android.permission.INTERNET"/>
<application <application
android:label="ac_web" android:label="ac_web"
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"> android:icon="@mipmap/ic_launcher"
android:usesCleartextTraffic="true">
<!-- The api is reached over plain http inside a trusted network (see
`AcApi.configure` in `lib/main.dart`), and android blocks cleartext
traffic by default since api 28. Drop this attribute as soon as the
backend is served over https. -->
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"