WanOS Package
WPK 应用开发文档
因为 Go 可以编译为二进制机器码,在低性能的盒子里面也可以流畅运行,这是 WPK 应用选择 Go 的主要优势,所以 WPK 应用推荐使用 Go + HTML 的单文件包装。WPK 是 WanOS 的应用安装包格式,开发者可以把一个带 Web 面板的应用打包成 .wpk,用户在 WanOS 文件管理器或应用商店中点击即可安装;静态页面、CSS、JS、图标和依赖都可以嵌入二进制或随包释放,适合玩客云、赚钱宝等 ARMv7 低功耗设备。
.wpk 和校验安装包。SHA256:a9103ffb5fb66fa0bd51994afd2b903788a75e45f858dfcf46747b6e358288a6应用必须满足什么条件
- 必须提供 Web 前端,用户能通过浏览器打开应用面板。
- 必须监听一个 HTTP 端口,建议读取
WANOS_APP_PORT。 - 必须支持 ARMv7 Linux,Go 应用建议用
GOOS=linux GOARCH=arm GOARM=7编译。 - 必须带图标,推荐
icon.png,尺寸 256x256 或 512x512。 - 不能要求用户手动执行命令,安装、启动、停止都要由包内脚本完成。
WanOS 会帮你做什么
- 解压 WPK 到用户选择的安装目录。
- 创建应用数据目录,传入运行环境变量。
- 有 systemd 时创建并启动 service;没有 systemd 时用后台进程兼容启动。
- 把应用加入桌面和应用商店已安装列表。
- 读取包内图标,让文件管理器和安装界面显示应用自己的图标。
快速开始
Windows 安装 Go 后,在 PowerShell 中能执行下面命令即可。
go version应用启动后监听 0.0.0.0:$WANOS_APP_PORT,不要只监听 127.0.0.1,否则局域网和 WanOS 反代可能访问不到。
使用下面参数交叉编译,尽量静态编译,减少系统依赖。
GOOS=linux GOARCH=arm GOARM=7 CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o bin/your-app .告诉 WanOS 应用名称、端口、入口路径、启动脚本和停止脚本,让安装、启动、停止、卸载都能自动完成。
WPK 本质是 zip 包,扩展名是 .wpk。上传到 WanOS 后点击即可安装。
WPK 包结构
推荐使用 WPK v1 结构,根目录必须有 manifest.json。压缩时不要把外层项目目录多套一层;如果多套一层,WanOS 会尝试自动识别,但不建议依赖这个兼容逻辑。
hello-wpk.wpk
├─ manifest.json
├─ icon.png
├─ bin/
│ └─ hello-wpk
├─ web/
│ └─ index.html
└─ scripts/
├─ install.sh
├─ start.sh
├─ stop.sh
└─ uninstall.sh
.wpk。WanOS 设备是 ARMv7,二进制架构不对会安装失败或启动失败。manifest.json 完整说明
{
"wpk_version": 1,
"id": "hello-wpk",
"name": "Hello WPK",
"version": "1.0.0",
"description": "第一个 WanOS WPK 示例应用",
"arch": ["armv7"],
"type": "web",
"icon": "icon.png",
"entry": {
"port": 42181,
"path": "/",
"open_mode": "new_page"
},
"service": {
"name": "hello-wpk",
"start": "scripts/start.sh",
"stop": "scripts/stop.sh"
},
"install": {
"install_dir": "/opt/wanos/apps/hello-wpk",
"data_dir": "/opt/wanos-data/apps/hello-wpk",
"scripts": {
"install": "scripts/install.sh",
"uninstall": "scripts/uninstall.sh"
}
}
}
| 字段 | 是否必填 | 说明 |
|---|---|---|
wpk_version | 必填 | 当前填 1。WanOS 用它识别新格式 WPK。 |
id | 必填 | 应用唯一 ID,只用小写字母、数字、-、_,例如 cloudflare-tunnel。 |
name | 必填 | 用户看到的应用名称,例如 Cloudflare 内网穿透。 |
version | 必填 | 应用版本号,建议语义化版本,例如 1.0.0。 |
description | 建议填写 | 应用简介,会在安装和应用商店中展示。 |
arch | 建议填写 | 支持架构。玩客云、赚钱宝常用 armv7。 |
icon | 必填 | 包内图标路径,支持 PNG/JPG/WebP,推荐 icon.png。 |
entry.port | 必填 | Web 面板端口。安装后 WanOS 会把这个端口写入 WANOS_APP_PORT。 |
entry.path | 必填 | 打开应用时的路径,通常是 /。 |
entry.open_mode | 必填 | new_page 表示新页面打开;popup 表示弹窗打开。完整 Web 应用建议用 new_page。 |
service.start | 必填 | 启动脚本路径。脚本必须能以前台方式启动应用。 |
service.stop | 建议填写 | 停止脚本路径。没有特殊清理逻辑时可直接 exit 0。 |
install.scripts.install | 建议填写 | 安装脚本。用于创建目录、复制文件、初始化数据。 |
install.scripts.uninstall | 建议填写 | 卸载脚本。用于清理临时文件,用户数据是否删除要谨慎。 |
运行环境变量
WanOS 启动应用时会注入以下变量。应用代码和脚本都应该优先读取这些变量,不要写死路径。
| 变量 | 说明 | 示例 |
|---|---|---|
WANOS_APP_ID | 应用 ID | hello-wpk |
WANOS_APP_NAME | 应用名称 | Hello WPK |
WANOS_APP_PORT | Web 服务端口 | 42181 |
WANOS_APP_PATH | Web 入口路径 | / |
WANOS_APP_ROOT | 应用安装目录 | /mnt/wanos/.../hello-wpk/app |
WANOS_APP_DATA | 应用数据目录 | /mnt/wanos/.../hello-wpk/data |
APP_DIR | 兼容变量,等同安装目录 | $WANOS_APP_ROOT |
DATA_DIR | 兼容变量,等同数据目录 | $WANOS_APP_DATA |
完整案例:Go + HTML 单文件应用
下面这个案例可以直接复制。它会启动一个 HTTP 服务,显示应用名称、数据目录和当前时间。HTML 嵌入到 Go 二进制里,不依赖外部前端框架。
1. 创建目录
mkdir hello-wpk
cd hello-wpk
mkdir bin scripts
2. main.go
package main
import (
"fmt"
"html/template"
"log"
"net/http"
"os"
"time"
)
const page = `<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>{{.Name}}</title>
<style>
body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;background:#f6f8fb;color:#111827}
main{min-height:100vh;display:grid;place-items:center;padding:24px}
section{max-width:620px;background:white;border:1px solid #e5e7eb;border-radius:12px;padding:28px;box-shadow:0 18px 50px rgba(15,23,42,.08)}
h1{margin:0 0 10px;font-size:28px}
p{line-height:1.7;color:#64748b}
code{background:#eef2ff;border-radius:6px;padding:2px 6px}
</style>
</head>
<body>
<main>
<section>
<h1>{{.Name}}</h1>
<p>这是一个 WanOS WPK 示例应用。</p>
<p>应用 ID:<code>{{.ID}}</code></p>
<p>数据目录:<code>{{.Data}}</code></p>
<p>当前时间:{{.Now}}</p>
</section>
</main>
</body>
</html>`
func env(key, fallback string) string {
if v := os.Getenv(key); v != "" {
return v
}
return fallback
}
func main() {
id := env("WANOS_APP_ID", "hello-wpk")
name := env("WANOS_APP_NAME", "Hello WPK")
dataDir := env("WANOS_APP_DATA", "./data")
port := env("WANOS_APP_PORT", "42181")
if err := os.MkdirAll(dataDir, 0755); err != nil {
log.Fatal(err)
}
tpl := template.Must(template.New("page").Parse(page))
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
_ = tpl.Execute(w, map[string]string{
"ID": id,
"Name": name,
"Data": dataDir,
"Now": time.Now().Format("2006-01-02 15:04:05"),
})
})
addr := "0.0.0.0:" + port
fmt.Println("listen", addr)
log.Fatal(http.ListenAndServe(addr, nil))
}
3. manifest.json
{
"wpk_version": 1,
"id": "hello-wpk",
"name": "Hello WPK",
"version": "1.0.0",
"description": "WanOS WPK 入门示例应用",
"arch": ["armv7"],
"type": "web",
"icon": "icon.png",
"entry": {
"port": 42181,
"path": "/",
"open_mode": "new_page"
},
"service": {
"name": "hello-wpk",
"start": "scripts/start.sh",
"stop": "scripts/stop.sh"
},
"install": {
"install_dir": "/opt/wanos/apps/hello-wpk",
"data_dir": "/opt/wanos-data/apps/hello-wpk",
"scripts": {
"install": "scripts/install.sh",
"uninstall": "scripts/uninstall.sh"
}
}
}
4. scripts/install.sh
#!/bin/sh
set -eu
APP_DIR="${WANOS_APP_INSTALL_ROOT:-${APP_DIR:-/opt/wanos/apps/hello-wpk}}"
DATA_DIR="${WANOS_APP_DATA_ROOT:-${DATA_DIR:-/opt/wanos-data/apps/hello-wpk}}"
mkdir -p "$APP_DIR" "$DATA_DIR"
cp -R bin scripts manifest.json "$APP_DIR/"
[ -f icon.png ] && cp icon.png "$APP_DIR/icon.png"
chmod +x "$APP_DIR/bin/hello-wpk" "$APP_DIR/scripts/"*.sh 2>/dev/null || true
echo "installed to $APP_DIR"
5. scripts/start.sh
#!/bin/sh
set -eu
APP_DIR="${WANOS_APP_INSTALL_ROOT:-${APP_DIR:-$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)}}"
cd "$APP_DIR"
exec "$APP_DIR/bin/hello-wpk"
6. scripts/stop.sh 和 scripts/uninstall.sh
#!/bin/sh
set -eu
exit 0
7. 编译 ARMv7
# PowerShell
$env:GOOS='linux'
$env:GOARCH='arm'
$env:GOARM='7'
$env:CGO_ENABLED='0'
go build -trimpath -ldflags='-s -w' -o bin/hello-wpk .
# Linux/macOS shell
GOOS=linux GOARCH=arm GOARM=7 CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o bin/hello-wpk .
脚本规则
install.sh在安装时执行,超时时间约 2 分钟,不要做长时间下载任务。start.sh必须以前台方式启动应用,最后一行建议用exec。stop.sh只做必要清理,WanOS 会负责停止 systemd 服务或后台进程。uninstall.sh不建议默认删除用户数据,除非用户明确选择清理数据。- 脚本必须兼容
/bin/sh,不要依赖 Bash 专属语法。
打包和本地校验
方式一:使用 WPK 开发者工具
- 打开
WanOS-WPK-Developer-Tool.exe。 - 填写应用 ID、名称、版本、端口、入口路径和图标。
- 选择项目目录,点击一键打包。
- 工具会生成
.wpk和 SHA256。
方式二:命令行打包
# 在项目目录内执行,把内容压成 zip,但扩展名用 .wpk
powershell Compress-Archive -Path manifest.json,icon.png,bin,scripts -DestinationPath hello-wpk.zip -Force
ren hello-wpk.zip hello-wpk.wpk
使用开发者工具命令行
python tools/wpk_dev_tool.py init ./hello-wpk --id hello-wpk --name "Hello WPK" --port 42181
python tools/wpk_dev_tool.py pack ./hello-wpk --out ./dist/hello-wpk.wpk
python tools/wpk_dev_tool.py validate ./dist/hello-wpk.wpk
在 WanOS 上测试
- 把
hello-wpk.wpk上传到文件管理器。 - 点击安装包,选择安装目录。
- 确认弹窗显示应用名称和图标。
- 安装完成后,在桌面或应用商店已安装里打开。
- 如果打不开,先看安装日志,再检查端口是否监听。
发布到应用商店
应用商店不是直接上传就上架。开发者提交 WPK 后会进入官方审核,通过后才会进入商店列表。
- 必须上传
.wpk单文件包。 - 必须上传应用图标。
- 必须填写应用名称、ID、版本、端口、说明和联系方式。
- 必须带 Web 前端,审核时会安装并打开测试。
- 不能包含挖矿、恶意下载、破坏系统、未经说明的远程控制逻辑。
常见问题和排错
提示“未找到 Go 单文件二进制”
通常是包里没有 ARMv7 Linux 可执行文件,或者只放了 Windows exe。用 GOOS=linux GOARCH=arm GOARM=7 重新编译。
安装完成但打不开
- 检查应用是否监听
0.0.0.0:$WANOS_APP_PORT。 - 检查
entry.port是否和程序实际监听端口一致。 - 检查
scripts/start.sh是否有exec "$APP_DIR/bin/xxx"。 - 检查程序是否依赖设备上没有的 glibc 或动态库。Go 建议
CGO_ENABLED=0。
图标不显示
确认 manifest.json 的 icon 路径正确,文件在包内,格式为 PNG/JPG/WebP。推荐直接放根目录 icon.png。
端口被占用
换一个大于 1024 的端口,例如 42181、42182。不要使用 WanOS 面板端口、80、443、22 等系统端口。
systemd 不存在怎么办
WanOS 安装器会兼容没有 systemd 的轻量系统,无法写入 systemd 服务时会退回后台进程方式启动。应用自己不要强依赖 systemctl。
可以打包 Node、Python、PHP 应用吗
可以,但不推荐让用户设备临时安装一堆依赖。最稳的是 Go 单文件。如果必须用 Node/Python/PHP,需要把运行时和依赖做成按需离线包,并在应用 UI 中明确提示安装组件。