12 KiB
Velopack + Supabase Storage 自动更新复用指南
本文档用于在桌面程序中复用“Velopack 生成安装包和更新包,Supabase Storage 托管更新源”的自动更新流程。示例均使用占位符,不绑定任何具体项目。
方案概览
更新链路分为两部分:
- 发布端使用 Velopack CLI 将程序发布目录打包成安装包、全量包、差分包和
releases.win.json。 - 上传端将这些产物放到 Supabase Storage 的公开桶目录中。
- 客户端运行时只读取公开更新源 URL,调用 Velopack 检查、下载并应用更新。
客户端不需要 Supabase key。Supabase key 只应出现在发布脚本、CI/CD 或受信任的维护机器中。
Supabase 配置
1. 创建 Storage 桶
推荐使用一个专门存放发布包的公开 File bucket:
| 配置项 | 推荐值 | 说明 |
|---|---|---|
| Bucket name | app-releases |
可按组织统一命名 |
| Public bucket | true |
客户端需要匿名下载 releases.win.json 和安装包 |
| File size limit | 按安装包大小设置 | 例如 512MB、1GB 或更高 |
| Allowed MIME types | 留空或允许二进制 | Velopack 产物包含 .exe、.nupkg、.json 等 |
Dashboard 路径通常是:
Supabase Dashboard -> Storage -> New bucket
也可以用 SQL 创建桶:
insert into storage.buckets (
id,
name,
public,
file_size_limit,
allowed_mime_types
)
values (
'app-releases',
'app-releases',
true,
1073741824,
null
)
on conflict (id) do update
set
public = excluded.public,
file_size_limit = excluded.file_size_limit,
allowed_mime_types = excluded.allowed_mime_types;
2. 目录规划
建议每个应用、平台和发布通道使用独立目录:
app-releases/
my-app/
windows/
stable/
releases.win.json
RELEASES
MyApp-win-Setup.exe
MyApp-1.2.3-full.nupkg
MyApp-1.2.3-delta.nupkg
beta/
releases.win.json
...
对应的 Velopack 更新源根地址为:
https://<project-ref>.supabase.co/storage/v1/object/public/app-releases/my-app/windows/stable
Velopack 会在该根地址下读取 releases.win.json,所以不要把 releases.win.json 再放到额外子目录里。
3. 权限策略
推荐做法:
- 桶设为 public,只开放匿名读取。
- 发布上传使用
service_rolekey,并且只在 CI/CD 或维护机器环境变量中保存。 - 不给
anon角色配置INSERT、UPDATE、DELETE权限。 - 不在客户端配置、日志、提交信息或文档中写入真实 key。
Supabase 的 public bucket 只代表对象可以通过公开 URL 读取;上传、覆盖、删除仍受访问控制影响。使用 service_role key 上传时会绕过 RLS,适合发布流程。
如果必须用非 service role 的登录用户上传,需要在 storage.objects 上创建受限策略。下面示例只允许已登录用户写入指定目录,实际项目应再结合用户、角色或后端校验收紧权限:
create policy "release upload insert"
on storage.objects
for insert
to authenticated
with check (
bucket_id = 'app-releases'
and (storage.foldername(name))[1] = 'my-app'
);
create policy "release upload select"
on storage.objects
for select
to authenticated
using (
bucket_id = 'app-releases'
and (storage.foldername(name))[1] = 'my-app'
);
create policy "release upload update"
on storage.objects
for update
to authenticated
using (
bucket_id = 'app-releases'
and (storage.foldername(name))[1] = 'my-app'
)
with check (
bucket_id = 'app-releases'
and (storage.foldername(name))[1] = 'my-app'
);
覆盖已有文件需要 SELECT 和 UPDATE 权限。发布流程更推荐使用 service role,而不是给普通客户端发放写权限。
应用配置文件
建议在应用中放一个独立配置文件,例如 Config/update_config.json:
{
"enable_auto_update": true,
"update_server_type": "supabase",
"update_server_url": "https://<project-ref>.supabase.co/storage/v1/object/public/app-releases/my-app/windows/stable",
"update_check_interval_hours": 24,
"silent_install": false,
"supabase": {
"project_url": "https://<project-ref>.supabase.co",
"bucket_name": "app-releases",
"directory": "my-app/windows/stable"
}
}
字段说明:
| 字段 | 用途 |
|---|---|
enable_auto_update |
是否启用自动更新 |
update_server_type |
可固定为 supabase,用于程序内部区分更新源 |
update_server_url |
客户端 Velopack 更新源根地址 |
update_check_interval_hours |
自动检查间隔;手动检查可忽略该间隔 |
silent_install |
是否下载后延迟到下次启动自动应用 |
supabase.project_url |
发布脚本上传时使用的 Supabase 项目 URL |
supabase.bucket_name |
发布包所在 bucket |
supabase.directory |
bucket 内目录 |
supabase 节只给发布脚本使用。客户端运行时检查更新只需要 update_server_url。
客户端集成
1. 安装 NuGet 包
dotnet add <YourApp.csproj> package Velopack
2. 在程序入口尽早初始化
Velopack 初始化应尽量放在应用启动最早位置:
using Velopack;
internal static class Program
{
[STAThread]
public static void Main(string[] args)
{
VelopackApp.Build()
.SetArgs(args)
.SetAutoApplyOnStartup(true)
.Run();
StartApplication(args);
}
}
SetAutoApplyOnStartup(true) 用于在下次启动时自动应用已下载但尚未安装的更新。
3. 检查、下载并应用更新
下面是最小可复用逻辑:
using Velopack;
public sealed class AppUpdateService
{
private readonly string _updateServerUrl;
public AppUpdateService(string updateServerUrl)
{
_updateServerUrl = updateServerUrl;
}
public async Task<bool> CheckDownloadAndRestartAsync(
IProgress<int>? progress = null,
CancellationToken cancellationToken = default)
{
var manager = new UpdateManager(_updateServerUrl);
if (!manager.IsInstalled)
{
return false;
}
var updateInfo = await manager.CheckForUpdatesAsync().ConfigureAwait(false);
if (updateInfo?.TargetFullRelease is null)
{
return false;
}
await manager.DownloadUpdatesAsync(
updateInfo,
value => progress?.Report(Math.Clamp(value, 0, 100)),
cancellationToken).ConfigureAwait(false);
manager.ApplyUpdatesAndRestart(updateInfo.TargetFullRelease);
return true;
}
}
建议在 UI 层:
- 启动后延迟 1 到 3 秒检查,避免影响首屏。
- 发现新版本后先提示用户,再下载并重启。
- 手动“检查更新”按钮忽略检查间隔。
- 开发环境或直接运行
dotnet run时,manager.IsInstalled通常为false,应跳过更新检查。
打包发布
1. 安装 Velopack CLI
dotnet tool install -g vpk
2. 提升版本号
更新项目文件中的版本号,确保新版本高于线上版本:
<Version>1.2.3</Version>
3. 发布应用目录
dotnet publish .\src\MyApp\MyApp.csproj `
-c Release `
-r win-x64 `
--self-contained false `
-o .\artifacts\publish\my-app
如果目标机器不保证安装 .NET Runtime,可以改用 self-contained 发布,或按 Velopack 文档为安装包配置所需 framework。
4. 生成 Velopack 包
vpk pack `
--packId MyCompany.MyApp `
--packVersion 1.2.3 `
--packDir .\artifacts\publish\my-app `
--mainExe MyApp.exe `
--packTitle "My App" `
--packAuthors "MyCompany" `
--outputDir .\artifacts\releases\my-app
输出目录应至少包含:
MyApp-win-Setup.exe
MyCompany.MyApp-1.2.3-full.nupkg
MyCompany.MyApp-1.2.3-delta.nupkg
releases.win.json
RELEASES
首次发布可能没有 delta 包;从第二次发布开始应包含 delta 包。
上传到 Supabase Storage
发布脚本应读取配置文件中的 supabase.project_url、supabase.bucket_name 和 supabase.directory,并从环境变量读取服务端 key:
$env:SUPABASE_SERVICE_ROLE_KEY = "<service-role-key>"
通用上传脚本示例:
param(
[Parameter(Mandatory = $true)]
[string]$ConfigPath,
[Parameter(Mandatory = $true)]
[string]$ReleasePath,
[string]$ServiceRoleKey = $env:SUPABASE_SERVICE_ROLE_KEY
)
$ErrorActionPreference = "Stop"
function Join-UrlPath {
param(
[string]$Left,
[string]$Right
)
if ([string]::IsNullOrWhiteSpace($Left)) {
return $Right
}
if ([string]::IsNullOrWhiteSpace($Right)) {
return $Left.TrimEnd("/")
}
return $Left.TrimEnd("/") + "/" + $Right.TrimStart("/")
}
if ([string]::IsNullOrWhiteSpace($ServiceRoleKey)) {
throw "SUPABASE_SERVICE_ROLE_KEY is empty."
}
$config = Get-Content -Encoding UTF8 $ConfigPath -Raw | ConvertFrom-Json
$baseUrl = $config.supabase.project_url.TrimEnd("/")
$bucketName = $config.supabase.bucket_name
$directory = $config.supabase.directory
if ([string]::IsNullOrWhiteSpace($baseUrl) -or
[string]::IsNullOrWhiteSpace($bucketName) -or
[string]::IsNullOrWhiteSpace($directory)) {
throw "Supabase project_url, bucket_name, or directory is missing."
}
$files = Get-ChildItem -Path $ReleasePath -File | Sort-Object Name
if (-not $files) {
throw "No release files were found."
}
$headers = @{
"apikey" = $ServiceRoleKey
"Authorization" = "Bearer $ServiceRoleKey"
}
foreach ($file in $files) {
$objectPath = Join-UrlPath $directory $file.Name
$uploadUrl = Join-UrlPath "$baseUrl/storage/v1/object/$bucketName" $objectPath
$uploadHeaders = $headers.Clone()
$uploadHeaders["Content-Type"] = "application/octet-stream"
$uploadHeaders["x-upsert"] = "true"
Invoke-RestMethod `
-Uri $uploadUrl `
-Method Post `
-Headers $uploadHeaders `
-InFile $file.FullName
}
$publicBaseUrl = Join-UrlPath "$baseUrl/storage/v1/object/public/$bucketName" $directory
Write-Host "Public feed root: $publicBaseUrl"
Write-Host "Velopack feed: $(Join-UrlPath $publicBaseUrl 'releases.win.json')"
上传命令:
.\UploadReleaseToSupabase.ps1 `
-ConfigPath .\Config\update_config.json `
-ReleasePath .\artifacts\releases\my-app
发布后验证
1. 验证 feed 可访问
$feedUrl = "https://<project-ref>.supabase.co/storage/v1/object/public/app-releases/my-app/windows/stable/releases.win.json"
$feed = Invoke-RestMethod -Uri $feedUrl -Method Get
$feed.Assets | Sort-Object {[version]$_.Version} -Descending | Select-Object -First 5 PackageId,Version,Type,FileName,Size
确认:
- 最新版本等于本次发布版本。
- 最新版本至少有
Full资产。 - 非首次发布时应有
Delta资产。
2. 验证安装包 URL
curl.exe -I "https://<project-ref>.supabase.co/storage/v1/object/public/app-releases/my-app/windows/stable/MyApp-win-Setup.exe"
期望结果:
HTTP/1.1 200 OK
3. 验证客户端更新
建议用两个版本验证:
- 安装旧版本。
- 上传新版本发布包。
- 启动旧版本并触发检查更新。
- 确认能发现新版本、下载进度正常、重启后版本号变为新版本。
复用检查清单
- Supabase Storage 已创建 public bucket。
- 更新包目录规划稳定,不同应用和通道互不覆盖。
- 客户端配置的
update_server_url指向包含releases.win.json的目录。 - 发布脚本只在受信环境使用
SUPABASE_SERVICE_ROLE_KEY。 - 客户端没有保存 Supabase key。
- 每次发布前提高应用版本号。
vpk pack输出包含releases.win.json、Setup.exe和.nupkg。- 上传后
releases.win.json可通过公开 URL 访问。 - 安装包 URL 返回
200 OK。 - 至少用旧版本安装包做一次真实升级测试。