Uniform Chat
  • Uniform.Matrix
  • API
Search Results for

    Show / Hide Table of Contents
    • Uniform.Matrix.Protocol.Core
      • Introduction
    • Uniform.Matrix.Protocol.Client
      • Introduction
      • Log in
      • Receive events
      • Rooms and messages
      • Directories and account data
      • Files and devices
      • Errors
    • Uniform.Matrix.Protocol.Crypto
      • Introduction
    • Uniform.Matrix.Hosting
      • Introduction
    • Uniform.Matrix.Gui.Terminal
      • Introduction
    • Uniform.Matrix.Audio
      • Introduction
    • Uniform.Matrix.Video
      • Introduction
    • Uniform.Stun.Protocol
      • Introduction
    • Uniform.Stun
      • Introduction
    • Uniform.LiveKit.Protocol
      • Introduction
    • Uniform.LiveKit
      • Introduction
    • Uniform.Matrix.WebRtc
      • Introduction
    • Uniform.Matrix.Client
      • Introduction
      • Room state
      • Rich text
      • Local storage
      • Outbox
      • Track rooms
    • Uniform.Matrix.Calls
      • Introduction
    • Uniform.Chat.Terminal
      • Introduction
    • Uniform.Chat.Avalonia
      • Introduction
      • View models
      • Views
    • Uniform.Chat.Desktop
      • Introduction
    • Uniform.Chat.Android
      • Introduction
    • Uniform.Matrix.Protocol.Server
      • Introduction
    • Uniform.Matrix.Server
      • Introduction
      • Requests
      • Storage
      • Events and state
      • Sync and the stream
      • Services
      • Push rules and pushers
      • Presence
      • URL previews
      • Rate limits
      • Federation
      • Testing
    • Uniform.Chat.Server
      • Introduction
    • Uniform.Turn
      • Introduction
    • Uniform.Stun.Hosting
      • Introduction
    • Uniform.Stun.Server
      • Introduction
    • Uniform.LiveKit.Authorization
      • Introduction
    • Uniform.LiveKit.Hosting
      • Introduction
    • Uniform.LiveKit.Server
      • Introduction
    • Building
    • Testing
    • Documentation

    Building

    dotnet build
    

    Every library generates its XML documentation file, so public members without doc comments show up as build warnings.

    The desktop and Android apps have their own notes: Uniform.Chat.Desktop and Uniform.Chat.Android.

    Releasing

    Pushing a version tag runs .github/workflows/release.yml:

    git tag v0.1.0
    git push origin v0.1.0
    

    The workflow builds and tests, packs the Uniform.Matrix.*, Uniform.Stun.*, Uniform.LiveKit.* and Uniform.Turn libraries with the tag's version, publishes the desktop app, the terminal client, the server, the STUN and TURN server and the MatrixRTC authorization server, each with its user guide, for linux-x64, linux-arm64, win-x64 and win-arm64 as self-contained single-file apps (.tar.gz for Linux, .zip for Windows), pushes the packages to NuGet.org, and creates a GitHub release with the archives, the signed Android APK uniform-chat-android-<version>.apk and SHA256SUMS.txt. A tag with a suffix, such as v0.2.0-alpha.1, makes a prerelease on both.

    Packages are pushed with trusted publishing: the job exchanges GitHub's OIDC token for a short-lived NuGet API key, so no key is stored. It needs a trusted publishing policy on nuget.org for this repository and release.yml, a release environment in the repository settings, and the nuget.org user name in the NUGET_USER secret.

    Android release signing

    The APK is signed with the app's release key, which Android uses to allow updates: an update signed with another key does not install over the app. Keep the keystore and its passwords safe and backed up; a lost key means users have to uninstall to get updates.

    Create the keystore once, outside the repository; keytool asks for the passwords:

    keytool -genkeypair -keystore ~/uniform-chat-release.keystore -alias uniform-chat -keyalg RSA -keysize 4096 -validity 10000 -dname "CN=Uniform Chat"
    

    Then add these repository secrets; the workflow writes the keystore to the runner's temporary folder and deletes it after the build. Without ANDROID_KEYSTORE_BASE64, the release has no APK.

    Secret Value
    ANDROID_KEYSTORE_BASE64 The keystore, from base64 -w0 ~/uniform-chat-release.keystore
    ANDROID_KEY_ALIAS The alias, e.g. uniform-chat
    ANDROID_KEYSTORE_PASSWORD The keystore password
    ANDROID_KEY_PASSWORD The key password

    To build a signed APK locally, give the keystore and alias as properties and the passwords in the environment, never on the command line:

    read -rs ANDROID_KEYSTORE_PASSWORD && export ANDROID_KEYSTORE_PASSWORD ANDROID_KEY_PASSWORD="$ANDROID_KEYSTORE_PASSWORD"
    dotnet publish src/Uniform.Chat.Android -c Release -p:Version=0.1.0 \
      -p:AndroidSigningKeyStore=$HOME/uniform-chat-release.keystore -p:AndroidSigningKeyAlias=uniform-chat
    

    The version code follows the version: major × 10000 + minor × 100 + patch, so 0.2.1 is 201. It has to grow with every release that app stores get.

    Store listings

    fastlane/metadata/android/en-US/ holds the title, the short and full description, the icon, screenshots and a changelog per version code, e.g. changelogs/201.txt, in the layout F-Droid and IzzyOnDroid read. Add the changelog of a version before tagging it.

    Debian packages and the apt repository

    The workflow also packages the five Linux apps for Debian and Ubuntu, for amd64 and arm64, with packaging/linux/build-deb.sh. The packages are self-contained like the archives, and need only the system's usual libraries:

    Package Installs
    uniform-chat The desktop app in /opt/uniform-chat/desktop, the command uniform-chat, a menu entry and an icon
    uniform-chat-terminal The terminal client in /opt/uniform-chat/terminal, the command uniform-chat-terminal
    uniform-chat-server The server in /opt/uniform-chat/server, the command uniform-chat-server, and the system service uniform-chat-server run by the user uniform-chat, off until enabled; settings in /etc/uniform-chat-server, data in /var/lib/uniform-chat-server
    uniform-stun-server The STUN and TURN server in /opt/uniform-chat/stun, the command uniform-stun-server
    uniform-livekit-server The MatrixRTC authorization service in /opt/uniform-chat/livekit, the command uniform-livekit-server

    A prerelease's version gets a tilde, so that it sorts before its release: 0.2.0-rc.1 is 0.2.0~rc.1.

    The releases themselves are the apt repository, with no other hosting. Each release, but not a prerelease, gets an index as its assets, made by packaging/linux/build-apt-index.sh: Packages lists its own packages and, from the previous release's index, those of all earlier releases; Release has the hashes, InRelease and Release.gpg sign it, and uniform-chat-archive-keyring.gpg is the public key. apt reads it from https://github.com/tagcode/Uniform.Chat/releases/ with the suite latest/download/, which GitHub serves from the newest release, and fetches each package from download/<tag>/ there. So users can also install an earlier version, as long as its release exists. Prereleases have packages but are not in the index.

    Users add the repository once:

    sudo install -d -m 0755 /etc/apt/keyrings
    curl -fsSL https://github.com/tagcode/Uniform.Chat/releases/latest/download/uniform-chat-archive-keyring.gpg | sudo tee /etc/apt/keyrings/uniform-chat.gpg > /dev/null
    echo "deb [signed-by=/etc/apt/keyrings/uniform-chat.gpg] https://github.com/tagcode/Uniform.Chat/releases/ latest/download/" | sudo tee /etc/apt/sources.list.d/uniform-chat.list
    sudo apt update
    

    The index is signed with a GPG key of its own. apt trusts packages by it, so keep it safe and backed up: with a new key, every user has to add the repository again. Create it once; gpg asks for a passphrase:

    gpg --quick-generate-key "Uniform Chat packages <tagcode@users.noreply.github.com>" rsa4096 sign never
    gpg --armor --export-secret-keys "Uniform Chat packages" > uniform-chat-apt-key.asc
    

    Then add these repository secrets, and keep uniform-chat-apt-key.asc with the other keys, not in the repository. Without APT_GPG_PRIVATE_KEY, releases have packages but no index.

    Secret Value
    APT_GPG_PRIVATE_KEY The contents of uniform-chat-apt-key.asc
    APT_GPG_PASSPHRASE Its passphrase

    To build a package locally, publish the app as the workflow does, then:

    packaging/linux/build-deb.sh server publish/uniform-chat-server-0.2.0-linux-x64 0.2.0 linux-x64 out
    

    Documentation on GitHub Pages

    After each release, but not a prerelease, the workflow publishes the documentation of that release on GitHub Pages, from the tagcode.github.io repository, in the same folders as here:

    Address Site
    https://tagcode.github.io/Uniform.Chat/docs/ This developer site, with the API reference
    https://tagcode.github.io/Uniform.Chat/user-docs/Uniform.Chat.Desktop/ The user guide of the desktop app; likewise Uniform.Chat.Android, Uniform.Chat.Terminal, Uniform.Chat.Server, Uniform.Stun.Server and Uniform.LiveKit.Server

    Each release replaces the previous documentation. The same job updates the F-Droid repository below, so both go into one commit. It needs the PAGES_TOKEN secret, described below; without the F-Droid secrets only the documentation is published.

    F-Droid repository

    After each release, but not a prerelease, the workflow adds the APK to the app's own F-Droid repository, which GitHub Pages serves from the tagcode.github.io repository at https://tagcode.github.io/fdroid/repo. fdroidserver reads the APKs, the store listing from fastlane/metadata/android/ and the app's entry from fdroid/metadata/rip.uniform.chat.yml, and signs the index with the repository key. The repository keeps only the newest version, as the site's space is limited; users can't go back to an older one through F-Droid. Prereleases are left out because they share the version code of their release.

    The repository key is separate from the app's release key. F-Droid users trust the repository by its fingerprint, so a lost key means they have to add the repository again. Create it once, outside the repository:

    keytool -genkeypair -keystore ~/uniform-chat-fdroid.keystore -alias fdroid-repo -keyalg RSA -keysize 4096 -sigalg SHA256withRSA -validity 10000 -dname "CN=Uniform Chat F-Droid repository"
    

    Then add these repository secrets. Without them, the release is not added to the F-Droid repository.

    Secret Value
    FDROID_KEYSTORE_BASE64 The keystore, from base64 -w0 ~/uniform-chat-fdroid.keystore
    FDROID_KEY_ALIAS The alias, e.g. fdroid-repo
    FDROID_KEYSTORE_PASSWORD The keystore password, which the key shares
    PAGES_TOKEN A fine-grained token for tagcode/tagcode.github.io only, with Contents: Read and write

    Each update replaces the Pages repository's history with one commit, so the APKs of dropped versions and old documentation don't make it grow. The site's other files stay as they are. To be offered the repository, users open https://tagcode.github.io/fdroid/repo and scan or tap its link, which carries the key's fingerprint.

    • Edit this page
    In this article
    Back to top Uniform Chat