Skip to content

HTML UI

Marc Staebler edited this page Mar 26, 2026 · 6 revisions

HTML-UI und AppContent

UserApps können HTML-basierte Benutzeroberflächen anzeigen. Dieses Kapitel erklärt die verschiedenen Darstellungsarten und wie du sie einsetzt.


AppViewMode – Darstellungsarten

Es gibt verschiedene Arten, wie eine HTML-UI dem Nutzer angezeigt werden kann:

Modus Beschreibung Typischer Einsatz
Popup Eigenes Fenster/Dialog Spiele, Formulare, Einstellungen
Overlay Überlagert den Channel Vollbild-Anwendungen
Global Globale App-Ansicht Apps im "Apps & Spiele"-Menü
Headerbar Leiste über dem Channel Statusanzeigen, Ticker

AppContent erstellen

Popup (häufigstes Format)

var pageData = { spielstand: 42 };
var htmlFile = new HTMLFile("index.html", pageData);

// Popup mit Größe 480x720 Pixel (Breite x Höhe)
var popup = AppContent.popupContent(htmlFile, 480, 720);
popup.setResponsive(true);  // Passt sich an Bildschirmgröße an

// Prüfen ob der Nutzer Popups anzeigen kann
if (user.canShowAppViewMode(AppViewMode.Popup)) {
    user.sendAppContent(popup);
}

Größen-Limits: Breite und Höhe müssen zwischen 50 und 1000 Pixel liegen.

Overlay

var htmlFile = new HTMLFile("overlay.html", {});
var overlay = AppContent.overlayContent(htmlFile, 600, 400);
overlay.setResponsive(true);

if (user.canShowAppViewMode(AppViewMode.Overlay)) {
    user.sendAppContent(overlay);
}

Headerbar

var htmlFile = new HTMLFile("header.html", {});
var header = AppContent.headerbarContent(htmlFile, 50);  // Nur Höhe, volle Breite

user.sendAppContent(header);

Headerbar-Hinweise:

  • Die Höhe ist auf 20–500 px limitiert, die Breite wird ignoriert (immer volle Breite)
  • Im HTMLChat scheint der Channel-Hintergrund durch die Headerbar hindurch. Setze daher immer eine Hintergrund-Farbe auf <body>, um das zu verhindern.

AppContentSession

Wenn du user.sendAppContent() aufrufst, erhältst du eine AppContentSession zurück. Darüber steuerst du die laufende UI-Instanz:

var session = user.sendAppContent(popup);

// Event an diese spezifische Session senden
session.sendEvent('update', { score: 100 });

// Alle aktiven Sessions eines Nutzers abrufen
var sessions = user.getAppContentSessions();
var popupSessions = user.getAppContentSessions(AppViewMode.Popup);

Close-Listener

Reagiere darauf, wenn ein Nutzer die App schließt:

var popup = AppContent.popupContent(htmlFile, 480, 720);
user.sendAppContent(popup);

popup.addCloseListener(function(user, appContent) {
    user.sendPrivateMessage(
        "App geschlossen, falls du sie wieder öffnen willst, klicke hier: °>/openApp|/openApp<°"
    );
});

Event an alle offenen Sessions senden

Über appContent.sendEvent() kannst du ein Event an alle Nutzer senden, die diesen AppContent geöffnet haben. Das ist nützlich, um z.B. Spielstände oder Statusänderungen an alle Teilnehmer gleichzeitig zu übermitteln:

// Servercode
var popup = AppContent.popupContent(new HTMLFile("game.html", {}), 480, 720);

// Popup an mehrere Nutzer senden
var nutzer = KnuddelsServer.getChannel().getOnlineUsers(UserType.Human);
for (var i = 0; i < nutzer.length; i++) {
    if (nutzer[i].canShowAppViewMode(AppViewMode.Popup)) {
        nutzer[i].sendAppContent(popup);
    }
}

// Später: Event an ALLE Nutzer senden, die dieses popup geöffnet haben
popup.sendEvent('scoreUpdate', { topScore: 9001, leader: 'MaxMustermann' });
// Clientcode (www/game.html)
if (typeof Client !== 'undefined') {
    Client.addEventListener('scoreUpdate', function(event) {
        document.getElementById('topScore').textContent = event.data.topScore;
        document.getElementById('leader').textContent = event.data.leader;
    });
}

Hinweis: Der type darf maximal 100 Zeichen lang sein (das Zeichen * ist nicht erlaubt). Die data werden als JSON übermittelt und dürfen maximal 10.000 Zeichen lang sein (bei DirectConnection: 1 MB).


AppContent ersetzen

Du kannst eine laufende UI durch eine neue ersetzen:

var alteUI = AppContent.popupContent(new HTMLFile("seite1.html", {}), 480, 720);
user.sendAppContent(alteUI);

// Später: UI ersetzen (ohne das Fenster zu schließen)
var neueUI = AppContent.popupContent(new HTMLFile("seite2.html", {}), 480, 720);
alteUI.replaceWithAppContent(neueUI);

CSS und JS einbinden

Um Cache-Probleme zu vermeiden, nutze die Client-Methoden zum Einbinden von Ressourcen:

// Clientcode (www/index.html)
if (typeof Client !== 'undefined') {
    Client.includeCSS('css/style.css');
    Client.includeJS('js/app.js');
}

Dadurch wird bei jedem App-Update automatisch der Cache invalidiert.


Fenster-Größe änderbar machen

Erlaube dem Nutzer, die Größe des App-Fensters selbst zu verändern:

// Clientcode
if (typeof Client !== 'undefined') {
    var hostFrame = Client.getHostFrame();
    hostFrame.setResizable(true);
}

Responsive Design

UserApps laufen sowohl auf Desktop als auch auf mobilen Geräten. Empfehlungen:

  • Setze immer popup.setResponsive(true)
  • Verwende <meta name="viewport" content="width=device-width, initial-scale=1.0"> im HTML
  • Teste auf verschiedenen Bildschirmgrößen
  • Prüfe mit user.canShowAppViewMode() ob der Modus unterstützt wird

Praxisbeispiel: Mehrseitige App

// Servercode (innerhalb von var App = { ... };)
chatCommands: {
    menu: function(user, params, command) {
        openPage(user, 'menu.html', { name: user.getNick() });
    }
},

function openPage(user, page, data) {
    var htmlFile = new HTMLFile(page, data || {});
    var popup = AppContent.popupContent(htmlFile, 480, 720);
    popup.setResponsive(true);

    if (user.canShowAppViewMode(AppViewMode.Popup)) {
        user.sendAppContent(popup);
    } else {
        user.sendPrivateMessage('Dein Gerät unterstützt diese Ansicht leider nicht.');
    }

    popup.addCloseListener(function(closingUser) {
        KnuddelsServer.getDefaultLogger().info(closingUser.getNick() + ' hat die App geschlossen');
    });
}

onEventReceived: function(user, type, data, appContentSession) {
    if (type === "navigate") {
        openPage(user, data.page + '.html', data.pageData || {});
    }
},

iOS-Hinweis

Damit sich die HTML-UI auf iOS-Geräten öffnen lässt, muss in der app.config eine gültige appleDeveloperId hinterlegt sein:

appleDeveloperId = DEINE_APPLE_ID

Ohne diese Angabe wird die App auf iOS nicht geöffnet. Weitere Informationen dazu findest du in den FAQ.


Sandbox-Umgebung und Einschränkungen

Die HTML-UI wird in einem sandboxed iframe ausgeführt. Das bringt einige Einschränkungen mit sich:

Erlaubte Sandbox-Flags

  • allow-forms – Formulare absenden
  • allow-orientation-lock – Bildschirmausrichtung
  • allow-pointer-lock – Mauszeiger sperren
  • allow-same-origin – Gleicher Ursprung
  • allow-scripts – JavaScript ausführen

Eingeschränkte Web-APIs

  • alert() → Wird durch console.log() ersetzt (erzeugt Warning)
  • prompt() → Deaktiviert
  • confirm() → Deaktiviert
  • window.history → Komplett deaktiviert
  • Kamera/Mikrofon-Zugriff ist nicht möglich

Polyfills (automatisch verfügbar)

Knuddels stellt automatisch Polyfills bereit — du musst sie nicht selbst einbinden:

  • Promise
  • Object.assign
  • Symbol / Symbol.iterator
  • String.prototype.startsWith

Deprecated APIs

  • document.addEventListener("eventReceived", ...) → Nutze stattdessen Client.addEventListener(type, callback). Die alte Variante war nie offiziell dokumentiert und wird in einer zukünftigen Version entfernt.
  • Client.onSendEventReceived() → Nutze stattdessen Client.dispatchEvent(). War eine interne API, die sich durch Frameworks verbreitet hat.

App-Manager verwalten

Channel-Owner können per Chat-Befehl App-Manager hinzufügen und entfernen:

// App-Manager hinzufügen
/apps addManager knuddelsDE.ENTWICKLER_ID.AppName NutzernameDesManagers

// App-Manager entfernen
/apps removeManager knuddelsDE.ENTWICKLER_ID.AppName NutzernameDesManagers

API-Referenz


← Zurück zur Übersicht

Navigation

Einstieg

Kernkonzepte

Features

Tutorials

Referenz & Hilfe

Clone this wiki locally