156 lines
5.9 KiB
Markdown
156 lines
5.9 KiB
Markdown
# Eine APK veröffentlichen
|
|
|
|
## Vorweg: die APK gehört nicht ins Repository
|
|
|
|
Ein Release-Anhang in Gitea liegt **neben** dem Repository, nicht darin. Gitea
|
|
legt ihn in seinem Anhang-Speicher ab; im Git-Verlauf taucht er nicht auf.
|
|
|
|
Das ist auch gut so. Eine APK ist eine 11-MB-Binärdatei, die sich bei jedem
|
|
Build komplett ändert. Läge sie im Repository, wüchse der Verlauf mit jeder
|
|
Version um 11 MB — und zwar **unwiderruflich**: Git vergisst nichts, ein
|
|
späteres Löschen bringt den Platz nicht zurück. Nach zehn Versionen wäre das
|
|
Auschecken des Projekts ein 110-MB-Download, obwohl der Quelltext selbst nur
|
|
wenige hundert Kilobyte hat.
|
|
|
|
Deshalb: bauen, an ein Release hängen, fertig. `.gitignore` sorgt dafür, dass
|
|
die gebauten Dateien gar nicht erst versehentlich hineinrutschen.
|
|
|
|
## Signieren
|
|
|
|
Android installiert **keine unsignierte APK** — auch nicht per Sideload. Das
|
|
hat nichts mit Googles Sperren zu tun, sondern damit, dass das System ohne
|
|
Signatur nicht feststellen kann, ob ein Update vom selben Absender stammt wie
|
|
die Erstinstallation.
|
|
|
|
Ohne eigenen Schlüssel signiert der Build mit dem Android-Debug-Schlüssel und
|
|
sagt das beim Bauen deutlich. Das funktioniert, hat aber einen Haken: Dieser
|
|
Schlüssel wird pro Rechner erzeugt. Baust du die nächste Version auf einem
|
|
anderen Rechner, hat sie eine andere Signatur, und Android verweigert das
|
|
Update — es bliebe nur Deinstallieren und neu einrichten.
|
|
|
|
### Einen eigenen Schlüssel anlegen
|
|
|
|
Einmalig. Das Passwort tippst du dabei selbst.
|
|
|
|
```bash
|
|
keytool -genkeypair -v \
|
|
-keystore ~/camper-monitor.jks \
|
|
-alias camper -keyalg RSA -keysize 4096 -validity 10000
|
|
```
|
|
|
|
Danach `Android/keystore.properties` anlegen (die Datei ist in `.gitignore`,
|
|
sie landet nicht im Repository):
|
|
|
|
```properties
|
|
storeFile=/Users/DEINNAME/camper-monitor.jks
|
|
storePassword=DEIN_PASSWORT
|
|
keyAlias=camper
|
|
keyPassword=DEIN_PASSWORT
|
|
```
|
|
|
|
> **Diesen Schlüssel aufbewahren.** Geht er verloren, lässt sich für alle, die
|
|
> die App installiert haben, nie wieder ein Update ausliefern. Eine Kopie an
|
|
> einen zweiten Ort, getrennt vom Rechner.
|
|
|
|
## Wenn Gitea die APK nicht annimmt
|
|
|
|
Zwei Dinge, die leicht zusammenfallen:
|
|
|
|
**Der Quelltext als `.zip` und `.tar.gz`** hängt an *jedem* Gitea-Release
|
|
automatisch dran. Gitea erzeugt beides aus dem Etikett; es ist nichts, was
|
|
versehentlich hochgeladen wurde, und es lässt sich auch nicht abschalten. Es
|
|
stört nur optisch und kostet keinen Speicher — die Archive werden erst beim
|
|
Anklicken erzeugt.
|
|
|
|
**Die APK abgelehnt** wird dagegen aus einem handfesten Grund: Gitea nimmt nur
|
|
Dateitypen an, die in seiner Liste stehen, und `.apk` steht dort nicht. Die
|
|
Liste dieser Instanz lässt sich abfragen:
|
|
|
|
```bash
|
|
curl -s https://git.home.fritob.de/api/v1/settings/attachment
|
|
```
|
|
|
|
Kommt dort eine `allowed_types`-Liste ohne `.apk` zurück, ist das die Ursache.
|
|
Die Grösse ist es nicht — die Grenze liegt bei 100 MiB, die APK bei 11.
|
|
|
|
### Der richtige Weg: `.apk` erlauben
|
|
|
|
In der `app.ini` des Servers (bei Docker meist
|
|
`/data/gitea/conf/app.ini`, sonst `/etc/gitea/app.ini`):
|
|
|
|
```ini
|
|
[attachment]
|
|
ALLOWED_TYPES = .avif,.cpuprofile,.csv,.dmp,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.json,.jsonc,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.patch,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.webp,.xls,.xlsx,.zip,.apk
|
|
|
|
[repository.release]
|
|
ALLOWED_TYPES = .apk,.zip
|
|
```
|
|
|
|
Beide Abschnitte, weil je nach Gitea-Fassung mal der eine, mal der andere für
|
|
Release-Anhänge zuständig ist. Danach Gitea neu starten.
|
|
|
|
Wer es sich einfach machen will, schreibt in beide Schlüssel `*/*` — dann ist
|
|
alles erlaubt. Auf einer Instanz im eigenen Netz ist das vertretbar; öffentlich
|
|
wäre es das nicht, weil dann auch beliebige ausführbare Dateien hochladbar sind.
|
|
|
|
### Ohne Serverzugriff: die Paket-Registry
|
|
|
|
Die nimmt beliebige Dateien an, ganz ohne Typenliste, und ist auf dieser
|
|
Instanz eingeschaltet. Der Preis: Die Datei landet unter *Packages* statt am
|
|
Release.
|
|
|
|
```bash
|
|
Android/upload-package.sh 1.0.0
|
|
```
|
|
|
|
Das Skript liest den Zugangsschlüssel aus `~/.gitea-token` und gibt ihn
|
|
nirgends aus. Ein Token mit dem Recht `write:package` genügt; anzulegen unter
|
|
*Einstellungen → Anwendungen → Zugriffstoken*.
|
|
|
|
## Von Hand veröffentlichen
|
|
|
|
```bash
|
|
source Android/env.sh
|
|
cd Android
|
|
./gradlew :app:assembleRelease -PversionName=1.0.0 -PversionCode=1
|
|
```
|
|
|
|
Die APK liegt dann unter
|
|
`Android/app/build/outputs/apk/release/app-release.apk`.
|
|
|
|
In Gitea: **Releases → New Release**, ein Etikett wie `v1.0.0` wählen, und die
|
|
APK unter *Attachments* hochladen. Fertig — genau das ist das „Wie sage ich
|
|
Gitea, dass die APK dort hinein soll".
|
|
|
|
## Von selbst veröffentlichen
|
|
|
|
`.gitea/workflows/release.yml` nimmt das ab: Ein Etikett hochschieben genügt.
|
|
|
|
```bash
|
|
git tag v1.0.0
|
|
git push origin v1.0.0
|
|
```
|
|
|
|
Der Ablauf baut die APK, legt das Release an, falls es noch nicht besteht, und
|
|
hängt die Datei an. Die Versionsnummer kommt aus dem Etikett, der
|
|
Versionszähler aus der Anzahl der Commits — so steigt er verlässlich.
|
|
|
|
### Voraussetzungen
|
|
|
|
1. **Ein Runner.** Actions brauchen in Gitea einen registrierten Runner mit dem
|
|
Etikett `ubuntu-latest`. Unter *Site Administration → Actions → Runners*
|
|
nachsehen. Ist keiner da, bleibt der Weg von Hand — der tut es genauso.
|
|
2. **Actions eingeschaltet**, im Repository unter *Settings → Advanced*.
|
|
3. **Der Schlüssel als Geheimnis**, falls mit eigenem Schlüssel signiert werden
|
|
soll. Unter *Settings → Actions → Secrets* anlegen:
|
|
|
|
| Name | Inhalt |
|
|
| ------------------ | ------------------------------------------ |
|
|
| `KEYSTORE_BASE64` | `base64 -i ~/camper-monitor.jks \| pbcopy` |
|
|
| `KEYSTORE_PASSWORD`| das Passwort des Schlüsselspeichers |
|
|
| `KEY_ALIAS` | `camper` |
|
|
| `KEY_PASSWORD` | das Passwort des Schlüssels |
|
|
|
|
Fehlen sie, baut der Ablauf trotzdem — dann eben mit dem Debug-Schlüssel,
|
|
und die APK heisst entsprechend.
|