Repository navigation
ManualZH
English | 中文
面向两个读者:(A) App 开发者 —— 如何把你开发的 Shiny App 接入 ShinyApps;(B) ShinyApps 维护者 —— 整个系统的运行过程、每个 workflow 的职责、发布与排障。
英文版见 ShinyApps User Manual (EN)。本文档基于 2026-09/10 的实机开发与验收记录整理,并对照当前仓库状态核对。建议放到 GitHub Wiki 时按下方「建议的 Wiki 页面拆分」拆成多页。
| Wiki 页面 | 内容 | 对应本文档章节 |
|---|---|---|
Home |
项目简介、架构总览、快速导航 | 第 0、1 节 |
用户指南 |
安装、启动页、安装/运行/更新/卸载、数据位置 | 第 4 节 |
开发者指南:接入你的 App |
bundle 打包、catalog 登记、图标 | 第 2 节 |
维护者指南:仓库与工作流 |
仓库结构、每个 workflow 的触发/产物/职责 | 第 3 节 |
发布流程 |
发壳、发 app、发图标、回滚 | 第 5 节 |
故障排查 FAQ |
已知问题与解决办法 | 第 6 节 |
已知限制与路线图 |
未解决问题、建议补充 | 第 7 节 |
贡献指南 |
向上游 shinyelectron 提交 PR | 第 8 节 |
GitHub Wiki 没有内置多语言,用以下任一种方式即可:
-
每个页面顶部放一行(本文档已采用):
[English](ManualEN) | **中文**; -
用
_Sidebar.md(推荐):它在所有 Wiki 页面都显示,等于全站语言开关。仓库里已附一份_Sidebar.md,中文/英文链接都指向ManualEN/ManualZH。
本文档约定使用纯字母页名:英文页
ManualEN,中文页ManualZH(不含任何连字符/标点,避免中文输入法把-打成全角「‐」)。
ShinyApps 是一个 Electron 桌面「外壳 / 启动器」,把多个 R/Shiny 应用聚合到一个启动页里,用户可以按需安装、运行、更新、卸载每个 App。当前可用应用(含描述、版本、支持平台、许可与是否可用)见 在线应用目录(https://fentouxungui.github.io/ShinyApps/),每次发布自动重新生成;机器可读清单为 catalog.json。
它基于开源项目 shinyelectron 的一个分支:fentouxungui/shinyelectron@multi-app-store。
┌────────────────────────────────────────────────────────────┐
│ Tier 0 · 运行时底座(随安装包装一次,常驻,不卸载) │
│ Electron 壳 + 便携 R 4.6.1 + 最小启动依赖(shiny 等) │
├────────────────────────────────────────────────────────────┤
│ Tier 1 · 共享依赖池 <userData>/lib │
│ 被 ≥2 个已安装 App 用到的 R 包,按引用计数管理 │
├────────────────────────────────────────────────────────────┤
│ Tier 2 · App 私有依赖 <userData>/private/<app-id> │
│ 只被 1 个 App 用到的包,或版本与共享池冲突的包 │
└────────────────────────────────────────────────────────────┘
- 只有 Tier 0 是人工写死的;Tier 1 / Tier 2 由每个 bundle 的依赖清单 + 引用计数自动计算。
- 运行时 R 版本固定为 4.6.1:壳的运行时和所有 App bundle 都必须用同一个 R 构建(二进制 ABI 必须一致)。
| 通道 | 对象 | 机制 |
|---|---|---|
| 壳更新 | Electron 壳本身 |
electron-updater + Release 里的 latest.yml / latest-mac.yml,退出时静默覆盖安装 |
| App 更新 | 单个 App | 客户端拉 catalog.json,按 semver 比对,卡片出现 Update
|
| 仓库 | 角色 |
|---|---|
fentouxungui/ShinyApps |
壳的配置 + catalog + schemas + 图标 + 构建脚本 + workflow |
fentouxungui/shinyelectron(分支 multi-app-store) |
Electron 主进程 / 启动器 / 商店引擎 / R 后端 |
fentouxungui/SeuratExplorer |
App:源码 + standalone 安装器 + app-layer bundle CI |
fentouxungui/scConvertShiny |
App:源码 + standalone 安装器 + app-layer bundle CI |
mianaz/scConvert |
第三方 R 包(scConvertShiny 的依赖,用 R CMD build 现建) |
说明:「standalone 安装器」= 某个 App 自己独立打包成一个完整桌面程序(把壳 + 运行时 + 该 App 全烤进去),与「接入 ShinyApps 商店」是两条并行、互不干扰的产物。
- 从 ShinyApps Releases 下载
shinyapps-Setup-<ver>-x64.exe(Windows)或.dmg(macOS)并安装。 - 打开 ShinyApps → 显示启动页(卡片网格)。
- 每张卡片有状态按钮:
Install→ 进度 →Run/Uninstall;有新版时出现Update。 - 运行 App 后,回启动页用 Apps → Back to Launcher(或
Ctrl+L);会先弹「未保存分析将丢失」确认。 - 同一时刻只运行一个 App;切回启动页会杀掉当前 App 的整个 R 进程树。
Windows
%APPDATA%\shinyapps\
├─ state.json # 已安装 App 与共享库引用计数
├─ apps\<id>\<ver>\# 解压后的 App bundle(app/ + rlib/)
├─ lib\ # 共享 R 库(Tier 1)
├─ private\<id>\ # App 私有库(Tier 2)
├─ store-cache\ # 下载缓存(.zip)
└─ logs\ # app-*.log(含 [store] 前缀的商店日志)
安装目录:%LOCALAPPDATA%\Programs\shinyapps\
图标缓存问题:商店图标来自
catalog.json的远程 URL;若加载失败,卡片会回退显示首字母。
| 方式 | 说明 | 适合 |
|---|---|---|
| A. 商店 / 按需安装(推荐) | 你的仓库自己产出预编译 bundle 发到自己的 Release;在 ShinyApps 的 catalog/apps.yml 登记即可。用户按需下载安装。 |
长期维护、希望加 App 不动壳 |
| B. 打进壳(bake-in) | 把 app.R + 依赖 tarball 放进 ShinyApps 仓库,重新构建壳。安装包即含该 App,无需下载。 |
离线、首装即用、App 很少且稳定 |
下面先讲推荐的 方式 A。
-
入口必须返回一个
shinyApp对象,不能在内部调用runApp()。因为 Electron 壳自己负责启动服务;App 里再runApp()会冲突。推荐像sc_app()那样导出一个「只return(shinyApp(ui, server))」的函数:# scConvertShiny 导出的入口 library(scConvertShiny) options(shiny.launch.browser = FALSE, shiny.deprecation.messages = FALSE) sc_app()
-
能产出一个标准 R 源码包(
R CMD build)。bundle CI 会用它 +DESCRIPTION里的Imports/Depends/LinkingTo计算依赖闭包。 -
版本号要能对上:Release tag(如
v0.1.10)去掉v必须等于DESCRIPTION里的Version。否则源码 tarball 名对不上,会产出坏包(CI 已有「找不到源码包就stop」的守卫)。 -
R 版本固定 4.6.1(与壳运行时一致)。
自动化捷径: 下列步骤可由可复用工具包 fentouxungui/shinyapps-onboarding 全程自动完成——fork、bundle 工作流、tag/release、catalog 登记 + 图标、以及上游 PR。内含双模式 workflow 模板(扁平 app 与 R 包 app)、catalog 条目片段、驱动脚本与两个真实示例。
在 App 仓库里确定一段入口(下面以 SeuratExplorer 为例,CI 会把它写成 bundle 里的 app/app.R):
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)如果你的 App 是 R 包且入口函数不会自己
runApp(),直接用library(<pkg>); <entry>()即可。
把下面这个 workflow 放到 你的 App 仓库 的 .github/workflows/(当前命名建议 build-app-bundle.yml;现网 SeuratExplorer/scConvertShiny 用的是带前缀的名字)。它会:
- 在
windows-latest/macos-14两个 runner 上,用 R 4.6.1 构建; -
R CMD build出源码包; - 计算完整传递依赖闭包(
seed <- unique(c(loc_names, declared))),CRAN/Bioc 依赖用二进制装、本地/源码包用源码装,全部装进bundle/rlib/; - 写出
bundle/manifest.json,并把app/+rlib/+manifest.json打成 zip; - 断言 zip 里必须含
rlib/(否则报错退出); - 计算
sha256,上传为 Release 资产<id>-<version>-<platform>.zip。
你需要在 workflow 顶部改这些环境变量:
env:
APP_ID: my-app # 小写、[a-z0-9-],必须与 catalog/apps.yml 的 id 一致
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" # 不要改并把你自己的入口代码写进「Assemble app + manifest.json」那一步(替换 writeLines(c(...)) 里的内容)。
产物命名契约(必须遵守):
<APP_ID>-<VERSION>-<PLATFORM>.zip
例:seurat-explorer-0.1.10-win-x64.zip
scconvert-0.1.10-mac-arm64.zip
PLATFORM ∈ {win-x64, win-arm64, mac-x64, mac-arm64, linux-x64}
publish-catalog.yml正是靠这个命名(<id>-<version>-<platform>.zip)自动解析 url / size / sha256。名字不对 → catalog 里不会出现该产物。
两种触发方式(二选一):
- 在 GitHub 上发布 Release(触发
release: published);或 - Actions 里手动跑
Build app bundle,填写 tag(workflow_dispatch.inputs.tag)。
结果:Release 资产里出现两个 zip(win-x64 / mac-arm64),每个几十到几百 MB(含 rlib/)。
只推 tag 不会自动触发 bundle workflow(默认只跑 standalone 的
build-desktop.yml,而GITHUB_TOKEN创建的 Release 不会级联触发)。要特定行为可改成release: published触发(现网即如此)或workflow_run。
编辑 ShinyApps/catalog/apps.yml,追加一项:
apps:
- id: my-app
repo: your-name/my-app # 用于 gh api 拉 latest release
name: My App
author: "Your Name"
description: "..."
homepage: "https://github.com/your-name/my-app" # About > Visit Website;同时是卡片名字链接目标
docs: "https://your-name.github.io/my-app/" # 可选;Help > Documentation
email: "you@example.org" # 可选;About > Email
copyright: "(c) 2026 Your Name" # 可选;About 文本
license: "MIT"
icon: "https://fentouxungui.github.io/ShinyApps/icons/my-app.png"
r_version: "4.6.1"-
id必须等于 bundle 的APP_ID; -
repo必须让gh api repos/<repo>/releases/latest能拿到最新 Release; -
icon是绝对 URL(商店模式图标来自 catalog,而不是_shinyelectron.yml)。 -
homepage/docs/email/author/copyright用于填充运行中 App 的 Help / About;未填则回退到外壳自身的值,或该项不显示。
push catalog/apps.yml 到 main 即触发 Publish catalog;也可到 Actions 手动跑。它会把 catalog.json 发到 gh-pages:
https://fentouxungui.github.io/ShinyApps/catalog.json
重启 ShinyApps 壳 → 启动页出现新卡片 → Install → 进度 → Run。
建议:在 App 自己的 bundle workflow 末尾加一步
repository_dispatch(types: [bundle-updated])通知 ShinyApps 刷新 catalog(publish-catalog.yml已监听该事件)。否则每次发新 bundle 后需等 10 分钟定时任务或手动跑。
-
卡片图标(每个 App):把
<id>.png(建议 512×512、透明背景)放进ShinyApps/icons/,在catalog/apps.yml里写https://fentouxungui.github.io/ShinyApps/icons/<id>.png。publish-catalog.yml会把icons/一并同步到 gh-pages(图标 URL 才可访问)。 -
壳的程序图标(.exe/.dmg 图标):
icons/shinyapps.png(≥1024)、icons/ico/shinyapps.ico、icons/mac/shinyapps.icns;由build-suite.R按平台选择并通过export(icon=)传入。 - 注意:
_shinyelectron.yml里的apps[].icon在商店模式下不生效(图标来自 catalog),不要指望它。 - 图标加载失败会回退成首字母,不会报错。
当你想「下载即用、不经过商店」,把 App 直接烤进 ShinyApps 安装包:
-
入口:新建
ShinyApps/apps/<id>/app.R(同上文的入口代码)。 -
依赖源码包:把 App 及其本地依赖的
*.tar.gz放进ShinyApps/dependency/。 -
配置
ShinyApps/_shinyelectron.yml:-
dependencies.r.local_packages列出上一步的 tarball(仓库相对路径,如dependency/SeuratExplorer_0.1.9.tar.gz); -
dependencies.extra_packages/dependencies.r.packages列出完整依赖闭包(renv只扫app.R源码,扫不到 App 包内部的Imports,必须显式列出); -
apps:数组增加一项{ id, name, description, path: ./apps/<id> }。
-
-
重构建壳:推一个
v*tag(或手动跑Build ShinyApps desktop并填 tag)。
优缺点:离线可用、无安装步骤;但安装包更大、每次加/改 App 都要重发壳、且更新 App 等于更新整个壳。
ShinyApps/
├─ _shinyelectron.yml # 壳的配置(app 元数据、运行时策略、依赖、apps 数组、updates)
├─ build-suite.R # 构建脚本:由 tag 自动设置版本 → shinyelectron::export()
├─ shared-library-policy.md # 共享库与兼容基线的契约(Tier 规则、引用计数)
├─ apps/
│ ├─ seurat-explorer/app.R # bake-in 入口(方式 B)
│ └─ scconvert/app.R
├─ dependency/ # bake-in 用的 R 源码包 tarball
│ ├─ 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 # 唯一手工维护的 App 登记表
├─ schemas/
│ ├─ catalog.schema.json # 服务端 catalog 的 schema
│ ├─ manifest.schema.json # bundle 内 manifest.json 的 schema
│ ├─ state.schema.json # 本地 state.json 的 schema
│ └─ catalog.json # 示例
├─ icons/
│ ├─ seurat-explorer.png scconvert.png
│ ├─ shinyapps.png shinyapps-512.png
│ ├─ ico/shinyapps.ico # Windows 程序图标
│ └─ mac/shinyapps.icns # macOS 程序图标
└─ .github/workflows/
├─ build-desktop.yml # 构建壳安装器 + 发 Release
└─ publish-catalog.yml # 生成 catalog.json + 同步 icons 到 gh-pages
gh-pages 分支(发布产物,由 workflow 自动维护):
gh-pages/
├─ catalog.json
└─ icons/<id>.png
| Workflow | 所在仓库 | 触发 | 产物 |
|---|---|---|---|
Build ShinyApps desktop (build-desktop.yml) |
ShinyApps | push tag v*;手动(输入 tag) |
shinyapps-Setup-<ver>-x64.exe/.dmg + latest*.yml + .blockmap,作为 Release 资产 |
Publish catalog (publish-catalog.yml) |
ShinyApps | cron 每 10 分钟;手动;repository_dispatch: [bundle-updated];push main(改 catalog/apps.yml 或 icons/**) |
gh-pages 上的 catalog.json + icons/
|
Build app bundle (*-build-app-bundle.yml) |
各 App 仓库 |
release: published;手动(输入 tag) |
<id>-<ver>-<platform>.zip(app/+rlib/+manifest.json),作为该 App Release 资产 |
standalone 安装器 (build-desktop.yml) |
各 App 仓库 | push tag v*
|
该 App 的独立完整安装器(与 ShinyApps 商店无关) |
-
触发:
push: tags: ['v*'];手动workflow_dispatch(输入tag)。 -
jobs:
-
build(matrix:windows-latest/macos-latest):-
checkout→r-lib/actions/setup-r(use-public-rspm)→setup-node(node 24); - 用
pak装fentouxungui/shinyelectron@multi-app-store+rlang/withr/renv; - macOS 额外
brew install hdf5 pkg-config并导出PKG_CONFIG_PATH/HDF5_*(给 scConvert 的 configure 用); -
APP_VERSION=${{ inputs.tag || github.ref_name }},执行source("build-suite.R"); - 上传
build/electron-app/dist/*.exe|.dmg|.blockmap|latest*.yml。
-
-
release:条件release || tag v* || inputs.tag;下载 artifacts →softprops/action-gh-release发布(generate_release_notes: true)。
-
-
版本号:不用手改
_shinyelectron.yml——build-suite.R会从APP_VERSION取得版本、去掉v、只改app.version后export()。本地不带APP_VERSION则保持原样。 -
程序图标:
build-suite.R按平台在icons/ico(Windows)/icons/mac(macOS)下挑图标传给export(icon=)。
-
触发:
schedule: cron '*/10 * * * *';workflow_dispatch;repository_dispatch: types: [bundle-updated];push main且路径为catalog/apps.yml或icons/**。 -
步骤:
- 读
catalog/apps.yml;对每个 App 用gh api repos/<repo>/releases/latest取最新 Release; - 扫描资产名
<id>-<version>-<platform>.zip(版本必须等于 Release tag 去v),提取browser_download_url/size/digest(sha256); - 生成
catalog/catalog.json(含schema/updated_at/shell_min_version/apps[]); - 用 worktree 把
catalog.json与icons/推到gh-pages; -
内容没有变化就不提交(比较时忽略
updated_at),避免每 10 分钟刷空提交。
- 读
- 注意:定时任务只在默认分支生效,且 GitHub 常延迟(几分钟到更久)。
-
触发:
release: published;workflow_dispatch(输入tag)。 -
matrix:
windows-latest → win-x64、macos-14 → mac-arm64。 -
关键逻辑:
- setup-r 用
r-version: 4.6.1; -
R CMD build --no-build-vignettes --no-manual;scConvertShiny 还会git clone mianaz/scConvert后R CMD build; - 用
DESCRIPTION的Depends/Imports/LinkingTo求声明依赖declared,seed <- unique(c(loc_names, declared)),再tools::package_dependencies(..., recursive=TRUE)求完整传递闭包; - CRAN/Bioc 依赖
type="binary"装、本地源码包type="source"装(本地 tarball 不能用 binary); - 生成
manifest.json(见 3.4),zip::zipr打包并断言含rlib/,算 sha256 写meta-<platform>.json; -
releasejob 把 zip 追加到对应 Release。
- setup-r 用
catalog.json(gh-pages,客户端拉取) —— schemas/catalog.schema.json
manifest.json(bundle 内,随 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": "可选:平台已知限制",
"packages": [ { "name": "Seurat", "version": "5.x", "path": "rlib/Seurat", "source": "cran" } ]
}state.json(本地 %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"] } }
}-
兼容基线:R 4.6.1;必须共享同版本的包:
Seurat、SeuratObject、ggplot2、DT、hdf5r。 -
放置规则(自动计算,不手写):
- 一个包名被 ≥2 个已安装 App 以同一版本需要 → 放共享库
<userData>/lib; - 只被 1 个 App 需要,或版本与共享池不同 → 放私有库
<userData>/private/<app-id>; - 运行时
R_LIBS = <私有库> : <共享库>(私有优先)。
- 一个包名被 ≥2 个已安装 App 以同一版本需要 → 放共享库
-
引用计数:安装时同版本
refs += app、缺则复制并refs=[app]、版本冲突进私有库;卸载时移除 ref,refs归零才删共享包;更新时先解新版本、补新引用、释放被弃引用,最后才删旧目录(可回滚)。
启动页是商店模式:渲染卡片网格(name / description / 图标;图标失败回退首字母),拉 catalog.json(进程内缓存,重启最稳),把 catalog.version 与 state.json 的已装版本做 semver 比较,决定显示 Install / Run / Update / Stop / Uninstall。
- 拉 catalog → 按平台选 artifact;
-
下载:支持断点续传(HTTP Range)、失败重试 5 次、空闲 60s 超时、按
content-length显示真实进度(downloading N / M MB);缓存目录store-cache/; -
校验:下载字节数 == catalog 的
size,且sha256匹配; -
解压:内置零依赖 ZIP 解包(仅用 Node
zlib,支持 stored/deflate + ZIP64 + zip-slip 防护),解到apps/<id>/<version>/; -
装依赖:把
rlib/里共享库缺失的包复制进<userData>/lib,同版本refs+1;版本冲突进私有库; - 写
state.json。 -
反馈:卡片显示当前步骤(
downloading %→verifying size→verifying checksum→unpacking→linking packages);失败时显示哪一步出错及原因——例如Install failed at step "verify": size mismatch (catalog N bytes, downloaded M bytes)——且该提示常驻到下次安装。
- 运行时
R_LIBS = 私有库:共享库,用随包的便携 R 起app/app.R(复用native-r.js)。 - 返回启动页(菜单 /
Ctrl+L/ app 内返回)都会:先弹未保存确认 → 确认后stop()杀掉整棵 R 进程树(Windowstaskkill /PID <pid> /T /F)→ 等status.phase === 'app_exit'或超时兜底 → 加载启动页。 - 同一时刻只有一个 App 后端。启动页时
Apps菜单被隐藏(避免无意义的「Back to Launcher」)。 -
卡片名字 → 主页:鼠标悬停 App 名字显示 “click to learn more”,点击用默认浏览器打开该 App 的 catalog
homepage;没有homepage的 App 名字不可点击。 -
按 App 的 Help/About:运行某 App 时,App 菜单标签、Help ▸ Documentation 与 About 弹窗使用该 App 的
name/version/description/author/copyright/homepage/email/docs;启动页时回退为外壳(ShinyApps)。
-
壳更新:启动时检查;在启动页通过
About → Check for Updates检查;electron-updater拉 Release 的latest*.yml比对,下载(.blockmap差量),退出时quitAndInstall()静默覆盖。注意:未签名会下载成功但安装失败。 -
App 更新:catalog 版本 > 本地版本 → 卡片出现
Update;点击后停后端 → 下载 → 校验 → 解到新版本目录 → 原子切换 → 重算引用计数 → 删旧目录。完成后main.js的done事件带op,launcher.html乐观清除Update(避免旧的回显丢失导致按钮不消失)。- 在 App 内运行时,
Help → About → Check for Updates检查的是该 App(与卡片Update同源):若有新版并确认,会停掉 App、回到启动页并执行更新(进度/失败显示在卡片上)。
- 在 App 内运行时,
停后端 → 删 App 目录与私有库 → 共享包 refs-1,归零才删。
- App 仓库:改
DESCRIPTION的Version并提交; - 打 tag(如
v0.1.11)并发布 Release(或手动跑Build app bundle填 tag); - 确认两个平台的
<id>-<ver>-<platform>.zip已上传且大小正常(不是几 KB;应含rlib/); - 触发
Publish catalog(push、手动、或 App workflow 发repository_dispatch),确认catalog.json里该 App 版本/sha256 已更新; - 客户端重启 ShinyApps → 卡片出现
Update→ 验证更新。
- 改壳相关文件(
_shinyelectron.yml、build-suite.R、图标等);不需要手改版本号; - 推
vX.Y.Ztag(或手动跑Build ShinyApps desktop填 tag); - 确认 Release 里
.exe/.dmg + latest*.yml + .blockmap齐全; - (若要真正启用壳自动更新)配置代码签名证书。
把 PNG 放进 icons/ → push(触发 publish-catalog.yml)→ 确认 https://fentouxungui.github.io/ShinyApps/icons/<id>.png 200 → 重启壳。
| 现象 | 根因 | 解决 |
|---|---|---|
装完还是显示 Update
|
界面刷新靠一次异步回显,长更新时可能丢失 | 已在 launcher.html 用 done(op) 乐观清除;升级壳 |
| 安装进度一直 0%,无报错 | 下载被截断(大小写不敏感的 Cache/ 撞名、无进度/超时/完整性校验) |
已修:断点续传 + 重试 5 次 + size 校验 + 60s 空闲超时 + store-cache/
|
| 卡片无图标 | gh-pages 上没有 icons/,或 CSP 拦截 |
用最新 publish-catalog.yml 同步 icons/;launcher.html 放行 img-src https:;失败会回退首字母 |
| 图标带蓝色背景 / 太小 |
.app-icon 有 background 且尺寸小 |
已修:有图时透明背景、容器 64px |
| 壳打不开、启动即退 |
appstore.js 没被打进包(require('./backends/appstore') 失败) |
确认 appstore.js 放在 inst/electron/backends/,且 R/build-templates.R 的复制列表包含它 |
| bundle zip 只有 ~2.5 KB | 只打了 app/+manifest.json,rlib/ 丢失 |
用 zip::zipr 打包并断言含 rlib/;CI 已加守卫 |
bundle CI 报 not available as a binary
|
本地源码 tarball 不能用 type="binary"
|
本地包用 type="source",CRAN/Bioc 闭包用 binary
|
依赖缺 RANN 等传递依赖 |
闭包只从 loc_names 展开,漏了 declared
|
seed <- unique(c(loc_names, declared)) |
| macOS build 挂在 scConvert | configure 找不到 HDF5 |
brew install hdf5 pkg-config 并导出 PKG_CONFIG_PATH/HDF5_*
|
tag 与 DESCRIPTION 版本不一致 → 坏包 |
workflow 找不到 Pkg_<ver>.tar.gz
|
对齐版本;CI 已加「源码包缺失即 stop」 |
| 壳自动更新下完装不上 | 未签名 | 购买/配置代码签名(signing.sign 目前为 false) |
Windows scConvert 转换报 H5Fclose
|
CRAN hdf5r 自带 HDF5 1.12.1 的已知限制 |
见第 7 节,暂挂 |
点 Apps → Back to Launcher 报 ReferenceError
|
leaveToLauncher 作用域不对 |
确保它在模块顶层(上游 PR 已整理) |
-
平台:便携 R 的
bundled策略目前只有 Windows / macOS(Linux 需system);bundle CI 目前只产win-x64与mac-arm64。 -
Windows scConvert 转换:CRAN
hdf5r二进制带 HDF5 1.12.1,H5Fclose终结器在 GC 时可能失败(不可捕获)。已在manifest.notes标注,待单独处理。 - 代码签名:Windows/macOS 未签名 → SmartScreen/Gatekeeper 警告;壳自动更新下载成功但安装失败。
-
空间冗余:安装后
apps/<id>/<ver>/rlib/与共享库lib/重复;store-cache/的 zip 未清理。建议装完删rlib/、清理缓存。 - 切 App 丢状态:一次只跑一个 App,返回启动页会杀掉进程,未保存分析丢失(已有确认框)。
-
catalog 刷新依赖定时/手动:App 发布后不会自动通知 ShinyApps(除非加
repository_dispatch)。 -
许可:
shinyelectron为 AGPL-3.0;SeuratExplorer为 GPL-3.0-or-later;scConvertShiny为 MIT。再分发时需遵守各自义务。
高优先级
-
README.md(仓库首页):目前仓库缺一个面向新人的入口。应含一句话简介、架构图、快速开始、指向 Wiki 各页。 -
LICENSE与THIRD-PARTY-NOTICES:明确 ShinyApps 自身许可,并列出 shinyelectron(AGPL-3.0)、各 App、第三方 R 包(Seurat、scConvert 等)的许可与义务。 -
「新增 App」模板 + 校验:提供一个可直接复制的
build-app-bundle.yml模板与apps.yml片段;再写一个 CI/脚本做契约校验(id合法、命名id-ver-platform.zip、tag==DESCRIPTION版本、r_version==4.6.1、zip 含rlib/)。 -
自动刷新 catalog:在各 App 的 bundle workflow 末尾加
repository_dispatch: [bundle-updated],把「手动跑 Publish catalog」变成自动。 - 版本兼容性矩阵:集中记录「壳版本 × 运行时 R 版本 × 必需共享包基线」,让 App 开发者一眼知道该按什么构建。
- 代码签名指南:Windows(CSC_LINK/CSC_KEY_PASSWORD)与 macOS(notarization)的配置步骤;说明签名前的自动更新行为。
中优先级
- 发布 checklist / 回滚手册:把第 5 节做成勾选清单;补「如何回滚一个坏 App 版本 / 坏壳版本」。
-
故障排查扩容:FAQ 增加「如何读
%APPDATA%\shinyapps\logs\app-*.log的[store]行」。 - 测试清单:菜单返回、未保存提示两分支、反复切换、真实转换、进程回收、退出无残留、大文件、快速连点、冷启动耗时/内存——可作为发布前验收。
-
空间优化:实现「装完删 bundle
rlib/」与「清理store-cache」,并在文档里说明收益。 -
安全说明:catalog 与 bundle 视为不可信输入;只走 HTTPS;校验
sha256(建议后续加签名/验签)。 - 截图与动图:启动页、安装进度、更新提示、返回确认框——Wiki 可读性会好很多。
- 中英文对照:至少 Home 与快速开始提供英文版。
低优先级 / 长期
-
CHANGELOG.md:壳与各 App 的版本变更;catalog 已预留changelog字段可用于更新弹窗展示。 - App 详情页:卡片展开显示作者/许可/版本/更新日志(catalog 已有这些字段)。
- 多语言 / 主题 / 搜索:启动页体验增强。
-
贡献与治理:
CONTRIBUTING.md、CODE_OF_CONDUCT.md、Issue/PR 模板。 - CI 端到端测试:在 CI 里对生成的 bundle 做「解压 → 校验 manifest → 冒烟启动」的最小验证。
multi-app-store 分支混合了「通用壳能力」与「本项目专属逻辑」,不建议整体开 PR。现已把其中最通用的一块——返回启动页前确认 + 启动页隐藏 Apps 菜单——整理成只含 inst/electron/shared/main.js 的干净补丁,对上游 main 生成:
git remote add upstream https://github.com/coatless-rpkg/shinyelectron # 若已有则跳过
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-launcher然后对 coatless-rpkg:main 开 PR。应用商店 / 安装器相关代码建议单独走 Issue 或后续 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" }版本号由
build-suite.R在构建时按 tag 自动改写,不要在发版时手改。
schema: 1
shell_min_version: "0.1.0"
apps:
- id: <小写唯一 id>
repo: <owner/repo> # gh api 拉 latest release
name: <显示名>
author: <作者> # About 文本
description: <描述> # About 文本
homepage: <URL> # About > Visit Website;同时是卡片名字链接目标
docs: <URL> # 可选;Help > Documentation
email: <地址> # 可选;About > Email
copyright: <文本> # 可选;About 文本
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>() # 必须 return 一个 shinyApp 对象,不要 runApp()| 术语 | 含义 |
|---|---|
| 壳 / shell | Electron 桌面程序本体(含便携 R 运行时) |
| bundle | 单个 App 的预编译包:app/ + rlib/ + manifest.json
|
| catalog | 托管在 gh-pages 的 catalog.json,App 列表与下载地址/校验和 |
| runtime 层 | Tier 0,随壳的一次性底座 |
| 共享库 | Tier 1,<userData>/lib,引用计数 |
| 私有库 | Tier 2,<userData>/private/<id>
|
| R_LIBS | R 包搜索路径,运行顺序 = 私有库:共享库 |
本文档由 Open-Science Agent 依据 2026-09/10 的开发与验收会话整理,并核对当前 ShinyApps / shinyelectron@multi-app-store / 各 App 仓库状态。若仓库后续变更,请以仓库内实际文件为准。
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..." } } } ] }