Repository navigation
ManualEN
English | 中文
For two audiences: (A) App developers — how to bring your Shiny app into ShinyApps; (B) ShinyApps maintainers — how the system runs, what each workflow does, and how to release and troubleshoot.
Compiled from the 2026-09/10 development and acceptance records and verified against the current repositories. When you publish this on the GitHub Wiki, split it into the pages suggested below.
| Wiki page | Content | Section(s) below |
|---|---|---|
Home |
Overview, architecture, navigation | 0, 1 |
User Guide |
Install, launcher, install/run/update/uninstall, data locations | 4 |
Developer Guide: Add your app |
Bundle build, catalog registration, icons | 2 |
Maintainer Guide: Repo & workflows |
Repo layout, each workflow's trigger/output/role | 3 |
Release Process |
Ship a shell, ship an app, ship icons, rollback | 5 |
FAQ / Troubleshooting |
Known issues and fixes | 6 |
Known Limits & Roadmap |
Open issues, suggested additions | 7 |
Contributing |
How to submit a PR upstream to shinyelectron | 8 |
ShinyApps is an Electron desktop shell/launcher that aggregates several R/Shiny apps into a single launcher page where users can install, run, update, and uninstall each app on demand. The current list of integrated apps — with description, version, supported platforms, license, and availability — is in the live app catalog (https://fentouxungui.github.io/ShinyApps/), regenerated automatically on every publish; the machine-readable manifest is catalog.json.
It is built on a fork of the open-source shinyelectron: fentouxungui/shinyelectron@multi-app-store.
┌────────────────────────────────────────────────────────────┐
│ Tier 0 · Runtime base (installed once with the shell, stays)│
│ Electron shell + portable R 4.6.1 + minimal deps (shiny) │
├────────────────────────────────────────────────────────────┤
│ Tier 1 · Shared dependency pool <userData>/lib │
│ R packages needed by >= 2 installed apps; ref-counted │
├────────────────────────────────────────────────────────────┤
│ Tier 2 · App-private deps <userData>/private/<app-id> │
│ Packages used by exactly 1 app, or version conflicts │
└────────────────────────────────────────────────────────────┘
- Only Tier 0 is hand-authored; Tier 1 / Tier 2 are computed from each bundle's dependency list plus reference counting.
- The runtime R version is pinned to 4.6.1: the shell runtime and every app bundle must be built against the same R (binary ABI must match).
| Channel | Target | Mechanism |
|---|---|---|
| Shell update | The Electron shell itself |
electron-updater + latest.yml / latest-mac.yml on the Release; silent overwrite install on quit |
| App update | A single app | The client fetches catalog.json, compares semver, and shows an Update button on the card |
| Repo | Role |
|---|---|
fentouxungui/ShinyApps |
Shell config + catalog + schemas + icons + build script + workflows |
fentouxungui/shinyelectron (multi-app-store branch) |
Electron main process / launcher / store engine / R backend |
fentouxungui/SeuratExplorer |
App: source + standalone installer + app-layer bundle CI |
fentouxungui/scConvertShiny |
App: source + standalone installer + app-layer bundle CI |
mianaz/scConvert |
Third-party R package (a scConvertShiny dependency, built via R CMD build) |
Note: a "standalone installer" packages one app into a complete desktop program (shell + runtime + that app baked in). It is a parallel product, independent of joining the ShinyApps store.
- Download
shinyapps-Setup-<ver>-x64.exe(Windows) or.dmg(macOS) from ShinyApps Releases and install it. - Open ShinyApps → the launcher appears (a grid of cards).
- Each card has state buttons:
Install→ progress →Run/Uninstall;Updateappears when a newer version exists. - After running an app, go back with Apps → Back to Launcher (or
Ctrl+L); it first asks "unsaved analysis will be lost". - Only one app runs at a time; returning to the launcher kills that app's whole R process tree.
Windows
%APPDATA%\shinyapps\
├─ state.json # installed apps and shared-library reference counts
├─ apps\<id>\<ver>\# unpacked app bundle (app/ + rlib/)
├─ lib\ # shared R library (Tier 1)
├─ private\<id>\ # app-private library (Tier 2)
├─ store-cache\ # download cache (.zip)
└─ logs\ # app-*.log (shop logs are prefixed with [store])
Install dir: %LOCALAPPDATA%\Programs\shinyapps\
Icon caching: store icons come from remote URLs in
catalog.json; if loading fails, the card falls back to the app's initial.
| Route | Description | Best for |
|---|---|---|
| A. Store / on-demand install (recommended) | Your repo publishes a prebuilt bundle to its own Release; you register it in ShinyApps' catalog/apps.yml. Users install on demand. |
Long-term apps; add apps without rebuilding the shell |
| B. Bake-in | Put app.R + dependency tarballs into the ShinyApps repo and rebuild the shell. The installer ships the app; no download. |
Offline, usable right after install, few stable apps |
Route A is described first.
-
The entry point must return a
shinyAppobject and must not callrunApp()internally. The Electron shell starts the server itself; an app callingrunApp()again conflicts. Export a function that onlyreturn(shinyApp(ui, server)), likesc_app():# scConvertShiny's exported entry library(scConvertShiny) options(shiny.launch.browser = FALSE, shiny.deprecation.messages = FALSE) sc_app()
-
It must build as a standard R source package (
R CMD build). The bundle CI uses it plusImports/Depends/LinkingToinDESCRIPTIONto compute the dependency closure. -
Versions must line up: the Release tag (e.g.
v0.1.10) minusvmust equalVersioninDESCRIPTION. Otherwise the source tarball name won't match and a broken bundle is produced (the CI now has a "source tarball missing -> stop" guard). -
R version pinned to 4.6.1 (matching the shell runtime).
Decide on an entry in your app repo (the CI writes it to app/app.R inside the bundle). SeuratExplorer's example:
library(SeuratExplorer)
options(shiny.launch.browser = FALSE, shiny.deprecation.messages = FALSE)
launchSeuratExplorer(verbose = FALSE,
ReductionKeyWords = c("umap","tsne","pca"),
SplitOptionMaxLevel = 12, MaxInputFileSize = 30 * 1024^3)If your app is an R package whose entry function does not call
runApp(), just uselibrary(<pkg>); <entry>().
Place this workflow in your app repo under .github/workflows/ (the convention is build-app-bundle.yml; the live SeuratExplorer/scConvertShiny files use prefixed names). It will:
- build on
windows-latest/macos-14with R 4.6.1; - run
R CMD build; - compute the full transitive dependency closure (
seed <- unique(c(loc_names, declared))), installing CRAN/Bioc deps as binary and local/source packages from source, all intobundle/rlib/; - write
bundle/manifest.jsonand zipapp/+rlib/+manifest.json; - assert the zip contains
rlib/(otherwise fail); - compute
sha256and upload<id>-<version>-<platform>.zipas a Release asset.
Edit these env vars at the top of the workflow:
env:
APP_ID: my-app # lowercase, [a-z0-9-], must match the id in catalog/apps.yml
APP_NAME: "My App"
APP_AUTHOR: "Your Name"
APP_DESC: "..."
APP_HOMEPAGE: "https://github.com/you/my-app"
APP_LICENSE: "MIT"
R_VERSION: "4.6.1" # do not changeAnd put your own entry code into the "Assemble app + manifest.json" step (replace the contents of writeLines(c(...))).
Asset naming contract (mandatory):
<APP_ID>-<VERSION>-<PLATFORM>.zip
e.g. seurat-explorer-0.1.10-win-x64.zip
scconvert-0.1.10-mac-arm64.zip
PLATFORM in {win-x64, win-arm64, mac-x64, mac-arm64, linux-x64}
publish-catalog.ymlrelies on exactly this pattern (<id>-<version>-<platform>.zip) to derive url / size / sha256. A wrong name means the artifact never appears in the catalog.
Two trigger options:
-
Publish a Release on GitHub (triggers
release: published); or -
Manually run
Build app bundlein Actions and fill in the tag (workflow_dispatch.inputs.tag).
Result: two zips appear as Release assets (win-x64 / mac-arm64), each tens to hundreds of MB (containing rlib/).
Pushing a tag alone does not auto-trigger the bundle workflow (only the standalone
build-desktop.ymlruns, and a Release created withGITHUB_TOKENdoes not cascade). To change behavior, userelease: published(as the live setup does) orworkflow_run.
Edit ShinyApps/catalog/apps.yml and append an entry:
apps:
- id: my-app
repo: your-name/my-app # used by gh api to fetch the latest release
name: My App
author: "Your Name"
description: "..."
homepage: "https://github.com/your-name/my-app" # About > Visit Website; also the card name link target
docs: "https://your-name.github.io/my-app/" # optional; Help > Documentation
email: "you@example.org" # optional; About > Email
copyright: "(c) 2026 Your Name" # optional; About text
license: "MIT"
icon: "https://fentouxungui.github.io/ShinyApps/icons/my-app.png"
r_version: "4.6.1"-
idmust equal the bundle'sAPP_ID; -
repomust letgh api repos/<repo>/releases/latestreach the latest Release; -
iconis an absolute URL (in store mode the icon comes from the catalog, not from_shinyelectron.yml). -
homepage/docs/email/author/copyrightfill the running app's Help / About; unset values fall back to the shell's own, or the item is omitted.
Pushing catalog/apps.yml to main triggers Publish catalog; you can also run it manually. It publishes catalog.json to gh-pages:
https://fentouxungui.github.io/ShinyApps/catalog.json
Restart the ShinyApps shell → the new card appears → Install → progress → Run.
Recommended: add a
repository_dispatchstep (types: [bundle-updated]) at the end of your app's bundle workflow to notify ShinyApps to refresh the catalog (publish-catalog.ymlalready listens for that event). Otherwise you must wait for the 10-minute schedule or run it manually after each new bundle.
-
Card icon (per app): put
<id>.png(512x512, transparent) intoShinyApps/icons/and sethttps://fentouxungui.github.io/ShinyApps/icons/<id>.pngincatalog/apps.yml.publish-catalog.ymlsyncsicons/to gh-pages so the URL resolves. -
Shell program icon (.exe/.dmg icon):
icons/shinyapps.png(>=1024),icons/ico/shinyapps.ico,icons/mac/shinyapps.icns;build-suite.Rselects per platform and passes it viaexport(icon=). - Note:
apps[].iconin_shinyelectron.ymlhas no effect in store mode (icons come from the catalog). Do not rely on it. - A failed icon load falls back to the initial, without error.
To ship an app inside the ShinyApps installer (no store):
-
Entry: create
ShinyApps/apps/<id>/app.R(same entry code as above). -
Dependency source packages: put the app and its local deps'
*.tar.gzintoShinyApps/dependency/. -
Configure
ShinyApps/_shinyelectron.yml:- list the tarballs in
dependencies.r.local_packages(repo-relative, e.g.dependency/SeuratExplorer_0.1.9.tar.gz); - list the full dependency closure in
dependencies.extra_packages/dependencies.r.packages(renvonly scansapp.Rsource and will miss the package's ownImports, so list them explicitly); - add an item to the
apps:array as{ id, name, description, path: ./apps/<id> }.
- list the tarballs in
-
Rebuild the shell: push a
v*tag (or manually runBuild ShinyApps desktopwith a tag).
Trade-offs: offline-capable with no install step; but a larger installer, and every add/change of an app means re-releasing the shell (updating an app equals updating the whole shell).
ShinyApps/
├─ _shinyelectron.yml # shell config (app metadata, runtime strategy, deps, apps[], updates)
├─ build-suite.R # build script: auto-set version from tag -> shinyelectron::export()
├─ shared-library-policy.md # shared-library & compatibility contract (tiers, ref-counting)
├─ apps/
│ ├─ seurat-explorer/app.R # bake-in entry (Route B)
│ └─ scconvert/app.R
├─ dependency/ # R source tarballs for bake-in
│ ├─ SeuratExplorer_0.1.9.tar.gz ├─ presto-1.1.0.tar.gz
│ ├─ scConvertShiny_0.1.1.tar.gz └─ scConvert-0.2.1.tar.gz
├─ catalog/
│ └─ apps.yml # the only hand-maintained app registry
├─ schemas/
│ ├─ catalog.schema.json # server catalog schema
│ ├─ manifest.schema.json # bundle manifest.json schema
│ ├─ state.schema.json # local state.json schema
│ └─ catalog.json # example
├─ icons/
│ ├─ seurat-explorer.png scconvert.png
│ ├─ shinyapps.png shinyapps-512.png
│ ├─ ico/shinyapps.ico # Windows program icon
│ └─ mac/shinyapps.icns # macOS program icon
└─ .github/workflows/
├─ build-desktop.yml # build shell installers + release
└─ publish-catalog.yml # generate catalog.json + publish icons to gh-pages
gh-pages branch (publishing output, maintained automatically by workflows):
gh-pages/
├─ catalog.json
└─ icons/<id>.png
| Workflow | Repo | Triggers | Output |
|---|---|---|---|
Build ShinyApps desktop (build-desktop.yml) |
ShinyApps | push tag v*; manual (input tag) |
shinyapps-Setup-<ver>-x64.exe/.dmg + latest*.yml + .blockmap as Release assets |
Publish catalog (publish-catalog.yml) |
ShinyApps | cron every 10 min; manual; repository_dispatch: [bundle-updated]; push main (changing catalog/apps.yml or icons/**) |
catalog.json + icons/ on gh-pages
|
Build app bundle (*-build-app-bundle.yml) |
Each app repo |
release: published; manual (input tag) |
<id>-<ver>-<platform>.zip (app/+rlib/+manifest.json) as that app's Release asset |
standalone installer (build-desktop.yml) |
Each app repo | push tag v*
|
Independent full installer for that app (unrelated to the ShinyApps store) |
-
Triggers:
push: tags: ['v*']; manualworkflow_dispatch(inputtag). -
Jobs:
-
build(matrix:windows-latest/macos-latest):-
checkout→r-lib/actions/setup-r(use-public-rspm) →setup-node(node 24); - install
fentouxungui/shinyelectron@multi-app-store+rlang/withr/renvviapak; - macOS additionally
brew install hdf5 pkg-configand exportsPKG_CONFIG_PATH/HDF5_*(for scConvert's configure); -
APP_VERSION=${{ inputs.tag || github.ref_name }}, thensource("build-suite.R"); - upload
build/electron-app/dist/*.exe|.dmg|.blockmap|latest*.yml.
-
-
release: conditionrelease || tag v* || inputs.tag; download artifacts →softprops/action-gh-release(generate_release_notes: true).
-
-
Version: do not hand-edit
_shinyelectron.yml—build-suite.RtakesAPP_VERSION, stripsv, patches onlyapp.version, thenexport(). Locally withoutAPP_VERSION, it stays as committed. -
Program icon:
build-suite.Rpicks an icon undericons/ico(Windows) /icons/mac(macOS) and passes it toexport(icon=).
-
Triggers:
schedule: cron '*/10 * * * *';workflow_dispatch;repository_dispatch: types: [bundle-updated];push mainfor pathscatalog/apps.ymloricons/**. -
Steps:
- Read
catalog/apps.yml; for each app,gh api repos/<repo>/releases/latest; - scan asset names
<id>-<version>-<platform>.zip(version must equal the Release tag minusv) and extractbrowser_download_url/size/digest(sha256); - generate
catalog/catalog.json(schema/updated_at/shell_min_version/apps[]); - push
catalog.jsonandicons/togh-pagesvia a worktree; -
skip the commit when nothing changed (ignoring
updated_at) to avoid empty commits every 10 minutes.
- Read
- Note: scheduled jobs run only on the default branch and GitHub often delays them (minutes or more).
-
Triggers:
release: published;workflow_dispatch(inputtag). -
matrix:
windows-latest -> win-x64,macos-14 -> mac-arm64. -
Key logic:
-
r-version: 4.6.1; -
R CMD build --no-build-vignettes --no-manual; scConvertShiny alsogit clone mianaz/scConvertthenR CMD build; - derive declared deps from
DESCRIPTION(Depends/Imports/LinkingTo),seed <- unique(c(loc_names, declared)), thentools::package_dependencies(..., recursive=TRUE)for the full transitive closure; - install CRAN/Bioc deps with
type="binary"and local source packages withtype="source"(local tarballs cannot be installed as binary); - write
manifest.json(see 3.4),zip::ziprthe bundle and assertrlib/is present, compute sha256 intometa-<platform>.json; - the
releasejob appends the zips to the corresponding Release.
-
catalog.json (gh-pages, fetched by clients) — schemas/catalog.schema.json
manifest.json (inside a bundle, downloaded with the app) — schemas/manifest.schema.json
{
"schema": 1,
"id": "seurat-explorer", "name": "SeuratExplorer", "version": "0.1.10",
"author": "...", "description": "...", "homepage": "...", "license": "...",
"runtime": "r-shiny",
"entry": "app/app.R",
"platform": "win-x64",
"r_version": "4.6.1",
"min_shell_version": "0.1.0",
"notes": "optional: known platform limitations",
"packages": [ { "name": "Seurat", "version": "5.x", "path": "rlib/Seurat", "source": "cran" } ]
}state.json (local %APPDATA%\shinyapps\state.json) — schemas/state.schema.json
{
"schema": 1,
"apps": { "seurat-explorer": { "version": "0.1.10", "platform": "win-x64", "dir": "...", "packages": ["Seurat", "..."] } },
"shared": { "Seurat": { "version": "5.x", "refs": ["seurat-explorer", "scconvert"] } }
}-
Compatibility baseline: R 4.6.1; packages that must share one version:
Seurat,SeuratObject,ggplot2,DT,hdf5r. -
Placement rules (computed, not authored):
- a package name needed by >= 2 installed apps at the same version -> shared library
<userData>/lib; - needed by exactly 1 app, or a version different from the shared pool -> private library
<userData>/private/<app-id>; - at runtime
R_LIBS = <private lib> : <shared lib>(private wins).
- a package name needed by >= 2 installed apps at the same version -> shared library
-
Reference counting: on install, same version ->
refs += app, absent -> copy andrefs=[app], version conflict -> private lib; on uninstall, remove the app from refs and delete the shared package only whenrefsis empty; on update, unpack the new version, add new refs, release dropped refs, and delete the old dir last (rollback-safe).
The launcher is in store mode: it renders a card grid (name / description / icon; falls back to initial on failure), fetches catalog.json (cached in-process; a restart is the most reliable refresh), compares catalog.version with the installed version in state.json via semver, and shows Install / Run / Update / Stop / Uninstall.
- Fetch catalog -> choose the platform artifact;
-
Download: HTTP Range resume, 5 retries, 60s idle timeout, real progress from
content-length(downloading N / M MB); cache dirstore-cache/; -
Verify: downloaded byte count == catalog
size, andsha256matches; -
Unzip: built-in zero-dependency ZIP extractor (Node
zlibonly; stored/deflate + ZIP64 + zip-slip protection) toapps/<id>/<version>/; -
Install deps: copy packages from
rlib/missing in the shared lib into<userData>/lib, same version ->refs+1; version conflict -> private lib; - Write
state.json. -
Feedback: the card shows the current step (
downloading %→verifying size→verifying checksum→unpacking→linking packages); on failure it shows which step failed and why — e.g.Install failed at step "verify": size mismatch (catalog N bytes, downloaded M bytes)— and the message persists until the next attempt.
- At runtime
R_LIBS = private lib : shared lib, startingapp/app.Rwith the portable R (reusingnative-r.js). - Returning to the launcher (menu /
Ctrl+L/ in-app back) does: confirm unsaved work first -> on confirmstop()the whole R process tree (Windowstaskkill /PID <pid> /T /F) -> wait forstatus.phase === 'app_exit'or a timeout fallback -> load the launcher. - Only one app backend runs at a time. On the launcher, the
Appsmenu is hidden (avoids a meaningless "Back to Launcher"). -
Card name → homepage: hovering an app name shows “click to learn more”; clicking it opens the app's catalog
homepagein the default browser. Apps without ahomepageshow a plain, non-clickable name. -
Per-app Help / About: while an app runs, the App-menu label, Help > Documentation, and the About dialog use that app's
name/version/description/author/copyright/homepage/email/docs; on the launcher they fall back to the shell (ShinyApps).
-
Shell update: checked at startup and, on the launcher, via
About -> Check for Updates;electron-updaterreads the Releaselatest*.yml, compares versions, downloads (.blockmapdelta), and runsquitAndInstall()on quit for a silent overwrite. Caveat: unsigned builds download but fail to install. -
App update: catalog version > installed version -> the card shows
Update; clicking stops the backend -> download -> verify -> unpack to a new version dir -> atomic switch -> recompute ref counts -> delete the old dir. When done,main.js'sdoneevent carriesop, andlauncher.htmloptimistically clearsUpdate(so a delayed/missed echo no longer leaves a stale button).- While a catalog app is running,
Help -> About -> Check for Updatestargets that app (same catalog version as the card'sUpdate): if newer and confirmed, it stops the app, returns to the launcher, and runs the update (progress/failure shown on the card).
- While a catalog app is running,
Stop the backend -> delete the app dir and private lib -> refs-1 on shared packages, delete only when refs reach zero.
- App repo: bump
VersioninDESCRIPTIONand commit; - tag (e.g.
v0.1.11) and publish a Release (or manually runBuild app bundlewith the tag); - confirm both platforms'
<id>-<ver>-<platform>.zipare uploaded and the size is normal (not a few KB; must containrlib/); - trigger
Publish catalog(push, manual, orrepository_dispatchfrom the app workflow) and confirm the app's version/sha256 updated incatalog.json; - restart the ShinyApps client -> the card shows
Update-> verify.
- Edit shell files (
_shinyelectron.yml,build-suite.R, icons, ...); no manual version bump needed; - push a
vX.Y.Ztag (or manually runBuild ShinyApps desktopwith the tag); - confirm the Release has
.exe/.dmg + latest*.yml + .blockmap; - (To actually enable shell auto-update) configure a code-signing certificate.
Put the PNG into icons/ -> push (triggers publish-catalog.yml) -> confirm https://fentouxungui.github.io/ShinyApps/icons/<id>.png returns 200 -> restart the shell.
| Symptom | Root cause | Fix |
|---|---|---|
Update still shows after updating |
UI refresh relied on a single async echo, which can be missed during long updates |
launcher.html now clears Update optimistically via done(op); update the shell |
| Install progress stuck at 0%, no error | Downloads were truncated (case-insensitive Cache/ collision; no progress/timeout/integrity checks) |
Fixed: HTTP Range resume + 5 retries + size check + 60s idle timeout + store-cache/
|
| Card icons missing | No icons/ on gh-pages, or CSP blocks them |
Use the latest publish-catalog.yml to sync icons/; launcher.html allows img-src https:; falls back to initial |
| Icon has a blue background / too small |
.app-icon had a background, small size |
Fixed: transparent background when an image exists, container 64px |
| Shell won't open, exits at startup |
appstore.js wasn't packaged (require('./backends/appstore') fails) |
Ensure appstore.js is in inst/electron/backends/ and listed in R/build-templates.R's copy list |
| Bundle zip is only ~2.5 KB | Only app/+manifest.json were zipped; rlib/ missing |
Use zip::zipr and assert rlib/; the CI now has a guard |
Bundle CI says not available as a binary
|
A local source tarball can't use type="binary"
|
Local packages use type="source"; CRAN/Bioc closure uses binary
|
Missing transitive deps (e.g. RANN) |
Closure expanded only from loc_names, missing declared
|
seed <- unique(c(loc_names, declared)) |
| macOS build fails on scConvert | configure can't find HDF5 |
brew install hdf5 pkg-config and export PKG_CONFIG_PATH/HDF5_*
|
Tag / DESCRIPTION version mismatch -> broken bundle |
Workflow can't find Pkg_<ver>.tar.gz
|
Align versions; the CI now has a "source tarball missing -> stop" guard |
| Shell auto-update downloads but won't install | Not signed | Buy/configure code signing (signing.sign is currently false) |
Windows scConvert conversion reports H5Fclose
|
Known limitation of CRAN hdf5r bundling HDF5 1.12.1 |
See section 7, deferred |
Apps -> Back to Launcher throws ReferenceError
|
leaveToLauncher scoping |
Ensure it is at module top level (upstream PR prepared) |
-
Platforms: the
bundledportable-R strategy is Windows / macOS only (Linux needssystem); bundle CI currently produceswin-x64andmac-arm64only. -
Windows scConvert conversion: CRAN
hdf5rships HDF5 1.12.1 and theH5Fclosefinalizer can fail during GC (uncatchable). Noted inmanifest.notes; deferred. - Code signing: unsigned Windows/macOS -> SmartScreen/Gatekeeper warnings; shell auto-update downloads but cannot install.
-
Disk duplication: after install,
apps/<id>/<ver>/rlib/duplicates the sharedlib/;store-cache/zips are not pruned. Suggest deletingrlib/after linking and pruning the cache. - State loss on app switch: only one app runs at a time; returning kills the process and unsaved analysis is lost (a confirmation dialog is shown).
-
Catalog refresh depends on the schedule or a manual run: an app release does not auto-notify ShinyApps (unless
repository_dispatchis added). -
Licenses:
shinyelectronis AGPL-3.0;SeuratExploreris GPL-3.0-or-later;scConvertShinyis MIT. Respect each obligation when redistributing.
High priority
-
README.md(repo home): the repo lacks a newcomer entry point. Include a one-line intro, architecture diagram, quick start, and links to the Wiki pages. -
LICENSEandTHIRD-PARTY-NOTICES: state ShinyApps' own license and list shinyelectron (AGPL-3.0), each app, and third-party R packages (Seurat, scConvert, ...) with their obligations. -
"Add an app" template + validation: a copy-paste
build-app-bundle.ymltemplate andapps.ymlsnippet, plus a CI/script that validates the contract (legalid,id-ver-platform.zipnaming, tag ==DESCRIPTIONversion,r_version == 4.6.1, zip containsrlib/). -
Auto-refresh the catalog: add
repository_dispatch: [bundle-updated]at the end of each app's bundle workflow, turning "manually run Publish catalog" into automatic. - Compatibility matrix: a single table of "shell version x runtime R version x required shared-package baseline" so app developers know what to build against.
- Code-signing guide: Windows (CSC_LINK/CSC_KEY_PASSWORD) and macOS (notarization) steps; explain auto-update behavior before signing.
Medium priority
- Release checklist / rollback runbook: turn section 5 into a checklist; add "how to roll back a bad app version / bad shell version".
-
Expanded troubleshooting: add "how to read the
[store]lines in%APPDATA%\shinyapps\logs\app-*.log". - Test checklist: menu return, both branches of the unsaved prompt, repeated switching, a real conversion, process cleanup, exit without leftovers, large files, rapid clicking, cold-start time/memory — usable as pre-release acceptance.
-
Space optimization: implement "delete the bundle
rlib/after install" and "prunestore-cache", and document the savings. -
Security note: treat catalog and bundles as untrusted input; HTTPS only; verify
sha256(consider adding signatures/verification later). - Screenshots and GIFs: launcher, install progress, update prompt, return-confirmation dialog — greatly improves Wiki readability.
- Bilingual coverage: at least Home and Quick Start in both languages.
Low priority / long term
-
CHANGELOG.md: version history for the shell and apps; the catalog already has achangelogfield for the update dialog. - App detail page: expand a card to show author/license/version/changelog (the catalog already carries these fields).
- Multi-language / theme / search: launcher UX enhancements.
-
Contribution and governance:
CONTRIBUTING.md,CODE_OF_CONDUCT.md, Issue/PR templates. - CI end-to-end test: a minimal "unzip -> validate manifest -> smoke start" check on the produced bundle in CI.
The multi-app-store branch mixes general shell capabilities with project-specific logic, so do not open it as one PR. Its most general piece — confirm before returning to the launcher + hide the Apps menu on the launcher — has been prepared as a clean patch containing only inst/electron/shared/main.js, generated against upstream main:
git remote add upstream https://github.com/coatless-rpkg/shinyelectron # skip if it exists
git fetch upstream
git checkout -b confirm-back-to-launcher upstream/main
git apply feature1-unsaved-prompt.patch
git add inst/electron/shared/main.js
git commit -m "Confirm before returning to the launcher; hide Apps menu on launcher"
git push origin confirm-back-to-launcherThen open a PR against coatless-rpkg:main. The store/installer code should go through a separate issue or later PR.
app: { name: "ShinyApps", version: "0.1.0", slug: "shinyapps" }
build: { type: "r-shiny", runtime_strategy: "bundled" }
installer: { app_id: "com.shinyapps.desktop" }
signing: { sign: false }
dependencies:
extra_packages: [SeuratExplorer, presto, Seurat, SeuratObject, ggplot2, DT,
scConvertShiny, scConvert, hdf5r, crayon, shiny, shinydashboard, callr, zip]
r:
version: "4.6.1"
local_packages:
- "dependency/SeuratExplorer_0.1.9.tar.gz"
- "dependency/presto-1.1.0.tar.gz"
- "dependency/scConvertShiny_0.1.1.tar.gz"
- "dependency/scConvert-0.2.1.tar.gz"
updates:
enabled: true
provider: "github"
check_on_startup: true
auto_download: true
auto_install: true
github: { owner: "fentouxungui", repo: "ShinyApps" }
apps:
- { id: seurat-explorer, name: "SeuratExplorer", path: "./apps/seurat-explorer" }
- { id: scconvert, name: "scConvertShiny", path: "./apps/scconvert" }The version is auto-patched by
build-suite.Rfrom the tag; do not hand-edit it when releasing.
schema: 1
shell_min_version: "0.1.0"
apps:
- id: <lowercase unique id>
repo: <owner/repo> # gh api fetches the latest release
name: <display name>
author: <author> # About text
description: <description> # About text
homepage: <URL> # About > Visit Website; also the card name link target
docs: <URL> # optional; Help > Documentation
email: <address> # optional; About > Email
copyright: <text> # optional; About text
license: <SPDX>
icon: https://fentouxungui.github.io/ShinyApps/icons/<id>.png
r_version: "4.6.1"library(<YourPkg>)
options(shiny.launch.browser = FALSE, shiny.deprecation.messages = FALSE)
<entry_function>() # must return a shinyApp object; do not runApp()| Term | Meaning |
|---|---|
| shell | The Electron desktop program itself (with portable R runtime) |
| bundle | A single app's prebuilt package: app/ + rlib/ + manifest.json
|
| catalog |
catalog.json hosted on gh-pages: app list + download URLs/checksums |
| runtime layer | Tier 0, the one-time base shipped with the shell |
| shared library | Tier 1, <userData>/lib, reference-counted |
| private library | Tier 2, <userData>/private/<id>
|
| R_LIBS | R package search path; run order = private lib : shared lib |
Compiled by an Open-Science Agent from the 2026-09/10 development and acceptance session, verified against the current ShinyApps / shinyelectron@multi-app-store / app repos. If the repos change, the files there are authoritative.
ShinyApps · Repository · Releases · Issues · Manual (EN) · 使用手册(中文) · catalog.json
Maintained by Zhang Yongchao · Built on shinyelectron (AGPL-3.0) · Wiki content is community-maintained; the code in each repository is authoritative. / 维护者:Zhang Yongchao · 基于 shinyelectron(AGPL-3.0)· 文档为社区维护,以各仓库代码为准。
{ "schema": 1, "updated_at": "2026-10-08T07:10:25Z", "shell_min_version": "0.1.0", "apps": [ { "id": "seurat-explorer", "name": "SeuratExplorer", "version": "0.1.10", "author": "...", "description": "...", "homepage": "...", "license": "...", "icon": "https://fentouxungui.github.io/ShinyApps/icons/seurat-explorer.png", "r_version": "4.6.1", "artifacts": { "win-x64": { "url": "https://.../seurat-explorer-0.1.10-win-x64.zip", "size": 215698175, "sha256": "ac4d81..." }, "mac-arm64": { "url": "https://.../seurat-explorer-0.1.10-mac-arm64.zip", "size": 199743796, "sha256": "871245..." } } } ] }