WanOS Package

WPK 应用开发文档

因为 Go 可以编译为二进制机器码,在低性能的盒子里面也可以流畅运行,这是 WPK 应用选择 Go 的主要优势,所以 WPK 应用推荐使用 Go + HTML 的单文件包装。WPK 是 WanOS 的应用安装包格式,开发者可以把一个带 Web 面板的应用打包成 .wpk,用户在 WanOS 文件管理器或应用商店中点击即可安装;静态页面、CSS、JS、图标和依赖都可以嵌入二进制或随包释放,适合玩客云、赚钱宝等 ARMv7 低功耗设备。

开发者工具是 Windows 绿色版,双击即可打开,也支持命令行创建模板、配置参数、打包 .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 时用后台进程兼容启动。
  • 把应用加入桌面和应用商店已安装列表。
  • 读取包内图标,让文件管理器和安装界面显示应用自己的图标。

快速开始

准备 Go 环境。

Windows 安装 Go 后,在 PowerShell 中能执行下面命令即可。

go version
创建一个 Web 应用。

应用启动后监听 0.0.0.0:$WANOS_APP_PORT,不要只监听 127.0.0.1,否则局域网和 WanOS 反代可能访问不到。

编译 ARMv7 二进制。

使用下面参数交叉编译,尽量静态编译,减少系统依赖。

GOOS=linux GOARCH=arm GOARM=7 CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o bin/your-app .
写 manifest.json 和 scripts。

告诉 WanOS 应用名称、端口、入口路径、启动脚本和停止脚本,让安装、启动、停止、卸载都能自动完成。

打包成 .wpk。

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
不要把 x86 Windows 程序、exe、amd64 Linux 程序直接改名成 .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应用 IDhello-wpk
WANOS_APP_NAME应用名称Hello WPK
WANOS_APP_PORTWeb 服务端口42181
WANOS_APP_PATHWeb 入口路径/
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 .

脚本规则

低配 ARMv7 设备 CPU 和内存都有限,安装脚本要短,运行服务要轻。大型依赖建议由应用首次打开后按需下载,并在 UI 上显示进度。

打包和本地校验

方式一:使用 WPK 开发者工具

  1. 打开 WanOS-WPK-Developer-Tool.exe
  2. 填写应用 ID、名称、版本、端口、入口路径和图标。
  3. 选择项目目录,点击一键打包。
  4. 工具会生成 .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 上测试

  1. hello-wpk.wpk 上传到文件管理器。
  2. 点击安装包,选择安装目录。
  3. 确认弹窗显示应用名称和图标。
  4. 安装完成后,在桌面或应用商店已安装里打开。
  5. 如果打不开,先看安装日志,再检查端口是否监听。

发布到应用商店

应用商店不是直接上传就上架。开发者提交 WPK 后会进入官方审核,通过后才会进入商店列表。

常见问题和排错

提示“未找到 Go 单文件二进制”

通常是包里没有 ARMv7 Linux 可执行文件,或者只放了 Windows exe。用 GOOS=linux GOARCH=arm GOARM=7 重新编译。

安装完成但打不开

图标不显示

确认 manifest.jsonicon 路径正确,文件在包内,格式为 PNG/JPG/WebP。推荐直接放根目录 icon.png

端口被占用

换一个大于 1024 的端口,例如 4218142182。不要使用 WanOS 面板端口、80、443、22 等系统端口。

systemd 不存在怎么办

WanOS 安装器会兼容没有 systemd 的轻量系统,无法写入 systemd 服务时会退回后台进程方式启动。应用自己不要强依赖 systemctl。

可以打包 Node、Python、PHP 应用吗

可以,但不推荐让用户设备临时安装一堆依赖。最稳的是 Go 单文件。如果必须用 Node/Python/PHP,需要把运行时和依赖做成按需离线包,并在应用 UI 中明确提示安装组件。