Native app
Playback, queue, library database, scanning, settings, imports, permissions, haptics, and system UI.
Create HTML, CSS, and JavaScript interfaces that run inside oPlayer's Android WebView. The native app owns playback, storage, permissions, and the media database; your theme owns the visual experience.
Imported themes are served from https://app-theme.local/user_themes/<theme-id>/index.html. That domain is local to the app; oPlayer intercepts it and routes requests to bundled assets, imported theme files, cached artwork, media content proxies, or local JSON endpoints.
Playback, queue, library database, scanning, settings, imports, permissions, haptics, and system UI.
Your index.html, style.css, theme.js, and local assets render the interface.
oplayer-bridge.js exposes window.Bridge for allowed reads, playback controls, events, and fullscreen setup.
Your distributable ZIP must contain these files at the archive root. Do not zip a parent folder.
manifest.json
index.html
style.css
theme.js
You may include local images, fonts, icons, and data files. The importer accepts html, css, js, json, png, jpg, jpeg, svg, gif, woff, woff2, ttf, and otf.
{
"id": "my_theme",
"name": "My Theme",
"title": "My Theme",
"version": "1.0.0",
"author": "Your Name"
}
Theme IDs may contain only letters, numbers, and underscores. Do not use built-in IDs such as ipod, classic, dark, glideform_touch, or glideform_retro.
<script src="https://app-theme.local/assets/core/oplayer-bridge.js"></script>
<script src="theme.js" defer></script>
React, Vite, and other bundlers are fine for authoring themes, but the installed ZIP must still be static files at the theme root. Include oplayer-bridge.js before your bundle, and call the bridge as window.Bridge from module code.
The installed theme must run fully offline through app-theme.local. Do not ship CDN React scripts, remote fonts, remote images, or code that assumes a local dev server is running. Bundle framework code, components, CSS, and small required assets into the static package files, and reference larger assets as local files inside the ZIP.
<script src="https://app-theme.local/assets/core/oplayer-bridge.js"></script>
<script type="module" src="theme.js"></script>
src_react/.src/.theme.js and the bundled stylesheet style.css.manifest.json, index.html, style.css, and theme.js at the package root.ReactiveTheme in this repository uses that split: builds/reactiveTheme/src_react/ is the React authoring project, while builds/reactiveTheme/src/ is the importable static theme folder.
cd builds/reactiveTheme/src_react
npm ci
npm run build
cd ../src
zip -r ../reactiveTheme.zip .
After this, reactiveTheme.zip contains only the offline package files that oPlayer imports.
Fullscreen themes must set all fullscreen manifest fields consistently and should also request the fullscreen shell after the DOM is ready.
{
"id": "my_fullscreen_theme",
"name": "My Fullscreen Theme",
"version": "1.0.0",
"author": "Your Name",
"deviceModel": "FULLSCREEN",
"layout": "fullscreen",
"fullscreen": true,
"themeDarkMode": true,
"systemBarStyle": "dark"
}
Use themeDarkMode and systemBarStyle for dark fullscreen themes so Android can set readable status/navigation icons before theme JavaScript runs.
function requestFullscreenShell() {
try {
var settings = Bridge.getSettings ? Bridge.getSettings() : {};
if (settings.deviceModel !== "FULLSCREEN") {
Bridge.setSetting("deviceModel", "FULLSCREEN");
}
if (settings.uiOrientationLock !== "PORTRAIT") {
Bridge.setSetting("uiOrientationLock", "PORTRAIT");
}
if (settings.themeDarkMode !== true) {
Bridge.setSetting("themeDarkMode", "true");
}
if (settings.systemBarsEnabled !== true) {
Bridge.setSetting("systemBarsEnabled", "true");
}
} catch (e) {}
}
document.addEventListener("DOMContentLoaded", requestFullscreenShell);
Built-in bundled themes can use the full native bridge. Imported themes get a narrow allowlist facade. This means future native methods are not exposed to imported themes unless they are deliberately added to the external bridge.
escapeExternalTheme()| API group | Imported themes | Notes |
|---|---|---|
| Library reads, playlists reads, podcasts reads, radio reads, videos reads | External allowed | Use async or paginated methods for large lists. |
| Playback controls, queue state, current track, sleep timer, volume | External allowed | Keep changes tied to user-visible controls. |
setSetting("deviceModel"), setSetting("uiOrientationLock"), setSetting("themeDarkMode"), setSetting("systemBarsEnabled") |
External limited | Allowed only for documented fullscreen startup and system-bar visibility behavior. |
| Theme management, imports, backup/restore, permissions, review prompts | Built-in only | Blocked for imported themes. |
| Playlist/favorite mutation, podcast/radio mutation, folder include/exclude, EQ mutation | Built-in only | Official store themes should not rely on these from imported packages. |
The raw Markdown guide contains the long-form method reference and should remain the version-controlled source for detailed API notes.
The official theme listing is curated. Review reduces risk for users who install from Glideform Studio, while sideloaded ZIPs from other sources remain outside the official review process.
Use browser preview for layout screenshots, then test the actual ZIP inside oPlayer. The browser mock is not the real backend and may return simplified values.
chrome://inspect.