Was ein Repository ist

Clink liest Packs aus öffentlichen GitHub-Repositories. Du fügst eines per Name hinzu, Clink liest dessen neuestes Release, und jede Datei wird vor der Installation geprüft. Nichts wird hochgeladen, und nichts von dir läuft auf einem Server.

Gib owner/repository, github.com/owner/repository oder die vollständige HTTPS-URL ein. Clink prüft jedes Release-Manifest und jede Datei, bevor etwas geladen wird.

Wähle eine Art

Jede Art von Pack hat ihre eigene Dateiendung und ihren eigenen Sammlungsnamen im Manifest, und Clink hält jede an ihre eigene Größengrenze. Wähle die Zeile, die du veröffentlichst, und bleib dabei: ein Theme, das unter Panels abgelegt ist, wird schlicht nicht gelesen.

ArtDateiSammlungGrößte Datei, in BytesOffizielles Repository
Themes.clinkthemethemes128.000anti-ltd/clink-themes
Layouts.clinklayoutlayouts512.000anti-ltd/clink-layouts
Profile.clinkprofileprofiles256.000anti-ltd/clink-profiles
Töne.clinkpacksounds512.000anti-ltd/clink-sounds
Schriften.otf .ttffonts32.000.000anti-ltd/clink-fonts
Bereiche.clinkpanelpanels50.000anti-ltd/clink-panels
Aktionen.clinkextactions48.000anti-ltd/clink-actions
Plugins.clinkpluginplugins66.000anti-ltd/clink-plugins

Sprachpakete sind die Ausnahme. Dort ist ein Pack kein einzelnes Dokument, sondern ein Satz von Lexikon- und Modelldateien, und das offizielle Repository bringt die Werkzeugkette mit, die sie baut. Fang dort mit der README an statt mit dieser Seite.

Fang beim offiziellen Repository an

Der schnellste Weg ist ein Fork. Er kommt mit dem Pack-Ordner, dem Manifest-Generator und dem Release-Workflow schon verdrahtet, dazu mit funktionierenden Beispielen zum Abschauen.

# Everything a repository needs is already wired together in the official one.
gh repo fork anti-ltd/clink-panels --clone
cd clink-panels

# Your packs replace the examples. Keep tools/ and .github/.
rm Panels/*.clinkpanel
cp ~/Downloads/my-panel.clinkpanel Panels/kaomoji-plus.clinkpanel

Behalte tools/ und .github/workflows/. Die beiden machen aus einem Push ein Release, das Clink lesen kann; ein Fork ohne sie veröffentlicht nichts.

Oder bau es aus drei Dateien

An einem Repository ist nichts Besonderes. Es braucht einen Ordner mit Packs, ein Skript, das das Manifest schreibt, und einen Workflow, der das Release schneidet.

my-panels/
├── Panels/
   └── kaomoji.clinkpanel        # one file per pack, the name is the id
├── tools/
   └── build-manifest.py         # writes manifest.json from that folder
└── .github/workflows/
    └── release.yml               # turns a push into a release

Der Workflow tut drei Dinge: das Manifest neu bauen, das vorige Release löschen und ein neues mit dem Tag latest veröffentlichen, mit den Pack-Dateien und dem Manifest im Anhang. Das ist alles.

name: Release panels
on:
  push:
    branches: [main]
    paths: ["Panels/**", "tools/**", ".github/workflows/release.yml"]
permissions: { contents: write }
jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: python3 tools/build-manifest.py
      - run: gh release delete latest --yes || true
        env: { GH_TOKEN: "${{ github.token }}" }
      - run: gh release create latest Panels/*.clinkpanel manifest.json --title "Latest panels" --latest
        env: { GH_TOKEN: "${{ github.token }}" }
.github/workflows/release.yml

Der Generator geht den Ordner durch und schreibt einen Eintrag je Datei. Er ist die einzige Quelle für Hash und Bytezahl, und genau deshalb läuft er im Workflow und nicht von Hand.

#!/usr/bin/env python3
import hashlib, json, os, pathlib

root = pathlib.Path(__file__).resolve().parents[1]
repository = os.environ.get("GITHUB_REPOSITORY", "<owner>/<repository>")
packs = []
for path in sorted((root / "Panels").glob("*.clinkpanel")):
    data = path.read_bytes()
    pack = json.loads(data)
    packs.append({
        "id": path.stem,
        "name": pack["name"],
        "version": "latest",
        "asset": {
            "path": path.name,
            "url": f"https://github.com/{repository}/releases/download/latest/{path.name}",
            "sha256": hashlib.sha256(data).hexdigest(),
            "byteCount": len(data),
        },
    })
(root / "manifest.json").write_text(json.dumps({"version": "latest", "panels": packs}, indent=2))
tools/build-manifest.py. Für eine andere Art ändere Ordner, Endung und Sammlungsnamen auf die Zeile, die du gewählt hast.

Das Manifest

Jedes Release veröffentlicht manifest.json neben den Pack-Dateien, und Clink liest es aus dem neuesten Release unter https://github.com/<owner>/<repository>/releases/latest/download/manifest.json. Jeder Eintrag nennt die Datei, ihre Adresse innerhalb desselben Releases, ihren SHA-256-Hash und ihre genaue Bytezahl.

{
  "version": "latest",
  "panels": [
    {
      "id": "kaomoji",
      "name": "Kaomoji",
      "version": "latest",
      "asset": {
        "path": "kaomoji.clinkpanel",
        "url": "https://github.com/<owner>/<repository>/releases/download/latest/kaomoji.clinkpanel",
        "sha256": "8f14e45fce…",
        "byteCount": 2048
      }
    }
  ]
}
Ein Eintrag aus dem Manifest eines Panel-Repositories.

Der Sammlungsname muss zur Art passen. Panels stehen unter panels, Themes unter themes, und so weiter durch die Tabelle oben.

Probier es aus, bevor du veröffentlichst

Ein Pack in einem Repository ist dieselbe Datei, die du auch von Hand öffnen kannst, also nimm zuerst den kurzen Weg: schick sie per AirDrop aufs Telefon, oder leg sie in Dateien und öffne sie mit Clink. Danach prüfe das Manifest, das dein Skript schreibt.

python3 tools/build-manifest.py
cat manifest.json
  1. Lass den Generator laufen. Er schreibt manifest.json aus dem neu, was gerade im Ordner liegt.
  2. Lies, was er geschrieben hat. Jeder Eintrag sollte eine Datei nennen, die es wirklich gibt, mit einer Bytezahl, die dazu passt.
  3. Öffne die Pack-Datei selbst in Clink und benutze sie. Ein Panel oder eine Aktion landet im eigenen Editor, wo du sie laufen lassen kannst.

Veröffentlichen

git add Panels manifest.json
git commit -m "Add my first panel"
git push

Push auf main, den Rest übernimmt der Workflow. Er ersetzt das Release latest, statt sich dazuzulegen, also ist der neueste Push immer das, was andere bekommen.

Öffne diesen Tab, sobald das Repository eine Version veröffentlicht hat.

In Clink hinzufügen

  1. Öffne Allgemein, dann Repositories, und füge Eigentümer/Repository hinzu.
  2. Öffne den Tab deiner Art und zieh zum Aktualisieren. Deine Packs stehen dort unter den Namen, die das Manifest ihnen gibt.
  3. Tipp eines an, um es zu laden. Clink prüft es und installiert es wie jedes andere Pack.

Ein Repository hinzuzufügen reicht für Datenpakete: Themes, Layouts, Profile, Sounds, Schriften und Sprachen. Panels, Aktionen und Plugins enthalten Logik, deshalb braucht jedes Repository einen eigenen Schalter, bevor Clink eines davon installiert, und die App fragt beim ersten Mal.

Panels enthalten eingeschränkte interaktive Logik. Erlaube nur Repositorys, denen du vertraust.

Was Clink prüft

  1. Die Adresse ist HTTPS auf github.com, unter den Releases des Repositories, das du hinzugefügt hast.
  2. Der Download hat genau die Bytezahl aus dem Manifest, und sein SHA-256-Hash mit 64 Zeichen stimmt überein.
  3. Die Datei trägt die richtige Endung und lässt sich als die Art von Pack lesen, die sie zu sein behauptet.
  4. Panels, Aktionen und Plugins bestehen die Quellrichtlinie, bevor sie gespeichert werden.

Wird ein Download abgelehnt, liegt es an einem dieser fünf Punkte. Die Meldung in der App ist bewusst kurz, geh sie also der Reihe nach durch.

PrüfungAbgelehnt, wenn
github.comDie Adresse ist nicht HTTPS auf github.com, unter den Releases des Repositories, das du hinzugefügt hast. Ein Manifest darf nirgendwo anders hinzeigen, auch nicht auf ein anderes Repository von dir.
byteCountDie Datei hat nicht genau die Größe, die das Manifest angibt, oder sie liegt über der Grenze ihrer Art. Das Manifest nach jeder Änderung neu zu bauen behebt die meisten dieser Fälle.
sha256Der Hash passt nicht zu den Bytes. Meist wurde das Manifest vor der letzten Änderung an der Datei geschrieben.
pathDer Dateiname endet nicht auf die Endung, die die Art verlangt, oder er versucht mit zwei Punkten aus dem Release herauszuklettern.
sourceEin Panel, eine Aktion oder ein Plugin hat die Quellrichtlinie nicht bestanden: zu lang, oder mit einem Fragment, das die Richtlinie ablehnt.

Aktualisieren, und etwas zurücknehmen

Die ID ist der Dateiname ohne Endung, und sie ist es, die aus einer Veröffentlichung ein Update macht. Behalte den Namen, und ein neues Release ersetzt die Kopie, die andere schon haben. Benenn die Datei um, und du hast ein zweites Pack neben das erste gestellt.

Ein Pack aus dem Repository zu nehmen stoppt neue Downloads. Die Telefone, die es schon haben, erreicht das nicht: behandle ein schlechtes Release als etwas zum Ersetzen, nicht zum Löschen.

Offizielle Repositories

Forke eines davon als Start. Jedes baut sein eigenes Manifest und veröffentlicht sich selbst mit GitHub Actions.

Im App Store laden